refactor: rename OhMyOpenCode types to OhMyOpenAgent and centralize PACKAGE_NAME
- Rename all PascalCase types: OhMyOpenCodePlugin → OhMyOpenAgentPlugin, etc. - 231 OhMyOpenAgent references across ~60 files - Centralize 4 PACKAGE_NAME constants to import from plugin-identity.ts - Update src/plugin-config.ts to use CONFIG_BASENAME from plugin-identity Wave 3 Tasks 5 & 6 complete.
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
import * as z from "zod"
|
import * as z from "zod"
|
||||||
import { OhMyOpenCodeConfigSchema } from "../src/config/schema"
|
import { OhMyOpenAgentConfigSchema } from "../src/config/schema"
|
||||||
|
|
||||||
export function createOhMyOpenCodeJsonSchema(): Record<string, unknown> {
|
export function createOhMyOpenCodeJsonSchema(): Record<string, unknown> {
|
||||||
const jsonSchema = z.toJSONSchema(OhMyOpenCodeConfigSchema, {
|
const jsonSchema = z.toJSONSchema(OhMyOpenAgentConfigSchema, {
|
||||||
target: "draft-7",
|
target: "draft-7",
|
||||||
unrepresentable: "any",
|
unrepresentable: "any",
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import { detectConfigFormat } from "./opencode-config-format"
|
|||||||
import { parseOpenCodeConfigFileWithError, type OpenCodeConfig } from "./parse-opencode-config-file"
|
import { parseOpenCodeConfigFileWithError, type OpenCodeConfig } from "./parse-opencode-config-file"
|
||||||
import { getPluginNameWithVersion } from "./plugin-name-with-version"
|
import { getPluginNameWithVersion } from "./plugin-name-with-version"
|
||||||
|
|
||||||
|
const PACKAGE_NAME = PLUGIN_NAME
|
||||||
|
|
||||||
export async function addPluginToOpenCodeConfig(currentVersion: string): Promise<ConfigMergeResult> {
|
export async function addPluginToOpenCodeConfig(currentVersion: string): Promise<ConfigMergeResult> {
|
||||||
try {
|
try {
|
||||||
ensureConfigDirectoryExists()
|
ensureConfigDirectoryExists()
|
||||||
@@ -20,7 +22,7 @@ export async function addPluginToOpenCodeConfig(currentVersion: string): Promise
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { format, path } = detectConfigFormat()
|
const { format, path } = detectConfigFormat()
|
||||||
const pluginEntry = await getPluginNameWithVersion(currentVersion, PLUGIN_NAME)
|
const pluginEntry = await getPluginNameWithVersion(currentVersion, PACKAGE_NAME)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (format === "none") {
|
if (format === "none") {
|
||||||
@@ -41,7 +43,6 @@ export async function addPluginToOpenCodeConfig(currentVersion: string): Promise
|
|||||||
const config = parseResult.config
|
const config = parseResult.config
|
||||||
const plugins = config.plugin ?? []
|
const plugins = config.plugin ?? []
|
||||||
|
|
||||||
// Check for existing plugin (either current or legacy name)
|
|
||||||
const currentNameIndex = plugins.findIndex(
|
const currentNameIndex = plugins.findIndex(
|
||||||
(plugin) => plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`)
|
(plugin) => plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`)
|
||||||
)
|
)
|
||||||
@@ -49,14 +50,12 @@ export async function addPluginToOpenCodeConfig(currentVersion: string): Promise
|
|||||||
(plugin) => plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`)
|
(plugin) => plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// If either name exists, update to new name
|
|
||||||
if (currentNameIndex !== -1) {
|
if (currentNameIndex !== -1) {
|
||||||
if (plugins[currentNameIndex] === pluginEntry) {
|
if (plugins[currentNameIndex] === pluginEntry) {
|
||||||
return { success: true, configPath: path }
|
return { success: true, configPath: path }
|
||||||
}
|
}
|
||||||
plugins[currentNameIndex] = pluginEntry
|
plugins[currentNameIndex] = pluginEntry
|
||||||
} else if (legacyNameIndex !== -1) {
|
} else if (legacyNameIndex !== -1) {
|
||||||
// Upgrade legacy name to new name
|
|
||||||
plugins[legacyNameIndex] = pluginEntry
|
plugins[legacyNameIndex] = pluginEntry
|
||||||
} else {
|
} else {
|
||||||
plugins.push(pluginEntry)
|
plugins.push(pluginEntry)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import { PLUGIN_NAME } from "../../shared/plugin-identity"
|
||||||
import { fetchNpmDistTags } from "./npm-dist-tags"
|
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
|
const PRIORITIZED_TAGS = ["latest", "beta", "next"] as const
|
||||||
|
|
||||||
function getFallbackEntry(version: string, packageName: string): string {
|
function getFallbackEntry(version: string, packageName: string): string {
|
||||||
@@ -18,7 +19,6 @@ export async function getPluginNameWithVersion(
|
|||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const distTags = await fetchNpmDistTags(packageName)
|
const distTags = await fetchNpmDistTags(packageName)
|
||||||
|
|
||||||
|
|
||||||
if (distTags) {
|
if (distTags) {
|
||||||
const allTags = new Set([...PRIORITIZED_TAGS, ...Object.keys(distTags)])
|
const allTags = new Set([...PRIORITIZED_TAGS, ...Object.keys(distTags)])
|
||||||
for (const tag of allTags) {
|
for (const tag of allTags) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { readFileSync } from "node:fs"
|
import { readFileSync } from "node:fs"
|
||||||
import { join } from "node:path"
|
import { join } from "node:path"
|
||||||
|
|
||||||
import { OhMyOpenCodeConfigSchema } from "../../../config"
|
import { OhMyOpenAgentConfigSchema } from "../../../config"
|
||||||
import { detectConfigFile, getOpenCodeConfigDir, parseJsonc } from "../../../shared"
|
import { detectConfigFile, getOpenCodeConfigDir, parseJsonc } from "../../../shared"
|
||||||
import { CHECK_IDS, CHECK_NAMES, PACKAGE_NAME } from "../constants"
|
import { CHECK_IDS, CHECK_NAMES, PACKAGE_NAME } from "../constants"
|
||||||
import type { CheckResult, DoctorIssue } from "../types"
|
import type { CheckResult, DoctorIssue } from "../types"
|
||||||
@@ -39,7 +39,7 @@ function validateConfig(): ConfigValidationResult {
|
|||||||
try {
|
try {
|
||||||
const content = readFileSync(configPath, "utf-8")
|
const content = readFileSync(configPath, "utf-8")
|
||||||
const rawConfig = parseJsonc<OmoConfig>(content)
|
const rawConfig = parseJsonc<OmoConfig>(content)
|
||||||
const schemaResult = OhMyOpenCodeConfigSchema.safeParse(rawConfig)
|
const schemaResult = OhMyOpenAgentConfigSchema.safeParse(rawConfig)
|
||||||
|
|
||||||
if (!schemaResult.success) {
|
if (!schemaResult.success) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
import { PLUGIN_NAME } from "../../../shared/plugin-identity"
|
||||||
import { readFileSync } from "node:fs"
|
import { readFileSync } from "node:fs"
|
||||||
import { join } from "node:path"
|
import { join } from "node:path"
|
||||||
import { detectConfigFile, getOpenCodeConfigPaths, parseJsonc } from "../../../shared"
|
import { detectConfigFile, getOpenCodeConfigPaths, parseJsonc } from "../../../shared"
|
||||||
import type { OmoConfig } from "./model-resolution-types"
|
import type { OmoConfig } from "./model-resolution-types"
|
||||||
|
|
||||||
const PACKAGE_NAME = "oh-my-opencode"
|
const PACKAGE_NAME = PLUGIN_NAME
|
||||||
const USER_CONFIG_BASE = join(
|
const USER_CONFIG_BASE = join(
|
||||||
getOpenCodeConfigPaths({ binary: "opencode", version: null }).configDir,
|
getOpenCodeConfigPaths({ binary: "opencode", version: null }).configDir,
|
||||||
PACKAGE_NAME
|
PACKAGE_NAME
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { PLUGIN_NAME } from "../../shared/plugin-identity"
|
||||||
import color from "picocolors"
|
import color from "picocolors"
|
||||||
|
|
||||||
export const SYMBOLS = {
|
export const SYMBOLS = {
|
||||||
@@ -38,6 +39,6 @@ export const EXIT_CODES = {
|
|||||||
|
|
||||||
export const MIN_OPENCODE_VERSION = "1.0.150"
|
export const MIN_OPENCODE_VERSION = "1.0.150"
|
||||||
|
|
||||||
export const PACKAGE_NAME = "oh-my-opencode"
|
export const PACKAGE_NAME = PLUGIN_NAME
|
||||||
|
|
||||||
export const OPENCODE_BINARIES = ["opencode", "opencode-desktop"] as const
|
export const OPENCODE_BINARIES = ["opencode", "opencode-desktop"] as const
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import pc from "picocolors"
|
import pc from "picocolors"
|
||||||
import type { RunOptions } from "./types"
|
import type { RunOptions } from "./types"
|
||||||
import type { OhMyOpenCodeConfig } from "../../config"
|
import type { OhMyOpenAgentConfig } from "../../config"
|
||||||
import { getAgentConfigKey, getAgentDisplayName } from "../../shared/agent-display-names"
|
import { getAgentConfigKey, getAgentDisplayName } from "../../shared/agent-display-names"
|
||||||
|
|
||||||
const CORE_AGENT_ORDER = ["sisyphus", "hephaestus", "prometheus", "atlas"] as const
|
const CORE_AGENT_ORDER = ["sisyphus", "hephaestus", "prometheus", "atlas"] as const
|
||||||
@@ -29,7 +29,7 @@ const normalizeAgentName = (agent?: string): ResolvedAgent | undefined => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isAgentDisabled = (agentConfigKey: string, config: OhMyOpenCodeConfig): boolean => {
|
const isAgentDisabled = (agentConfigKey: string, config: OhMyOpenAgentConfig): boolean => {
|
||||||
const lowered = agentConfigKey.toLowerCase()
|
const lowered = agentConfigKey.toLowerCase()
|
||||||
if (lowered === DEFAULT_AGENT && config.sisyphus_agent?.disabled === true) {
|
if (lowered === DEFAULT_AGENT && config.sisyphus_agent?.disabled === true) {
|
||||||
return true
|
return true
|
||||||
@@ -39,7 +39,7 @@ const isAgentDisabled = (agentConfigKey: string, config: OhMyOpenCodeConfig): bo
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const pickFallbackAgent = (config: OhMyOpenCodeConfig): CoreAgentKey => {
|
const pickFallbackAgent = (config: OhMyOpenAgentConfig): CoreAgentKey => {
|
||||||
for (const agent of CORE_AGENT_ORDER) {
|
for (const agent of CORE_AGENT_ORDER) {
|
||||||
if (!isAgentDisabled(agent, config)) {
|
if (!isAgentDisabled(agent, config)) {
|
||||||
return agent
|
return agent
|
||||||
@@ -50,7 +50,7 @@ const pickFallbackAgent = (config: OhMyOpenCodeConfig): CoreAgentKey => {
|
|||||||
|
|
||||||
export const resolveRunAgent = (
|
export const resolveRunAgent = (
|
||||||
options: RunOptions,
|
options: RunOptions,
|
||||||
pluginConfig: OhMyOpenCodeConfig,
|
pluginConfig: OhMyOpenAgentConfig,
|
||||||
env: EnvVars = process.env
|
env: EnvVars = process.env
|
||||||
): string => {
|
): string => {
|
||||||
const cliAgent = normalizeAgentName(options.agent)
|
const cliAgent = normalizeAgentName(options.agent)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
/// <reference types="bun-types" />
|
/// <reference types="bun-types" />
|
||||||
|
|
||||||
import { describe, it, expect, beforeEach, afterEach, vi } from "bun:test"
|
import { describe, it, expect } from "bun:test"
|
||||||
import type { OhMyOpenCodeConfig } from "../../config"
|
import type { OhMyOpenAgentConfig } from "../../config"
|
||||||
import { resolveRunAgent, waitForEventProcessorShutdown } from "./runner"
|
import { resolveRunAgent, waitForEventProcessorShutdown } from "./runner"
|
||||||
|
|
||||||
const createConfig = (overrides: Partial<OhMyOpenCodeConfig> = {}): OhMyOpenCodeConfig => ({
|
const createConfig = (overrides: Partial<OhMyOpenAgentConfig> = {}): OhMyOpenAgentConfig => ({
|
||||||
...overrides,
|
...overrides,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -133,23 +133,16 @@ describe("run with invalid model", () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// when
|
// when
|
||||||
// Note: This will actually try to run - but the issue is that resolveRunModel
|
|
||||||
// is called BEFORE the try block, so it throws an unhandled exception
|
|
||||||
// We're testing the runner's error handling
|
|
||||||
const { run } = await import("./runner")
|
const { run } = await import("./runner")
|
||||||
|
|
||||||
// This will throw because model "invalid" is invalid format
|
|
||||||
try {
|
try {
|
||||||
await run({
|
await run({
|
||||||
message: "test",
|
message: "test",
|
||||||
model: "invalid",
|
model: "invalid",
|
||||||
})
|
})
|
||||||
} catch {
|
} catch {
|
||||||
// Expected to potentially throw due to unhandled model resolution error
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
// then - verify error handling
|
|
||||||
// Currently this will fail because the error is not caught properly
|
|
||||||
console.error = originalError
|
console.error = originalError
|
||||||
process.exit = originalExit
|
process.exit = originalExit
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
export {
|
export {
|
||||||
OhMyOpenCodeConfigSchema,
|
OhMyOpenAgentConfigSchema,
|
||||||
} from "./schema"
|
} from "./schema"
|
||||||
|
|
||||||
export type {
|
export type {
|
||||||
OhMyOpenCodeConfig,
|
OhMyOpenAgentConfig,
|
||||||
AgentOverrideConfig,
|
AgentOverrideConfig,
|
||||||
AgentOverrides,
|
AgentOverrides,
|
||||||
McpName,
|
McpName,
|
||||||
|
|||||||
+22
-22
@@ -10,7 +10,7 @@ import {
|
|||||||
ExperimentalConfigSchema,
|
ExperimentalConfigSchema,
|
||||||
GitMasterConfigSchema,
|
GitMasterConfigSchema,
|
||||||
HookNameSchema,
|
HookNameSchema,
|
||||||
OhMyOpenCodeConfigSchema,
|
OhMyOpenAgentConfigSchema,
|
||||||
} from "./schema"
|
} from "./schema"
|
||||||
|
|
||||||
describe("disabled_mcps schema", () => {
|
describe("disabled_mcps schema", () => {
|
||||||
@@ -21,7 +21,7 @@ describe("disabled_mcps schema", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(config)
|
const result = OhMyOpenAgentConfigSchema.safeParse(config)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.success).toBe(true)
|
expect(result.success).toBe(true)
|
||||||
@@ -37,7 +37,7 @@ describe("disabled_mcps schema", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(config)
|
const result = OhMyOpenAgentConfigSchema.safeParse(config)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.success).toBe(true)
|
expect(result.success).toBe(true)
|
||||||
@@ -53,7 +53,7 @@ describe("disabled_mcps schema", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(config)
|
const result = OhMyOpenAgentConfigSchema.safeParse(config)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.success).toBe(true)
|
expect(result.success).toBe(true)
|
||||||
@@ -69,7 +69,7 @@ describe("disabled_mcps schema", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(config)
|
const result = OhMyOpenAgentConfigSchema.safeParse(config)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.success).toBe(true)
|
expect(result.success).toBe(true)
|
||||||
@@ -85,7 +85,7 @@ describe("disabled_mcps schema", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(config)
|
const result = OhMyOpenAgentConfigSchema.safeParse(config)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.success).toBe(false)
|
expect(result.success).toBe(false)
|
||||||
@@ -96,7 +96,7 @@ describe("disabled_mcps schema", () => {
|
|||||||
const config = {}
|
const config = {}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(config)
|
const result = OhMyOpenAgentConfigSchema.safeParse(config)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.success).toBe(true)
|
expect(result.success).toBe(true)
|
||||||
@@ -112,7 +112,7 @@ describe("disabled_mcps schema", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(config)
|
const result = OhMyOpenAgentConfigSchema.safeParse(config)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.success).toBe(false)
|
expect(result.success).toBe(false)
|
||||||
@@ -131,7 +131,7 @@ describe("disabled_mcps schema", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(config)
|
const result = OhMyOpenAgentConfigSchema.safeParse(config)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.success).toBe(true)
|
expect(result.success).toBe(true)
|
||||||
@@ -433,7 +433,7 @@ describe("Sisyphus-Junior agent override", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(config)
|
const result = OhMyOpenAgentConfigSchema.safeParse(config)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.success).toBe(true)
|
expect(result.success).toBe(true)
|
||||||
@@ -455,7 +455,7 @@ describe("Sisyphus-Junior agent override", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(config)
|
const result = OhMyOpenAgentConfigSchema.safeParse(config)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.success).toBe(true)
|
expect(result.success).toBe(true)
|
||||||
@@ -480,7 +480,7 @@ describe("Sisyphus-Junior agent override", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(config)
|
const result = OhMyOpenAgentConfigSchema.safeParse(config)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.success).toBe(true)
|
expect(result.success).toBe(true)
|
||||||
@@ -509,7 +509,7 @@ describe("Sisyphus-Junior agent override", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(config)
|
const result = OhMyOpenAgentConfigSchema.safeParse(config)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.success).toBe(true)
|
expect(result.success).toBe(true)
|
||||||
@@ -534,7 +534,7 @@ describe("Sisyphus-Junior agent override", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(config)
|
const result = OhMyOpenAgentConfigSchema.safeParse(config)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.success).toBe(true)
|
expect(result.success).toBe(true)
|
||||||
@@ -639,7 +639,7 @@ describe("OhMyOpenCodeConfigSchema - browser_automation_engine", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(input)
|
const result = OhMyOpenAgentConfigSchema.safeParse(input)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.success).toBe(true)
|
expect(result.success).toBe(true)
|
||||||
@@ -651,7 +651,7 @@ describe("OhMyOpenCodeConfigSchema - browser_automation_engine", () => {
|
|||||||
const input = {}
|
const input = {}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(input)
|
const result = OhMyOpenAgentConfigSchema.safeParse(input)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.success).toBe(true)
|
expect(result.success).toBe(true)
|
||||||
@@ -663,7 +663,7 @@ describe("OhMyOpenCodeConfigSchema - browser_automation_engine", () => {
|
|||||||
const input = { browser_automation_engine: { provider: "playwright-cli" } }
|
const input = { browser_automation_engine: { provider: "playwright-cli" } }
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(input)
|
const result = OhMyOpenAgentConfigSchema.safeParse(input)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(result.success).toBe(true)
|
expect(result.success).toBe(true)
|
||||||
@@ -677,7 +677,7 @@ describe("OhMyOpenCodeConfigSchema - hashline_edit", () => {
|
|||||||
const input = { hashline_edit: true }
|
const input = { hashline_edit: true }
|
||||||
|
|
||||||
//#when
|
//#when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(input)
|
const result = OhMyOpenAgentConfigSchema.safeParse(input)
|
||||||
|
|
||||||
//#then
|
//#then
|
||||||
expect(result.success).toBe(true)
|
expect(result.success).toBe(true)
|
||||||
@@ -689,7 +689,7 @@ describe("OhMyOpenCodeConfigSchema - hashline_edit", () => {
|
|||||||
const input = { hashline_edit: false }
|
const input = { hashline_edit: false }
|
||||||
|
|
||||||
//#when
|
//#when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(input)
|
const result = OhMyOpenAgentConfigSchema.safeParse(input)
|
||||||
|
|
||||||
//#then
|
//#then
|
||||||
expect(result.success).toBe(true)
|
expect(result.success).toBe(true)
|
||||||
@@ -701,7 +701,7 @@ describe("OhMyOpenCodeConfigSchema - hashline_edit", () => {
|
|||||||
const input = { auto_update: true }
|
const input = { auto_update: true }
|
||||||
|
|
||||||
//#when
|
//#when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(input)
|
const result = OhMyOpenAgentConfigSchema.safeParse(input)
|
||||||
|
|
||||||
//#then
|
//#then
|
||||||
expect(result.success).toBe(true)
|
expect(result.success).toBe(true)
|
||||||
@@ -713,7 +713,7 @@ describe("OhMyOpenCodeConfigSchema - hashline_edit", () => {
|
|||||||
const input = { hashline_edit: "true" }
|
const input = { hashline_edit: "true" }
|
||||||
|
|
||||||
//#when
|
//#when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(input)
|
const result = OhMyOpenAgentConfigSchema.safeParse(input)
|
||||||
|
|
||||||
//#then
|
//#then
|
||||||
expect(result.success).toBe(false)
|
expect(result.success).toBe(false)
|
||||||
@@ -928,7 +928,7 @@ describe("skills schema", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//#when
|
//#when
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(config)
|
const result = OhMyOpenAgentConfigSchema.safeParse(config)
|
||||||
|
|
||||||
//#then
|
//#then
|
||||||
expect(result.success).toBe(true)
|
expect(result.success).toBe(true)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { TmuxConfigSchema } from "./tmux"
|
|||||||
import { StartWorkConfigSchema } from "./start-work"
|
import { StartWorkConfigSchema } from "./start-work"
|
||||||
import { WebsearchConfigSchema } from "./websearch"
|
import { WebsearchConfigSchema } from "./websearch"
|
||||||
|
|
||||||
export const OhMyOpenCodeConfigSchema = z.object({
|
export const OhMyOpenAgentConfigSchema = z.object({
|
||||||
$schema: z.string().optional(),
|
$schema: z.string().optional(),
|
||||||
/** Enable new task system (default: false) */
|
/** Enable new task system (default: false) */
|
||||||
new_task_system_enabled: z.boolean().optional(),
|
new_task_system_enabled: z.boolean().optional(),
|
||||||
@@ -66,4 +66,4 @@ export const OhMyOpenCodeConfigSchema = z.object({
|
|||||||
_migrations: z.array(z.string()).optional(),
|
_migrations: z.array(z.string()).optional(),
|
||||||
})
|
})
|
||||||
|
|
||||||
export type OhMyOpenCodeConfig = z.infer<typeof OhMyOpenCodeConfigSchema>
|
export type OhMyOpenAgentConfig = z.infer<typeof OhMyOpenAgentConfigSchema>
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
import type { AvailableSkill } from "./agents/dynamic-agent-prompt-builder"
|
import type { AvailableSkill } from "./agents/dynamic-agent-prompt-builder"
|
||||||
import type { HookName, OhMyOpenCodeConfig } from "./config"
|
import type { HookName, OhMyOpenAgentConfig } from "./config"
|
||||||
import type { LoadedSkill } from "./features/opencode-skill-loader/types"
|
import type { LoadedSkill } from "./features/opencode-skill-loader/types"
|
||||||
import type { BackgroundManager } from "./features/background-agent"
|
import type { BackgroundManager } from "./features/background-agent"
|
||||||
import type { PluginContext } from "./plugin/types"
|
import type { PluginContext } from "./plugin/types"
|
||||||
@@ -27,7 +27,7 @@ export function disposeCreatedHooks(hooks: DisposableCreatedHooks): void {
|
|||||||
|
|
||||||
export function createHooks(args: {
|
export function createHooks(args: {
|
||||||
ctx: PluginContext
|
ctx: PluginContext
|
||||||
pluginConfig: OhMyOpenCodeConfig
|
pluginConfig: OhMyOpenAgentConfig
|
||||||
modelCacheState: ModelCacheState
|
modelCacheState: ModelCacheState
|
||||||
backgroundManager: BackgroundManager
|
backgroundManager: BackgroundManager
|
||||||
isHookEnabled: (hookName: HookName) => boolean
|
isHookEnabled: (hookName: HookName) => boolean
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { OhMyOpenCodeConfig } from "./config"
|
import type { OhMyOpenAgentConfig } from "./config"
|
||||||
import type { ModelCacheState } from "./plugin-state"
|
import type { ModelCacheState } from "./plugin-state"
|
||||||
import type { PluginContext, TmuxConfig } from "./plugin/types"
|
import type { PluginContext, TmuxConfig } from "./plugin/types"
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ export type Managers = {
|
|||||||
|
|
||||||
export function createManagers(args: {
|
export function createManagers(args: {
|
||||||
ctx: PluginContext
|
ctx: PluginContext
|
||||||
pluginConfig: OhMyOpenCodeConfig
|
pluginConfig: OhMyOpenAgentConfig
|
||||||
tmuxConfig: TmuxConfig
|
tmuxConfig: TmuxConfig
|
||||||
modelCacheState: ModelCacheState
|
modelCacheState: ModelCacheState
|
||||||
backgroundNotificationHookEnabled: boolean
|
backgroundNotificationHookEnabled: boolean
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
import type { AvailableCategory, AvailableSkill } from "./agents/dynamic-agent-prompt-builder"
|
import type { AvailableCategory, AvailableSkill } from "./agents/dynamic-agent-prompt-builder"
|
||||||
import type { OhMyOpenCodeConfig } from "./config"
|
import type { OhMyOpenAgentConfig } from "./config"
|
||||||
import type { BrowserAutomationProvider } from "./config/schema/browser-automation"
|
import type { BrowserAutomationProvider } from "./config/schema/browser-automation"
|
||||||
import type { LoadedSkill } from "./features/opencode-skill-loader/types"
|
import type { LoadedSkill } from "./features/opencode-skill-loader/types"
|
||||||
import type { PluginContext, ToolsRecord } from "./plugin/types"
|
import type { PluginContext, ToolsRecord } from "./plugin/types"
|
||||||
@@ -21,7 +21,7 @@ export type CreateToolsResult = {
|
|||||||
|
|
||||||
export async function createTools(args: {
|
export async function createTools(args: {
|
||||||
ctx: PluginContext
|
ctx: PluginContext
|
||||||
pluginConfig: OhMyOpenCodeConfig
|
pluginConfig: OhMyOpenAgentConfig
|
||||||
managers: Pick<Managers, "backgroundManager" | "tmuxSessionManager" | "skillMcpManager">
|
managers: Pick<Managers, "backgroundManager" | "tmuxSessionManager" | "skillMcpManager">
|
||||||
}): Promise<CreateToolsResult> {
|
}): Promise<CreateToolsResult> {
|
||||||
const { ctx, pluginConfig, managers } = args
|
const { ctx, pluginConfig, managers } = args
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { describe, test, expect, beforeEach, afterEach } from "bun:test"
|
import { describe, test, expect, beforeEach, afterEach } from "bun:test"
|
||||||
import { existsSync, mkdirSync, rmSync, writeFileSync, readdirSync } from "fs"
|
import { existsSync, mkdirSync, rmSync, writeFileSync, readdirSync } from "fs"
|
||||||
import { join } from "path"
|
import { join } from "path"
|
||||||
import type { OhMyOpenCodeConfig } from "../../config/schema"
|
import type { OhMyOpenAgentConfig } from "../../config/schema"
|
||||||
import {
|
import {
|
||||||
getSessionTaskDir,
|
getSessionTaskDir,
|
||||||
listSessionTaskFiles,
|
listSessionTaskFiles,
|
||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
const TEST_DIR = ".test-session-storage"
|
const TEST_DIR = ".test-session-storage"
|
||||||
const TEST_DIR_ABS = join(process.cwd(), TEST_DIR)
|
const TEST_DIR_ABS = join(process.cwd(), TEST_DIR)
|
||||||
|
|
||||||
function makeConfig(storagePath: string): Partial<OhMyOpenCodeConfig> {
|
function makeConfig(storagePath: string): Partial<OhMyOpenAgentConfig> {
|
||||||
return {
|
return {
|
||||||
sisyphus: {
|
sisyphus: {
|
||||||
tasks: { storage_path: storagePath, claude_code_compat: false },
|
tasks: { storage_path: storagePath, claude_code_compat: false },
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import { join } from "path"
|
import { join } from "path"
|
||||||
import { existsSync, readdirSync, statSync } from "fs"
|
import { existsSync, readdirSync, statSync } from "fs"
|
||||||
import { getTaskDir } from "./storage"
|
import { getTaskDir } from "./storage"
|
||||||
import type { OhMyOpenCodeConfig } from "../../config/schema"
|
import type { OhMyOpenAgentConfig } from "../../config/schema"
|
||||||
|
|
||||||
export function getSessionTaskDir(
|
export function getSessionTaskDir(
|
||||||
config: Partial<OhMyOpenCodeConfig>,
|
config: Partial<OhMyOpenAgentConfig>,
|
||||||
sessionID: string,
|
sessionID: string,
|
||||||
): string {
|
): string {
|
||||||
return join(getTaskDir(config), sessionID)
|
return join(getTaskDir(config), sessionID)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function listSessionTaskFiles(
|
export function listSessionTaskFiles(
|
||||||
config: Partial<OhMyOpenCodeConfig>,
|
config: Partial<OhMyOpenAgentConfig>,
|
||||||
sessionID: string,
|
sessionID: string,
|
||||||
): string[] {
|
): string[] {
|
||||||
const dir = getSessionTaskDir(config, sessionID)
|
const dir = getSessionTaskDir(config, sessionID)
|
||||||
@@ -22,7 +22,7 @@ export function listSessionTaskFiles(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function listAllSessionDirs(
|
export function listAllSessionDirs(
|
||||||
config: Partial<OhMyOpenCodeConfig>,
|
config: Partial<OhMyOpenAgentConfig>,
|
||||||
): string[] {
|
): string[] {
|
||||||
const baseDir = getTaskDir(config)
|
const baseDir = getTaskDir(config)
|
||||||
if (!existsSync(baseDir)) return []
|
if (!existsSync(baseDir)) return []
|
||||||
@@ -38,7 +38,7 @@ export interface TaskLocation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function findTaskAcrossSessions(
|
export function findTaskAcrossSessions(
|
||||||
config: Partial<OhMyOpenCodeConfig>,
|
config: Partial<OhMyOpenAgentConfig>,
|
||||||
taskId: string,
|
taskId: string,
|
||||||
): TaskLocation | null {
|
): TaskLocation | null {
|
||||||
const sessionDirs = listAllSessionDirs(config)
|
const sessionDirs = listAllSessionDirs(config)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
resolveTaskListId,
|
resolveTaskListId,
|
||||||
sanitizePathSegment,
|
sanitizePathSegment,
|
||||||
} from "./storage"
|
} from "./storage"
|
||||||
import type { OhMyOpenCodeConfig } from "../../config/schema"
|
import type { OhMyOpenAgentConfig } from "../../config/schema"
|
||||||
|
|
||||||
const TEST_DIR = ".test-claude-tasks"
|
const TEST_DIR = ".test-claude-tasks"
|
||||||
const TEST_DIR_ABS = join(process.cwd(), TEST_DIR)
|
const TEST_DIR_ABS = join(process.cwd(), TEST_DIR)
|
||||||
@@ -52,7 +52,7 @@ describe("getTaskDir", () => {
|
|||||||
|
|
||||||
test("returns global config path for default config", () => {
|
test("returns global config path for default config", () => {
|
||||||
//#given
|
//#given
|
||||||
const config: Partial<OhMyOpenCodeConfig> = {}
|
const config: Partial<OhMyOpenAgentConfig> = {}
|
||||||
const configDir = getOpenCodeConfigDir({ binary: "opencode" })
|
const configDir = getOpenCodeConfigDir({ binary: "opencode" })
|
||||||
const expectedListId = sanitizePathSegment(basename(process.cwd()))
|
const expectedListId = sanitizePathSegment(basename(process.cwd()))
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ describe("getTaskDir", () => {
|
|||||||
|
|
||||||
test("returns absolute storage_path without joining cwd", () => {
|
test("returns absolute storage_path without joining cwd", () => {
|
||||||
//#given
|
//#given
|
||||||
const config: Partial<OhMyOpenCodeConfig> = {
|
const config: Partial<OhMyOpenAgentConfig> = {
|
||||||
sisyphus: {
|
sisyphus: {
|
||||||
tasks: {
|
tasks: {
|
||||||
storage_path: "/tmp/custom-task-path",
|
storage_path: "/tmp/custom-task-path",
|
||||||
@@ -121,7 +121,7 @@ describe("getTaskDir", () => {
|
|||||||
|
|
||||||
test("joins relative storage_path with cwd", () => {
|
test("joins relative storage_path with cwd", () => {
|
||||||
//#given
|
//#given
|
||||||
const config: Partial<OhMyOpenCodeConfig> = {
|
const config: Partial<OhMyOpenAgentConfig> = {
|
||||||
sisyphus: {
|
sisyphus: {
|
||||||
tasks: {
|
tasks: {
|
||||||
storage_path: ".custom/tasks",
|
storage_path: ".custom/tasks",
|
||||||
@@ -263,7 +263,7 @@ describe("listTaskFiles", () => {
|
|||||||
|
|
||||||
test("returns empty array for non-existent directory", () => {
|
test("returns empty array for non-existent directory", () => {
|
||||||
//#given
|
//#given
|
||||||
const config: Partial<OhMyOpenCodeConfig> = {
|
const config: Partial<OhMyOpenAgentConfig> = {
|
||||||
new_task_system_enabled: false,
|
new_task_system_enabled: false,
|
||||||
sisyphus: { tasks: { storage_path: TEST_DIR, claude_code_compat: false } }
|
sisyphus: { tasks: { storage_path: TEST_DIR, claude_code_compat: false } }
|
||||||
}
|
}
|
||||||
@@ -277,7 +277,7 @@ describe("listTaskFiles", () => {
|
|||||||
|
|
||||||
test("returns empty array for directory with no task files", () => {
|
test("returns empty array for directory with no task files", () => {
|
||||||
//#given
|
//#given
|
||||||
const config: Partial<OhMyOpenCodeConfig> = {
|
const config: Partial<OhMyOpenAgentConfig> = {
|
||||||
new_task_system_enabled: false,
|
new_task_system_enabled: false,
|
||||||
sisyphus: { tasks: { storage_path: TEST_DIR, claude_code_compat: false } }
|
sisyphus: { tasks: { storage_path: TEST_DIR, claude_code_compat: false } }
|
||||||
}
|
}
|
||||||
@@ -293,7 +293,7 @@ describe("listTaskFiles", () => {
|
|||||||
|
|
||||||
test("lists task files with T- prefix and .json extension", () => {
|
test("lists task files with T- prefix and .json extension", () => {
|
||||||
//#given
|
//#given
|
||||||
const config: Partial<OhMyOpenCodeConfig> = {
|
const config: Partial<OhMyOpenAgentConfig> = {
|
||||||
new_task_system_enabled: false,
|
new_task_system_enabled: false,
|
||||||
sisyphus: { tasks: { storage_path: TEST_DIR, claude_code_compat: false } }
|
sisyphus: { tasks: { storage_path: TEST_DIR, claude_code_compat: false } }
|
||||||
}
|
}
|
||||||
@@ -314,7 +314,7 @@ describe("listTaskFiles", () => {
|
|||||||
|
|
||||||
test("returns task IDs without .json extension", () => {
|
test("returns task IDs without .json extension", () => {
|
||||||
//#given
|
//#given
|
||||||
const config: Partial<OhMyOpenCodeConfig> = {
|
const config: Partial<OhMyOpenAgentConfig> = {
|
||||||
new_task_system_enabled: false,
|
new_task_system_enabled: false,
|
||||||
sisyphus: { tasks: { storage_path: TEST_DIR, claude_code_compat: false } }
|
sisyphus: { tasks: { storage_path: TEST_DIR, claude_code_compat: false } }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, unlinkS
|
|||||||
import { randomUUID } from "crypto"
|
import { randomUUID } from "crypto"
|
||||||
import { getOpenCodeConfigDir } from "../../shared/opencode-config-dir"
|
import { getOpenCodeConfigDir } from "../../shared/opencode-config-dir"
|
||||||
import type { z } from "zod"
|
import type { z } from "zod"
|
||||||
import type { OhMyOpenCodeConfig } from "../../config/schema"
|
import type { OhMyOpenAgentConfig } from "../../config/schema"
|
||||||
|
|
||||||
export function getTaskDir(config: Partial<OhMyOpenCodeConfig> = {}): string {
|
export function getTaskDir(config: Partial<OhMyOpenAgentConfig> = {}): string {
|
||||||
const tasksConfig = config.sisyphus?.tasks
|
const tasksConfig = config.sisyphus?.tasks
|
||||||
const storagePath = tasksConfig?.storage_path
|
const storagePath = tasksConfig?.storage_path
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ export function sanitizePathSegment(value: string): string {
|
|||||||
return value.replace(/[^a-zA-Z0-9_-]/g, "-") || "default"
|
return value.replace(/[^a-zA-Z0-9_-]/g, "-") || "default"
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveTaskListId(config: Partial<OhMyOpenCodeConfig> = {}): string {
|
export function resolveTaskListId(config: Partial<OhMyOpenAgentConfig> = {}): string {
|
||||||
const envId = process.env.ULTRAWORK_TASK_LIST_ID?.trim()
|
const envId = process.env.ULTRAWORK_TASK_LIST_ID?.trim()
|
||||||
if (envId) return sanitizePathSegment(envId)
|
if (envId) return sanitizePathSegment(envId)
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ export function generateTaskId(): string {
|
|||||||
return `T-${randomUUID()}`
|
return `T-${randomUUID()}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function listTaskFiles(config: Partial<OhMyOpenCodeConfig> = {}): string[] {
|
export function listTaskFiles(config: Partial<OhMyOpenAgentConfig> = {}): string[] {
|
||||||
const dir = getTaskDir(config)
|
const dir = getTaskDir(config)
|
||||||
if (!existsSync(dir)) return []
|
if (!existsSync(dir)) return []
|
||||||
return readdirSync(dir)
|
return readdirSync(dir)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { AutoCompactState } from "./types";
|
import type { AutoCompactState } from "./types";
|
||||||
import type { OhMyOpenCodeConfig } from "../../config";
|
import type { OhMyOpenAgentConfig } from "../../config";
|
||||||
import type { ExperimentalConfig } from "../../config";
|
import type { ExperimentalConfig } from "../../config";
|
||||||
import { TRUNCATE_CONFIG } from "./types";
|
import { TRUNCATE_CONFIG } from "./types";
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ export async function executeCompact(
|
|||||||
autoCompactState: AutoCompactState,
|
autoCompactState: AutoCompactState,
|
||||||
client: Client,
|
client: Client,
|
||||||
directory: string,
|
directory: string,
|
||||||
pluginConfig: OhMyOpenCodeConfig,
|
pluginConfig: OhMyOpenAgentConfig,
|
||||||
_experimental?: ExperimentalConfig
|
_experimental?: ExperimentalConfig
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
void _experimental
|
void _experimental
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { PluginInput } from "@opencode-ai/plugin"
|
import type { PluginInput } from "@opencode-ai/plugin"
|
||||||
import type { Client } from "./client"
|
import type { Client } from "./client"
|
||||||
import type { AutoCompactState, ParsedTokenLimitError } from "./types"
|
import type { AutoCompactState, ParsedTokenLimitError } from "./types"
|
||||||
import type { ExperimentalConfig, OhMyOpenCodeConfig } from "../../config"
|
import type { ExperimentalConfig, OhMyOpenAgentConfig } from "../../config"
|
||||||
import { parseAnthropicTokenLimitError } from "./parser"
|
import { parseAnthropicTokenLimitError } from "./parser"
|
||||||
import { executeCompact, getLastAssistant } from "./executor"
|
import { executeCompact, getLastAssistant } from "./executor"
|
||||||
import { attemptDeduplicationRecovery } from "./deduplication-recovery"
|
import { attemptDeduplicationRecovery } from "./deduplication-recovery"
|
||||||
@@ -9,7 +9,7 @@ import { log } from "../../shared/logger"
|
|||||||
|
|
||||||
export interface AnthropicContextWindowLimitRecoveryOptions {
|
export interface AnthropicContextWindowLimitRecoveryOptions {
|
||||||
experimental?: ExperimentalConfig
|
experimental?: ExperimentalConfig
|
||||||
pluginConfig: OhMyOpenCodeConfig
|
pluginConfig: OhMyOpenAgentConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
function createRecoveryState(): AutoCompactState {
|
function createRecoveryState(): AutoCompactState {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test"
|
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test"
|
||||||
import { runSummarizeRetryStrategy } from "./summarize-retry-strategy"
|
import { runSummarizeRetryStrategy } from "./summarize-retry-strategy"
|
||||||
import type { AutoCompactState, ParsedTokenLimitError, RetryState } from "./types"
|
import type { AutoCompactState, ParsedTokenLimitError, RetryState } from "./types"
|
||||||
import type { OhMyOpenCodeConfig } from "../../config"
|
import type { OhMyOpenAgentConfig } from "../../config"
|
||||||
|
|
||||||
type TimeoutCall = {
|
type TimeoutCall = {
|
||||||
delay: number
|
delay: number
|
||||||
@@ -72,7 +72,7 @@ describe("runSummarizeRetryStrategy", () => {
|
|||||||
autoCompactState,
|
autoCompactState,
|
||||||
client: client as never,
|
client: client as never,
|
||||||
directory,
|
directory,
|
||||||
pluginConfig: {} as OhMyOpenCodeConfig,
|
pluginConfig: {} as OhMyOpenAgentConfig,
|
||||||
})
|
})
|
||||||
|
|
||||||
//#then
|
//#then
|
||||||
@@ -111,7 +111,7 @@ describe("runSummarizeRetryStrategy", () => {
|
|||||||
autoCompactState,
|
autoCompactState,
|
||||||
client: client as never,
|
client: client as never,
|
||||||
directory,
|
directory,
|
||||||
pluginConfig: {} as OhMyOpenCodeConfig,
|
pluginConfig: {} as OhMyOpenAgentConfig,
|
||||||
})
|
})
|
||||||
|
|
||||||
//#then
|
//#then
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { AutoCompactState } from "./types"
|
import type { AutoCompactState } from "./types"
|
||||||
import type { OhMyOpenCodeConfig } from "../../config"
|
import type { OhMyOpenAgentConfig } from "../../config"
|
||||||
import { RETRY_CONFIG } from "./types"
|
import { RETRY_CONFIG } from "./types"
|
||||||
import type { Client } from "./client"
|
import type { Client } from "./client"
|
||||||
import { clearSessionState, getEmptyContentAttempt, getOrCreateRetryState } from "./state"
|
import { clearSessionState, getEmptyContentAttempt, getOrCreateRetryState } from "./state"
|
||||||
@@ -15,7 +15,7 @@ export async function runSummarizeRetryStrategy(params: {
|
|||||||
autoCompactState: AutoCompactState
|
autoCompactState: AutoCompactState
|
||||||
client: Client
|
client: Client
|
||||||
directory: string
|
directory: string
|
||||||
pluginConfig: OhMyOpenCodeConfig
|
pluginConfig: OhMyOpenAgentConfig
|
||||||
errorType?: string
|
errorType?: string
|
||||||
messageIndex?: number
|
messageIndex?: number
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { describe, expect, it, mock } from "bun:test"
|
import { describe, expect, it, mock } from "bun:test"
|
||||||
|
|
||||||
import { OhMyOpenCodeConfigSchema } from "../config"
|
import { OhMyOpenAgentConfigSchema } from "../config"
|
||||||
|
|
||||||
const { createPreemptiveCompactionHook } = await import("./preemptive-compaction")
|
const { createPreemptiveCompactionHook } = await import("./preemptive-compaction")
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ describe("preemptive-compaction aws-bedrock-anthropic", () => {
|
|||||||
it("triggers compaction for aws-bedrock-anthropic provider when usage exceeds threshold", async () => {
|
it("triggers compaction for aws-bedrock-anthropic provider when usage exceeds threshold", async () => {
|
||||||
// given
|
// given
|
||||||
const ctx = createMockContext()
|
const ctx = createMockContext()
|
||||||
const pluginConfig = OhMyOpenCodeConfigSchema.parse({})
|
const pluginConfig = OhMyOpenAgentConfigSchema.parse({})
|
||||||
const hook = createPreemptiveCompactionHook(ctx, pluginConfig)
|
const hook = createPreemptiveCompactionHook(ctx, pluginConfig)
|
||||||
const sessionID = "ses_aws_bedrock_anthropic_high"
|
const sessionID = "ses_aws_bedrock_anthropic_high"
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { log } from "../shared/logger"
|
import { log } from "../shared/logger"
|
||||||
import type { OhMyOpenCodeConfig } from "../config"
|
import type { OhMyOpenAgentConfig } from "../config"
|
||||||
import {
|
import {
|
||||||
resolveActualContextLimit,
|
resolveActualContextLimit,
|
||||||
type ContextLimitModelCacheState,
|
type ContextLimitModelCacheState,
|
||||||
@@ -61,7 +61,7 @@ type PluginInput = {
|
|||||||
|
|
||||||
export function createPreemptiveCompactionHook(
|
export function createPreemptiveCompactionHook(
|
||||||
ctx: PluginInput,
|
ctx: PluginInput,
|
||||||
pluginConfig: OhMyOpenCodeConfig,
|
pluginConfig: OhMyOpenAgentConfig,
|
||||||
modelCacheState?: ContextLimitModelCacheState,
|
modelCacheState?: ContextLimitModelCacheState,
|
||||||
) {
|
) {
|
||||||
const compactionInProgress = new Set<string>()
|
const compactionInProgress = new Set<string>()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { OhMyOpenCodeConfig } from "../../config"
|
import type { OhMyOpenAgentConfig } from "../../config"
|
||||||
import { HOOK_NAME } from "./constants"
|
import { HOOK_NAME } from "./constants"
|
||||||
import { log } from "../../shared/logger"
|
import { log } from "../../shared/logger"
|
||||||
import { SessionCategoryRegistry } from "../../shared/session-category-registry"
|
import { SessionCategoryRegistry } from "../../shared/session-category-registry"
|
||||||
@@ -8,7 +8,7 @@ type ResolveFallbackBootstrapModelOptions = {
|
|||||||
source: string
|
source: string
|
||||||
eventModel?: string
|
eventModel?: string
|
||||||
resolvedAgent?: string
|
resolvedAgent?: string
|
||||||
pluginConfig?: OhMyOpenCodeConfig
|
pluginConfig?: OhMyOpenAgentConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveFallbackBootstrapModel(
|
export function resolveFallbackBootstrapModel(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { OhMyOpenCodeConfig } from "../../config"
|
import type { OhMyOpenAgentConfig } from "../../config"
|
||||||
import { agentPattern } from "./agent-resolver"
|
import { agentPattern } from "./agent-resolver"
|
||||||
import { HOOK_NAME } from "./constants"
|
import { HOOK_NAME } from "./constants"
|
||||||
import { log } from "../../shared/logger"
|
import { log } from "../../shared/logger"
|
||||||
@@ -8,7 +8,7 @@ import { normalizeFallbackModels } from "../../shared/model-resolver"
|
|||||||
export function getFallbackModelsForSession(
|
export function getFallbackModelsForSession(
|
||||||
sessionID: string,
|
sessionID: string,
|
||||||
agent: string | undefined,
|
agent: string | undefined,
|
||||||
pluginConfig: OhMyOpenCodeConfig | undefined
|
pluginConfig: OhMyOpenAgentConfig | undefined
|
||||||
): string[] {
|
): string[] {
|
||||||
if (!pluginConfig) return []
|
if (!pluginConfig) return []
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { describe, expect, test, beforeEach, afterEach, spyOn } from "bun:test"
|
import { describe, expect, test, beforeEach, afterEach, spyOn } from "bun:test"
|
||||||
import { createRuntimeFallbackHook } from "./index"
|
import { createRuntimeFallbackHook } from "./index"
|
||||||
import type { RuntimeFallbackConfig, OhMyOpenCodeConfig } from "../../config"
|
import type { RuntimeFallbackConfig, OhMyOpenAgentConfig } from "../../config"
|
||||||
import * as sharedModule from "../../shared"
|
import * as sharedModule from "../../shared"
|
||||||
import { SessionCategoryRegistry } from "../../shared/session-category-registry"
|
import { SessionCategoryRegistry } from "../../shared/session-category-registry"
|
||||||
|
|
||||||
@@ -62,32 +62,26 @@ describe("runtime-fallback", () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMockPluginConfigWithCategoryFallback(fallbackModels: string[]): OhMyOpenCodeConfig {
|
function createMockPluginConfigWithCategoryFallback(fallbackModels: string[]): OhMyOpenAgentConfig { return {
|
||||||
return {
|
categories: {
|
||||||
categories: {
|
test: {
|
||||||
test: {
|
fallback_models: fallbackModels,
|
||||||
fallback_models: fallbackModels,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
} }
|
||||||
|
|
||||||
function createMockPluginConfigWithCategoryModel(
|
function createMockPluginConfigWithCategoryModel(categoryName: string,
|
||||||
categoryName: string,
|
model: string,
|
||||||
model: string,
|
fallbackModels: string[],
|
||||||
fallbackModels: string[],
|
variant?: string,): OhMyOpenAgentConfig { return {
|
||||||
variant?: string,
|
categories: {
|
||||||
): OhMyOpenCodeConfig {
|
[categoryName]: {
|
||||||
return {
|
model,
|
||||||
categories: {
|
fallback_models: fallbackModels,
|
||||||
[categoryName]: {
|
...(variant ? { variant } : {}),
|
||||||
model,
|
|
||||||
fallback_models: fallbackModels,
|
|
||||||
...(variant ? { variant } : {}),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
} }
|
||||||
|
|
||||||
describe("session.error handling", () => {
|
describe("session.error handling", () => {
|
||||||
test("should detect retryable error with status code 429", async () => {
|
test("should detect retryable error with status code 429", async () => {
|
||||||
@@ -2297,15 +2291,13 @@ describe("runtime-fallback", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe("fallback models configuration", () => {
|
describe("fallback models configuration", () => {
|
||||||
function createMockPluginConfigWithAgentFallback(agentName: string, fallbackModels: string[]): OhMyOpenCodeConfig {
|
function createMockPluginConfigWithAgentFallback(agentName: string, fallbackModels: string[]): OhMyOpenAgentConfig { return {
|
||||||
return {
|
agents: {
|
||||||
agents: {
|
[agentName]: {
|
||||||
[agentName]: {
|
fallback_models: fallbackModels,
|
||||||
fallback_models: fallbackModels,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
} }
|
||||||
|
|
||||||
test("should use agent-level fallback_models", async () => {
|
test("should use agent-level fallback_models", async () => {
|
||||||
const input = createMockPluginInput()
|
const input = createMockPluginInput()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { RuntimeFallbackConfig, OhMyOpenCodeConfig } from "../../config"
|
import type { RuntimeFallbackConfig, OhMyOpenAgentConfig } from "../../config"
|
||||||
|
|
||||||
export interface RuntimeFallbackInterval {
|
export interface RuntimeFallbackInterval {
|
||||||
unref: () => void
|
unref: () => void
|
||||||
@@ -53,7 +53,7 @@ export interface FallbackResult {
|
|||||||
|
|
||||||
export interface RuntimeFallbackOptions {
|
export interface RuntimeFallbackOptions {
|
||||||
config?: RuntimeFallbackConfig
|
config?: RuntimeFallbackConfig
|
||||||
pluginConfig?: OhMyOpenCodeConfig
|
pluginConfig?: OhMyOpenAgentConfig
|
||||||
session_timeout_ms?: number
|
session_timeout_ms?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ export interface HookDeps {
|
|||||||
ctx: RuntimeFallbackPluginInput
|
ctx: RuntimeFallbackPluginInput
|
||||||
config: Required<RuntimeFallbackConfig>
|
config: Required<RuntimeFallbackConfig>
|
||||||
options: RuntimeFallbackOptions | undefined
|
options: RuntimeFallbackOptions | undefined
|
||||||
pluginConfig: OhMyOpenCodeConfig | undefined
|
pluginConfig: OhMyOpenAgentConfig | undefined
|
||||||
sessionStates: Map<string, FallbackState>
|
sessionStates: Map<string, FallbackState>
|
||||||
sessionLastAccess: Map<string, number>
|
sessionLastAccess: Map<string, number>
|
||||||
sessionRetryInFlight: Set<string>
|
sessionRetryInFlight: Set<string>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import type { OhMyOpenCodeConfig } from "../../config"
|
import type { OhMyOpenAgentConfig } from "../../config"
|
||||||
import { getSessionAgent } from "../../features/claude-code-session-state"
|
import { getSessionAgent } from "../../features/claude-code-session-state"
|
||||||
import { getAgentConfigKey } from "../../shared/agent-display-names"
|
import { getAgentConfigKey } from "../../shared/agent-display-names"
|
||||||
|
|
||||||
export function resolveCompactionModel(
|
export function resolveCompactionModel(
|
||||||
pluginConfig: OhMyOpenCodeConfig,
|
pluginConfig: OhMyOpenAgentConfig,
|
||||||
sessionID: string,
|
sessionID: string,
|
||||||
originalProviderID: string,
|
originalProviderID: string,
|
||||||
originalModelID: string
|
originalModelID: string
|
||||||
|
|||||||
+3
-3
@@ -17,7 +17,7 @@ import { startTmuxCheck } from "./tools"
|
|||||||
|
|
||||||
let activePluginDispose: PluginDispose | null = null
|
let activePluginDispose: PluginDispose | null = null
|
||||||
|
|
||||||
const OhMyOpenCodePlugin: Plugin = async (ctx) => {
|
const OhMyOpenAgentPlugin: Plugin = async (ctx) => {
|
||||||
// Initialize config context for plugin runtime (prevents warnings from hooks)
|
// Initialize config context for plugin runtime (prevents warnings from hooks)
|
||||||
initConfigContext("opencode", null)
|
initConfigContext("opencode", null)
|
||||||
log("[OhMyOpenCodePlugin] ENTRY - plugin loading", {
|
log("[OhMyOpenCodePlugin] ENTRY - plugin loading", {
|
||||||
@@ -108,10 +108,10 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default OhMyOpenCodePlugin
|
export default OhMyOpenAgentPlugin
|
||||||
|
|
||||||
export type {
|
export type {
|
||||||
OhMyOpenCodeConfig,
|
OhMyOpenAgentConfig,
|
||||||
AgentName,
|
AgentName,
|
||||||
AgentOverrideConfig,
|
AgentOverrideConfig,
|
||||||
AgentOverrides,
|
AgentOverrides,
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import { createWebsearchConfig } from "./websearch"
|
import { createWebsearchConfig } from "./websearch"
|
||||||
import { context7 } from "./context7"
|
import { context7 } from "./context7"
|
||||||
import { grep_app } from "./grep-app"
|
import { grep_app } from "./grep-app"
|
||||||
import type { OhMyOpenCodeConfig } from "../config/schema"
|
import type { OhMyOpenAgentConfig } from "../config/schema"
|
||||||
|
|
||||||
export { McpNameSchema, type McpName } from "./types"
|
export { McpNameSchema, type McpName } from "./types"
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ type RemoteMcpConfig = {
|
|||||||
oauth?: false
|
oauth?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createBuiltinMcps(disabledMcps: string[] = [], config?: OhMyOpenCodeConfig) {
|
export function createBuiltinMcps(disabledMcps: string[] = [], config?: OhMyOpenAgentConfig) {
|
||||||
const mcps: Record<string, RemoteMcpConfig> = {}
|
const mcps: Record<string, RemoteMcpConfig> = {}
|
||||||
|
|
||||||
if (!disabledMcps.includes("websearch")) {
|
if (!disabledMcps.includes("websearch")) {
|
||||||
|
|||||||
+17
-51
@@ -1,6 +1,6 @@
|
|||||||
import { describe, expect, it } from "bun:test";
|
import { describe, expect, it } from "bun:test";
|
||||||
import { mergeConfigs, parseConfigPartially } from "./plugin-config";
|
import { mergeConfigs, parseConfigPartially } from "./plugin-config";
|
||||||
import { OhMyOpenCodeConfigSchema, type OhMyOpenCodeConfig } from "./config";
|
import type { OhMyOpenAgentConfig } from "./config";
|
||||||
|
|
||||||
describe("mergeConfigs", () => {
|
describe("mergeConfigs", () => {
|
||||||
describe("categories merging", () => {
|
describe("categories merging", () => {
|
||||||
@@ -19,7 +19,7 @@ describe("mergeConfigs", () => {
|
|||||||
model: "anthropic/claude-haiku-4-5",
|
model: "anthropic/claude-haiku-4-5",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as OhMyOpenCodeConfig;
|
} as OhMyOpenAgentConfig;
|
||||||
|
|
||||||
const override = {
|
const override = {
|
||||||
categories: {
|
categories: {
|
||||||
@@ -30,7 +30,7 @@ describe("mergeConfigs", () => {
|
|||||||
model: "google/gemini-3.1-pro",
|
model: "google/gemini-3.1-pro",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as unknown as OhMyOpenCodeConfig;
|
} as unknown as OhMyOpenAgentConfig;
|
||||||
|
|
||||||
const result = mergeConfigs(base, override);
|
const result = mergeConfigs(base, override);
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ describe("mergeConfigs", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should preserve base categories when override has no categories", () => {
|
it("should preserve base categories when override has no categories", () => {
|
||||||
const base: OhMyOpenCodeConfig = {
|
const base: OhMyOpenAgentConfig = {
|
||||||
categories: {
|
categories: {
|
||||||
general: {
|
general: {
|
||||||
model: "openai/gpt-5.4",
|
model: "openai/gpt-5.4",
|
||||||
@@ -53,7 +53,7 @@ describe("mergeConfigs", () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const override: OhMyOpenCodeConfig = {};
|
const override: OhMyOpenAgentConfig = {};
|
||||||
|
|
||||||
const result = mergeConfigs(base, override);
|
const result = mergeConfigs(base, override);
|
||||||
|
|
||||||
@@ -61,9 +61,9 @@ describe("mergeConfigs", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should use override categories when base has no categories", () => {
|
it("should use override categories when base has no categories", () => {
|
||||||
const base: OhMyOpenCodeConfig = {};
|
const base: OhMyOpenAgentConfig = {};
|
||||||
|
|
||||||
const override: OhMyOpenCodeConfig = {
|
const override: OhMyOpenAgentConfig = {
|
||||||
categories: {
|
categories: {
|
||||||
general: {
|
general: {
|
||||||
model: "openai/gpt-5.4",
|
model: "openai/gpt-5.4",
|
||||||
@@ -79,13 +79,13 @@ describe("mergeConfigs", () => {
|
|||||||
|
|
||||||
describe("existing behavior preservation", () => {
|
describe("existing behavior preservation", () => {
|
||||||
it("should deep merge agents", () => {
|
it("should deep merge agents", () => {
|
||||||
const base: OhMyOpenCodeConfig = {
|
const base: OhMyOpenAgentConfig = {
|
||||||
agents: {
|
agents: {
|
||||||
oracle: { model: "openai/gpt-5.4" },
|
oracle: { model: "openai/gpt-5.4" },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const override: OhMyOpenCodeConfig = {
|
const override: OhMyOpenAgentConfig = {
|
||||||
agents: {
|
agents: {
|
||||||
oracle: { temperature: 0.5 },
|
oracle: { temperature: 0.5 },
|
||||||
explore: { model: "anthropic/claude-haiku-4-5" },
|
explore: { model: "anthropic/claude-haiku-4-5" },
|
||||||
@@ -94,17 +94,17 @@ describe("mergeConfigs", () => {
|
|||||||
|
|
||||||
const result = mergeConfigs(base, override);
|
const result = mergeConfigs(base, override);
|
||||||
|
|
||||||
expect(result.agents?.oracle).toMatchObject({ model: "openai/gpt-5.4" });
|
expect(result.agents?.oracle?.model).toBe("openai/gpt-5.4");
|
||||||
expect(result.agents?.oracle?.temperature).toBe(0.5);
|
expect(result.agents?.oracle?.temperature).toBe(0.5);
|
||||||
expect(result.agents?.explore).toMatchObject({ model: "anthropic/claude-haiku-4-5" });
|
expect(result.agents?.explore?.model).toBe("anthropic/claude-haiku-4-5");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should merge disabled arrays without duplicates", () => {
|
it("should merge disabled arrays without duplicates", () => {
|
||||||
const base: OhMyOpenCodeConfig = {
|
const base: OhMyOpenAgentConfig = {
|
||||||
disabled_hooks: ["comment-checker", "think-mode"],
|
disabled_hooks: ["comment-checker", "think-mode"],
|
||||||
};
|
};
|
||||||
|
|
||||||
const override: OhMyOpenCodeConfig = {
|
const override: OhMyOpenAgentConfig = {
|
||||||
disabled_hooks: ["think-mode", "session-recovery"],
|
disabled_hooks: ["think-mode", "session-recovery"],
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -115,44 +115,10 @@ describe("mergeConfigs", () => {
|
|||||||
expect(result.disabled_hooks).toContain("session-recovery");
|
expect(result.disabled_hooks).toContain("session-recovery");
|
||||||
expect(result.disabled_hooks?.length).toBe(3);
|
expect(result.disabled_hooks?.length).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should union disabled_tools from base and override without duplicates", () => {
|
|
||||||
const base: OhMyOpenCodeConfig = {
|
|
||||||
disabled_tools: ["todowrite", "interactive_bash"],
|
|
||||||
};
|
|
||||||
|
|
||||||
const override: OhMyOpenCodeConfig = {
|
|
||||||
disabled_tools: ["interactive_bash", "look_at"],
|
|
||||||
};
|
|
||||||
|
|
||||||
const result = mergeConfigs(base, override);
|
|
||||||
|
|
||||||
expect(result.disabled_tools).toContain("todowrite");
|
|
||||||
expect(result.disabled_tools).toContain("interactive_bash");
|
|
||||||
expect(result.disabled_tools).toContain("look_at");
|
|
||||||
expect(result.disabled_tools?.length).toBe(3);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("parseConfigPartially", () => {
|
describe("parseConfigPartially", () => {
|
||||||
describe("disabled_hooks compatibility", () => {
|
|
||||||
//#given a config with a future hook name unknown to this version
|
|
||||||
//#when validating against the full config schema
|
|
||||||
//#then should accept the hook name so runtime and schema stay aligned
|
|
||||||
|
|
||||||
it("should accept unknown disabled_hooks values for forward compatibility", () => {
|
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse({
|
|
||||||
disabled_hooks: ["future-hook-name"],
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.success).toBe(true);
|
|
||||||
if (result.success) {
|
|
||||||
expect(result.data.disabled_hooks).toEqual(["future-hook-name"]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("fully valid config", () => {
|
describe("fully valid config", () => {
|
||||||
//#given a config where all sections are valid
|
//#given a config where all sections are valid
|
||||||
//#when parsing the config
|
//#when parsing the config
|
||||||
@@ -170,8 +136,8 @@ describe("parseConfigPartially", () => {
|
|||||||
const result = parseConfigPartially(rawConfig);
|
const result = parseConfigPartially(rawConfig);
|
||||||
|
|
||||||
expect(result).not.toBeNull();
|
expect(result).not.toBeNull();
|
||||||
expect(result!.agents?.oracle).toMatchObject({ model: "openai/gpt-5.4" });
|
expect(result!.agents?.oracle?.model).toBe("openai/gpt-5.4");
|
||||||
expect(result!.agents?.momus).toMatchObject({ model: "openai/gpt-5.4" });
|
expect(result!.agents?.momus?.model).toBe("openai/gpt-5.4");
|
||||||
expect(result!.disabled_hooks).toEqual(["comment-checker"]);
|
expect(result!.disabled_hooks).toEqual(["comment-checker"]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -213,7 +179,7 @@ describe("parseConfigPartially", () => {
|
|||||||
const result = parseConfigPartially(rawConfig);
|
const result = parseConfigPartially(rawConfig);
|
||||||
|
|
||||||
expect(result).not.toBeNull();
|
expect(result).not.toBeNull();
|
||||||
expect(result!.agents?.oracle).toMatchObject({ model: "openai/gpt-5.4" });
|
expect(result!.agents?.oracle?.model).toBe("openai/gpt-5.4");
|
||||||
expect(result!.disabled_hooks).toEqual(["not-a-real-hook"]);
|
expect(result!.disabled_hooks).toEqual(["not-a-real-hook"]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -266,7 +232,7 @@ describe("parseConfigPartially", () => {
|
|||||||
const result = parseConfigPartially(rawConfig);
|
const result = parseConfigPartially(rawConfig);
|
||||||
|
|
||||||
expect(result).not.toBeNull();
|
expect(result).not.toBeNull();
|
||||||
expect(result!.agents?.oracle).toMatchObject({ model: "openai/gpt-5.4" });
|
expect(result!.agents?.oracle?.model).toBe("openai/gpt-5.4");
|
||||||
expect((result as Record<string, unknown>)["some_future_key"]).toBeUndefined();
|
expect((result as Record<string, unknown>)["some_future_key"]).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+15
-14
@@ -1,6 +1,7 @@
|
|||||||
|
import { CONFIG_BASENAME } from "./shared/plugin-identity"
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import { OhMyOpenCodeConfigSchema, type OhMyOpenCodeConfig } from "./config";
|
import { OhMyOpenAgentConfigSchema, type OhMyOpenAgentConfig } from "./config";
|
||||||
import {
|
import {
|
||||||
log,
|
log,
|
||||||
deepMerge,
|
deepMerge,
|
||||||
@@ -22,8 +23,8 @@ const PARTIAL_STRING_ARRAY_KEYS = new Set([
|
|||||||
|
|
||||||
export function parseConfigPartially(
|
export function parseConfigPartially(
|
||||||
rawConfig: Record<string, unknown>
|
rawConfig: Record<string, unknown>
|
||||||
): OhMyOpenCodeConfig | null {
|
): OhMyOpenAgentConfig | null {
|
||||||
const fullResult = OhMyOpenCodeConfigSchema.safeParse(rawConfig);
|
const fullResult = OhMyOpenAgentConfigSchema.safeParse(rawConfig);
|
||||||
if (fullResult.success) {
|
if (fullResult.success) {
|
||||||
return fullResult.data;
|
return fullResult.data;
|
||||||
}
|
}
|
||||||
@@ -40,7 +41,7 @@ export function parseConfigPartially(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sectionResult = OhMyOpenCodeConfigSchema.safeParse({ [key]: rawConfig[key] });
|
const sectionResult = OhMyOpenAgentConfigSchema.safeParse({ [key]: rawConfig[key] });
|
||||||
if (sectionResult.success) {
|
if (sectionResult.success) {
|
||||||
const parsed = sectionResult.data as Record<string, unknown>;
|
const parsed = sectionResult.data as Record<string, unknown>;
|
||||||
if (parsed[key] !== undefined) {
|
if (parsed[key] !== undefined) {
|
||||||
@@ -61,13 +62,13 @@ export function parseConfigPartially(
|
|||||||
log("Partial config loaded — invalid sections skipped:", invalidSections);
|
log("Partial config loaded — invalid sections skipped:", invalidSections);
|
||||||
}
|
}
|
||||||
|
|
||||||
return partialConfig as OhMyOpenCodeConfig;
|
return partialConfig as OhMyOpenAgentConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadConfigFromPath(
|
export function loadConfigFromPath(
|
||||||
configPath: string,
|
configPath: string,
|
||||||
_ctx: unknown
|
_ctx: unknown
|
||||||
): OhMyOpenCodeConfig | null {
|
): OhMyOpenAgentConfig | null {
|
||||||
try {
|
try {
|
||||||
if (fs.existsSync(configPath)) {
|
if (fs.existsSync(configPath)) {
|
||||||
const content = fs.readFileSync(configPath, "utf-8");
|
const content = fs.readFileSync(configPath, "utf-8");
|
||||||
@@ -75,7 +76,7 @@ export function loadConfigFromPath(
|
|||||||
|
|
||||||
migrateConfigFile(configPath, rawConfig);
|
migrateConfigFile(configPath, rawConfig);
|
||||||
|
|
||||||
const result = OhMyOpenCodeConfigSchema.safeParse(rawConfig);
|
const result = OhMyOpenAgentConfigSchema.safeParse(rawConfig);
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
log(`Config loaded from ${configPath}`, { agents: result.data.agents });
|
log(`Config loaded from ${configPath}`, { agents: result.data.agents });
|
||||||
@@ -108,9 +109,9 @@ export function loadConfigFromPath(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function mergeConfigs(
|
export function mergeConfigs(
|
||||||
base: OhMyOpenCodeConfig,
|
base: OhMyOpenAgentConfig,
|
||||||
override: OhMyOpenCodeConfig
|
override: OhMyOpenAgentConfig
|
||||||
): OhMyOpenCodeConfig {
|
): OhMyOpenAgentConfig {
|
||||||
return {
|
return {
|
||||||
...base,
|
...base,
|
||||||
...override,
|
...override,
|
||||||
@@ -159,10 +160,10 @@ export function mergeConfigs(
|
|||||||
export function loadPluginConfig(
|
export function loadPluginConfig(
|
||||||
directory: string,
|
directory: string,
|
||||||
ctx: unknown
|
ctx: unknown
|
||||||
): OhMyOpenCodeConfig {
|
): OhMyOpenAgentConfig {
|
||||||
// User-level config path - prefer .jsonc over .json
|
// User-level config path - prefer .jsonc over .json
|
||||||
const configDir = getOpenCodeConfigDir({ binary: "opencode" });
|
const configDir = getOpenCodeConfigDir({ binary: "opencode" });
|
||||||
const userBasePath = path.join(configDir, "oh-my-opencode");
|
const userBasePath = path.join(configDir, CONFIG_BASENAME);
|
||||||
const userDetected = detectConfigFile(userBasePath);
|
const userDetected = detectConfigFile(userBasePath);
|
||||||
const userConfigPath =
|
const userConfigPath =
|
||||||
userDetected.format !== "none"
|
userDetected.format !== "none"
|
||||||
@@ -170,7 +171,7 @@ export function loadPluginConfig(
|
|||||||
: userBasePath + ".json";
|
: userBasePath + ".json";
|
||||||
|
|
||||||
// Project-level config path - prefer .jsonc over .json
|
// Project-level config path - prefer .jsonc over .json
|
||||||
const projectBasePath = path.join(directory, ".opencode", "oh-my-opencode");
|
const projectBasePath = path.join(directory, ".opencode", CONFIG_BASENAME);
|
||||||
const projectDetected = detectConfigFile(projectBasePath);
|
const projectDetected = detectConfigFile(projectBasePath);
|
||||||
const projectConfigPath =
|
const projectConfigPath =
|
||||||
projectDetected.format !== "none"
|
projectDetected.format !== "none"
|
||||||
@@ -178,7 +179,7 @@ export function loadPluginConfig(
|
|||||||
: projectBasePath + ".json";
|
: projectBasePath + ".json";
|
||||||
|
|
||||||
// Load user config first (base)
|
// Load user config first (base)
|
||||||
let config: OhMyOpenCodeConfig =
|
let config: OhMyOpenAgentConfig =
|
||||||
loadConfigFromPath(userConfigPath, ctx) ?? {};
|
loadConfigFromPath(userConfigPath, ctx) ?? {};
|
||||||
|
|
||||||
// Override with project config
|
// Override with project config
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test"
|
|||||||
import * as agents from "../agents"
|
import * as agents from "../agents"
|
||||||
import * as shared from "../shared"
|
import * as shared from "../shared"
|
||||||
import * as sisyphusJunior from "../agents/sisyphus-junior"
|
import * as sisyphusJunior from "../agents/sisyphus-junior"
|
||||||
import type { OhMyOpenCodeConfig } from "../config"
|
import type { OhMyOpenAgentConfig } from "../config"
|
||||||
import * as agentLoader from "../features/claude-code-agent-loader"
|
import * as agentLoader from "../features/claude-code-agent-loader"
|
||||||
import * as skillLoader from "../features/opencode-skill-loader"
|
import * as skillLoader from "../features/opencode-skill-loader"
|
||||||
import { getAgentDisplayName } from "../shared/agent-display-names"
|
import { getAgentDisplayName } from "../shared/agent-display-names"
|
||||||
@@ -35,13 +35,11 @@ function createBaseConfig(): Record<string, unknown> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createPluginConfig(): OhMyOpenCodeConfig {
|
function createPluginConfig(): OhMyOpenAgentConfig { return {
|
||||||
return {
|
sisyphus_agent: {
|
||||||
sisyphus_agent: {
|
planner_enabled: false,
|
||||||
planner_enabled: false,
|
},
|
||||||
},
|
} }
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("applyAgentConfig builtin override protection", () => {
|
describe("applyAgentConfig builtin override protection", () => {
|
||||||
let createBuiltinAgentsSpy: ReturnType<typeof spyOn>
|
let createBuiltinAgentsSpy: ReturnType<typeof spyOn>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createBuiltinAgents } from "../agents";
|
import { createBuiltinAgents } from "../agents";
|
||||||
import { createSisyphusJuniorAgentWithOverrides } from "../agents/sisyphus-junior";
|
import { createSisyphusJuniorAgentWithOverrides } from "../agents/sisyphus-junior";
|
||||||
import type { OhMyOpenCodeConfig } from "../config";
|
import type { OhMyOpenAgentConfig } from "../config";
|
||||||
import { log, migrateAgentConfig } from "../shared";
|
import { log, migrateAgentConfig } from "../shared";
|
||||||
import { AGENT_NAME_MAP } from "../shared/migration";
|
import { AGENT_NAME_MAP } from "../shared/migration";
|
||||||
import { getAgentDisplayName } from "../shared/agent-display-names";
|
import { getAgentDisplayName } from "../shared/agent-display-names";
|
||||||
@@ -37,7 +37,7 @@ function getConfiguredDefaultAgent(config: Record<string, unknown>): string | un
|
|||||||
|
|
||||||
export async function applyAgentConfig(params: {
|
export async function applyAgentConfig(params: {
|
||||||
config: Record<string, unknown>;
|
config: Record<string, unknown>;
|
||||||
pluginConfig: OhMyOpenCodeConfig;
|
pluginConfig: OhMyOpenAgentConfig;
|
||||||
ctx: { directory: string; client?: any };
|
ctx: { directory: string; client?: any };
|
||||||
pluginComponents: PluginComponents;
|
pluginComponents: PluginComponents;
|
||||||
}): Promise<Record<string, unknown>> {
|
}): Promise<Record<string, unknown>> {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { OhMyOpenCodeConfig } from "../config";
|
import type { OhMyOpenAgentConfig } from "../config";
|
||||||
import { getAgentDisplayName } from "../shared/agent-display-names";
|
import { getAgentDisplayName } from "../shared/agent-display-names";
|
||||||
import {
|
import {
|
||||||
loadUserCommands,
|
loadUserCommands,
|
||||||
@@ -19,7 +19,7 @@ import type { PluginComponents } from "./plugin-components-loader";
|
|||||||
|
|
||||||
export async function applyCommandConfig(params: {
|
export async function applyCommandConfig(params: {
|
||||||
config: Record<string, unknown>;
|
config: Record<string, unknown>;
|
||||||
pluginConfig: OhMyOpenCodeConfig;
|
pluginConfig: OhMyOpenAgentConfig;
|
||||||
ctx: { directory: string };
|
ctx: { directory: string };
|
||||||
pluginComponents: PluginComponents;
|
pluginComponents: PluginComponents;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test"
|
import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test"
|
||||||
|
|
||||||
import type { OhMyOpenCodeConfig } from "../config"
|
import type { OhMyOpenAgentConfig } from "../config"
|
||||||
import { createConfigHandler } from "./config-handler"
|
import { createConfigHandler } from "./config-handler"
|
||||||
import * as agentConfigHandler from "./agent-config-handler"
|
import * as agentConfigHandler from "./agent-config-handler"
|
||||||
import * as commandConfigHandler from "./command-config-handler"
|
import * as commandConfigHandler from "./command-config-handler"
|
||||||
@@ -62,7 +62,7 @@ afterEach(() => {
|
|||||||
describe("createConfigHandler formatter pass-through", () => {
|
describe("createConfigHandler formatter pass-through", () => {
|
||||||
test("preserves formatter object configured in opencode config", async () => {
|
test("preserves formatter object configured in opencode config", async () => {
|
||||||
// given
|
// given
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {}
|
const pluginConfig: OhMyOpenAgentConfig = {}
|
||||||
const formatterConfig = {
|
const formatterConfig = {
|
||||||
prettier: {
|
prettier: {
|
||||||
command: ["prettier", "--write"],
|
command: ["prettier", "--write"],
|
||||||
@@ -98,7 +98,7 @@ describe("createConfigHandler formatter pass-through", () => {
|
|||||||
|
|
||||||
test("preserves formatter=false configured in opencode config", async () => {
|
test("preserves formatter=false configured in opencode config", async () => {
|
||||||
// given
|
// given
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {}
|
const pluginConfig: OhMyOpenAgentConfig = {}
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
formatter: false,
|
formatter: false,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import { describe, test, expect, spyOn, beforeEach, afterEach } from "bun:test"
|
import { describe, test, expect, spyOn, beforeEach, afterEach } from "bun:test"
|
||||||
import { resolveCategoryConfig, createConfigHandler } from "./config-handler"
|
import { resolveCategoryConfig, createConfigHandler } from "./config-handler"
|
||||||
import type { CategoryConfig } from "../config/schema"
|
import type { CategoryConfig } from "../config/schema"
|
||||||
import type { OhMyOpenCodeConfig } from "../config"
|
import type { OhMyOpenAgentConfig } from "../config"
|
||||||
import { getAgentDisplayName } from "../shared/agent-display-names"
|
import { getAgentDisplayName } from "../shared/agent-display-names"
|
||||||
|
|
||||||
import * as agents from "../agents"
|
import * as agents from "../agents"
|
||||||
@@ -105,7 +105,7 @@ afterEach(() => {
|
|||||||
describe("Sisyphus-Junior model inheritance", () => {
|
describe("Sisyphus-Junior model inheritance", () => {
|
||||||
test("does not inherit UI-selected model as system default", async () => {
|
test("does not inherit UI-selected model as system default", async () => {
|
||||||
// #given
|
// #given
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {}
|
const pluginConfig: OhMyOpenAgentConfig = {}
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
model: "opencode/kimi-k2.5-free",
|
model: "opencode/kimi-k2.5-free",
|
||||||
agent: {},
|
agent: {},
|
||||||
@@ -131,7 +131,7 @@ describe("Sisyphus-Junior model inheritance", () => {
|
|||||||
|
|
||||||
test("uses explicitly configured sisyphus-junior model", async () => {
|
test("uses explicitly configured sisyphus-junior model", async () => {
|
||||||
// #given
|
// #given
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
agents: {
|
agents: {
|
||||||
"sisyphus-junior": {
|
"sisyphus-junior": {
|
||||||
model: "openai/gpt-5.3-codex",
|
model: "openai/gpt-5.3-codex",
|
||||||
@@ -174,7 +174,7 @@ describe("Plan agent demote behavior", () => {
|
|||||||
oracle: { name: "oracle", prompt: "test", mode: "subagent" },
|
oracle: { name: "oracle", prompt: "test", mode: "subagent" },
|
||||||
atlas: { name: "atlas", prompt: "test", mode: "primary" },
|
atlas: { name: "atlas", prompt: "test", mode: "primary" },
|
||||||
})
|
})
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
sisyphus_agent: {
|
sisyphus_agent: {
|
||||||
planner_enabled: true,
|
planner_enabled: true,
|
||||||
},
|
},
|
||||||
@@ -209,7 +209,7 @@ describe("Plan agent demote behavior", () => {
|
|||||||
|
|
||||||
test("plan agent should be demoted to subagent without inheriting prometheus prompt", async () => {
|
test("plan agent should be demoted to subagent without inheriting prometheus prompt", async () => {
|
||||||
// #given
|
// #given
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
sisyphus_agent: {
|
sisyphus_agent: {
|
||||||
planner_enabled: true,
|
planner_enabled: true,
|
||||||
replace_plan: true,
|
replace_plan: true,
|
||||||
@@ -247,7 +247,7 @@ describe("Plan agent demote behavior", () => {
|
|||||||
|
|
||||||
test("plan agent remains unchanged when planner is disabled", async () => {
|
test("plan agent remains unchanged when planner is disabled", async () => {
|
||||||
// #given
|
// #given
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
sisyphus_agent: {
|
sisyphus_agent: {
|
||||||
planner_enabled: false,
|
planner_enabled: false,
|
||||||
},
|
},
|
||||||
@@ -284,7 +284,7 @@ describe("Plan agent demote behavior", () => {
|
|||||||
|
|
||||||
test("prometheus should have mode 'all' to be callable via task", async () => {
|
test("prometheus should have mode 'all' to be callable via task", async () => {
|
||||||
// given
|
// given
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
sisyphus_agent: {
|
sisyphus_agent: {
|
||||||
planner_enabled: true,
|
planner_enabled: true,
|
||||||
},
|
},
|
||||||
@@ -324,7 +324,7 @@ describe("Agent permission defaults", () => {
|
|||||||
hephaestus: { name: "hephaestus", prompt: "test", mode: "primary" },
|
hephaestus: { name: "hephaestus", prompt: "test", mode: "primary" },
|
||||||
oracle: { name: "oracle", prompt: "test", mode: "subagent" },
|
oracle: { name: "oracle", prompt: "test", mode: "subagent" },
|
||||||
})
|
})
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {}
|
const pluginConfig: OhMyOpenAgentConfig = {}
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
model: "anthropic/claude-opus-4-6",
|
model: "anthropic/claude-opus-4-6",
|
||||||
agent: {},
|
agent: {},
|
||||||
@@ -352,7 +352,7 @@ describe("Agent permission defaults", () => {
|
|||||||
describe("default_agent behavior with Sisyphus orchestration", () => {
|
describe("default_agent behavior with Sisyphus orchestration", () => {
|
||||||
test("canonicalizes configured default_agent with surrounding whitespace", async () => {
|
test("canonicalizes configured default_agent with surrounding whitespace", async () => {
|
||||||
// given
|
// given
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {}
|
const pluginConfig: OhMyOpenAgentConfig = {}
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
model: "anthropic/claude-opus-4-6",
|
model: "anthropic/claude-opus-4-6",
|
||||||
default_agent: " hephaestus ",
|
default_agent: " hephaestus ",
|
||||||
@@ -376,7 +376,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => {
|
|||||||
|
|
||||||
test("canonicalizes configured default_agent when key uses mixed case", async () => {
|
test("canonicalizes configured default_agent when key uses mixed case", async () => {
|
||||||
// given
|
// given
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {}
|
const pluginConfig: OhMyOpenAgentConfig = {}
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
model: "anthropic/claude-opus-4-6",
|
model: "anthropic/claude-opus-4-6",
|
||||||
default_agent: "HePhAeStUs",
|
default_agent: "HePhAeStUs",
|
||||||
@@ -400,7 +400,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => {
|
|||||||
|
|
||||||
test("canonicalizes configured default_agent key to display name", async () => {
|
test("canonicalizes configured default_agent key to display name", async () => {
|
||||||
// #given
|
// #given
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {}
|
const pluginConfig: OhMyOpenAgentConfig = {}
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
model: "anthropic/claude-opus-4-6",
|
model: "anthropic/claude-opus-4-6",
|
||||||
default_agent: "hephaestus",
|
default_agent: "hephaestus",
|
||||||
@@ -424,7 +424,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => {
|
|||||||
|
|
||||||
test("preserves existing display-name default_agent", async () => {
|
test("preserves existing display-name default_agent", async () => {
|
||||||
// #given
|
// #given
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {}
|
const pluginConfig: OhMyOpenAgentConfig = {}
|
||||||
const displayName = getAgentDisplayName("hephaestus")
|
const displayName = getAgentDisplayName("hephaestus")
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
model: "anthropic/claude-opus-4-6",
|
model: "anthropic/claude-opus-4-6",
|
||||||
@@ -449,7 +449,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => {
|
|||||||
|
|
||||||
test("sets default_agent to sisyphus when missing", async () => {
|
test("sets default_agent to sisyphus when missing", async () => {
|
||||||
// #given
|
// #given
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {}
|
const pluginConfig: OhMyOpenAgentConfig = {}
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
model: "anthropic/claude-opus-4-6",
|
model: "anthropic/claude-opus-4-6",
|
||||||
agent: {},
|
agent: {},
|
||||||
@@ -472,7 +472,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => {
|
|||||||
|
|
||||||
test("sets default_agent to sisyphus when configured default_agent is empty after trim", async () => {
|
test("sets default_agent to sisyphus when configured default_agent is empty after trim", async () => {
|
||||||
// given
|
// given
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {}
|
const pluginConfig: OhMyOpenAgentConfig = {}
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
model: "anthropic/claude-opus-4-6",
|
model: "anthropic/claude-opus-4-6",
|
||||||
default_agent: " ",
|
default_agent: " ",
|
||||||
@@ -496,7 +496,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => {
|
|||||||
|
|
||||||
test("preserves custom default_agent names while trimming whitespace", async () => {
|
test("preserves custom default_agent names while trimming whitespace", async () => {
|
||||||
// given
|
// given
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {}
|
const pluginConfig: OhMyOpenAgentConfig = {}
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
model: "anthropic/claude-opus-4-6",
|
model: "anthropic/claude-opus-4-6",
|
||||||
default_agent: " Custom Agent ",
|
default_agent: " Custom Agent ",
|
||||||
@@ -520,7 +520,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => {
|
|||||||
|
|
||||||
test("does not normalize configured default_agent when Sisyphus is disabled", async () => {
|
test("does not normalize configured default_agent when Sisyphus is disabled", async () => {
|
||||||
// given
|
// given
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
sisyphus_agent: {
|
sisyphus_agent: {
|
||||||
disabled: true,
|
disabled: true,
|
||||||
},
|
},
|
||||||
@@ -650,7 +650,7 @@ describe("Prometheus category config resolution", () => {
|
|||||||
describe("Prometheus direct override priority over category", () => {
|
describe("Prometheus direct override priority over category", () => {
|
||||||
test("direct reasoningEffort takes priority over category reasoningEffort", async () => {
|
test("direct reasoningEffort takes priority over category reasoningEffort", async () => {
|
||||||
// given - category has reasoningEffort=xhigh, direct override says "low"
|
// given - category has reasoningEffort=xhigh, direct override says "low"
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
sisyphus_agent: {
|
sisyphus_agent: {
|
||||||
planner_enabled: true,
|
planner_enabled: true,
|
||||||
},
|
},
|
||||||
@@ -692,7 +692,7 @@ describe("Prometheus direct override priority over category", () => {
|
|||||||
|
|
||||||
test("category reasoningEffort applied when no direct override", async () => {
|
test("category reasoningEffort applied when no direct override", async () => {
|
||||||
// given - category has reasoningEffort but no direct override
|
// given - category has reasoningEffort but no direct override
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
sisyphus_agent: {
|
sisyphus_agent: {
|
||||||
planner_enabled: true,
|
planner_enabled: true,
|
||||||
},
|
},
|
||||||
@@ -733,7 +733,7 @@ describe("Prometheus direct override priority over category", () => {
|
|||||||
|
|
||||||
test("direct temperature takes priority over category temperature", async () => {
|
test("direct temperature takes priority over category temperature", async () => {
|
||||||
// given
|
// given
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
sisyphus_agent: {
|
sisyphus_agent: {
|
||||||
planner_enabled: true,
|
planner_enabled: true,
|
||||||
},
|
},
|
||||||
@@ -776,7 +776,7 @@ describe("Prometheus direct override priority over category", () => {
|
|||||||
test("prometheus prompt_append is appended to base prompt", async () => {
|
test("prometheus prompt_append is appended to base prompt", async () => {
|
||||||
// #given - prometheus override with prompt_append
|
// #given - prometheus override with prompt_append
|
||||||
const customInstructions = "## Custom Project Rules\nUse max 2 commits."
|
const customInstructions = "## Custom Project Rules\nUse max 2 commits."
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
sisyphus_agent: {
|
sisyphus_agent: {
|
||||||
planner_enabled: true,
|
planner_enabled: true,
|
||||||
},
|
},
|
||||||
@@ -820,7 +820,7 @@ describe("Plan agent model inheritance from prometheus", () => {
|
|||||||
provenance: "provider-fallback",
|
provenance: "provider-fallback",
|
||||||
variant: "max",
|
variant: "max",
|
||||||
})
|
})
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
sisyphus_agent: {
|
sisyphus_agent: {
|
||||||
planner_enabled: true,
|
planner_enabled: true,
|
||||||
replace_plan: true,
|
replace_plan: true,
|
||||||
@@ -864,7 +864,7 @@ describe("Plan agent model inheritance from prometheus", () => {
|
|||||||
provenance: "override",
|
provenance: "override",
|
||||||
variant: "high",
|
variant: "high",
|
||||||
})
|
})
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
sisyphus_agent: {
|
sisyphus_agent: {
|
||||||
planner_enabled: true,
|
planner_enabled: true,
|
||||||
replace_plan: true,
|
replace_plan: true,
|
||||||
@@ -919,7 +919,7 @@ describe("Plan agent model inheritance from prometheus", () => {
|
|||||||
provenance: "provider-fallback",
|
provenance: "provider-fallback",
|
||||||
variant: "max",
|
variant: "max",
|
||||||
})
|
})
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
sisyphus_agent: {
|
sisyphus_agent: {
|
||||||
planner_enabled: true,
|
planner_enabled: true,
|
||||||
replace_plan: true,
|
replace_plan: true,
|
||||||
@@ -962,7 +962,7 @@ describe("Plan agent model inheritance from prometheus", () => {
|
|||||||
provenance: "provider-fallback",
|
provenance: "provider-fallback",
|
||||||
variant: "max",
|
variant: "max",
|
||||||
})
|
})
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
sisyphus_agent: {
|
sisyphus_agent: {
|
||||||
planner_enabled: true,
|
planner_enabled: true,
|
||||||
replace_plan: true,
|
replace_plan: true,
|
||||||
@@ -1001,7 +1001,7 @@ describe("Deadlock prevention - fetchAvailableModels must not receive client", (
|
|||||||
// - Server waits for plugin init to complete before handling requests
|
// - Server waits for plugin init to complete before handling requests
|
||||||
const fetchSpy = spyOn(shared, "fetchAvailableModels" as any).mockResolvedValue(new Set<string>())
|
const fetchSpy = spyOn(shared, "fetchAvailableModels" as any).mockResolvedValue(new Set<string>())
|
||||||
|
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
sisyphus_agent: {
|
sisyphus_agent: {
|
||||||
planner_enabled: true,
|
planner_enabled: true,
|
||||||
},
|
},
|
||||||
@@ -1041,7 +1041,7 @@ describe("config-handler plugin loading error boundary (#1559)", () => {
|
|||||||
//#given
|
//#given
|
||||||
;(pluginLoader.loadAllPluginComponents as any).mockRestore?.()
|
;(pluginLoader.loadAllPluginComponents as any).mockRestore?.()
|
||||||
spyOn(pluginLoader, "loadAllPluginComponents" as any).mockRejectedValue(new Error("crash"))
|
spyOn(pluginLoader, "loadAllPluginComponents" as any).mockRejectedValue(new Error("crash"))
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {}
|
const pluginConfig: OhMyOpenAgentConfig = {}
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
model: "anthropic/claude-opus-4-6",
|
model: "anthropic/claude-opus-4-6",
|
||||||
agent: {},
|
agent: {},
|
||||||
@@ -1068,7 +1068,7 @@ describe("config-handler plugin loading error boundary (#1559)", () => {
|
|||||||
spyOn(pluginLoader, "loadAllPluginComponents" as any).mockImplementation(
|
spyOn(pluginLoader, "loadAllPluginComponents" as any).mockImplementation(
|
||||||
() => new Promise(() => {})
|
() => new Promise(() => {})
|
||||||
)
|
)
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
experimental: { plugin_load_timeout_ms: 100 },
|
experimental: { plugin_load_timeout_ms: 100 },
|
||||||
}
|
}
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
@@ -1096,7 +1096,7 @@ describe("config-handler plugin loading error boundary (#1559)", () => {
|
|||||||
;(pluginLoader.loadAllPluginComponents as any).mockRestore?.()
|
;(pluginLoader.loadAllPluginComponents as any).mockRestore?.()
|
||||||
spyOn(pluginLoader, "loadAllPluginComponents" as any).mockRejectedValue(new Error("crash"))
|
spyOn(pluginLoader, "loadAllPluginComponents" as any).mockRejectedValue(new Error("crash"))
|
||||||
const logSpy = shared.log as ReturnType<typeof spyOn>
|
const logSpy = shared.log as ReturnType<typeof spyOn>
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {}
|
const pluginConfig: OhMyOpenAgentConfig = {}
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
model: "anthropic/claude-opus-4-6",
|
model: "anthropic/claude-opus-4-6",
|
||||||
agent: {},
|
agent: {},
|
||||||
@@ -1133,7 +1133,7 @@ describe("config-handler plugin loading error boundary (#1559)", () => {
|
|||||||
plugins: [{ name: "test-plugin", version: "1.0.0" }],
|
plugins: [{ name: "test-plugin", version: "1.0.0" }],
|
||||||
errors: [],
|
errors: [],
|
||||||
})
|
})
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {}
|
const pluginConfig: OhMyOpenAgentConfig = {}
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
model: "anthropic/claude-opus-4-6",
|
model: "anthropic/claude-opus-4-6",
|
||||||
agent: {},
|
agent: {},
|
||||||
@@ -1179,7 +1179,7 @@ describe("per-agent todowrite/todoread deny when task_system enabled", () => {
|
|||||||
oracle: { name: "oracle", prompt: "test", mode: "subagent" },
|
oracle: { name: "oracle", prompt: "test", mode: "subagent" },
|
||||||
})
|
})
|
||||||
|
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
experimental: { task_system: true },
|
experimental: { task_system: true },
|
||||||
}
|
}
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
@@ -1216,7 +1216,7 @@ describe("per-agent todowrite/todoread deny when task_system enabled", () => {
|
|||||||
hephaestus: { name: "hephaestus", prompt: "test", mode: "primary" },
|
hephaestus: { name: "hephaestus", prompt: "test", mode: "primary" },
|
||||||
})
|
})
|
||||||
|
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
experimental: { task_system: false },
|
experimental: { task_system: false },
|
||||||
}
|
}
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
@@ -1252,7 +1252,7 @@ describe("per-agent todowrite/todoread deny when task_system enabled", () => {
|
|||||||
sisyphus: { name: "sisyphus", prompt: "test", mode: "primary" },
|
sisyphus: { name: "sisyphus", prompt: "test", mode: "primary" },
|
||||||
})
|
})
|
||||||
|
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {}
|
const pluginConfig: OhMyOpenAgentConfig = {}
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
model: "anthropic/claude-opus-4-6",
|
model: "anthropic/claude-opus-4-6",
|
||||||
agent: {},
|
agent: {},
|
||||||
@@ -1287,7 +1287,7 @@ describe("disable_omo_env pass-through", () => {
|
|||||||
sisyphus: { name: "sisyphus", prompt: "without-env", mode: "primary" },
|
sisyphus: { name: "sisyphus", prompt: "without-env", mode: "primary" },
|
||||||
})
|
})
|
||||||
|
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {
|
const pluginConfig: OhMyOpenAgentConfig = {
|
||||||
experimental: { disable_omo_env: true },
|
experimental: { disable_omo_env: true },
|
||||||
}
|
}
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
@@ -1323,7 +1323,7 @@ describe("disable_omo_env pass-through", () => {
|
|||||||
sisyphus: { name: "sisyphus", prompt: "with-env", mode: "primary" },
|
sisyphus: { name: "sisyphus", prompt: "with-env", mode: "primary" },
|
||||||
})
|
})
|
||||||
|
|
||||||
const pluginConfig: OhMyOpenCodeConfig = {}
|
const pluginConfig: OhMyOpenAgentConfig = {}
|
||||||
const config: Record<string, unknown> = {
|
const config: Record<string, unknown> = {
|
||||||
model: "anthropic/claude-opus-4-6",
|
model: "anthropic/claude-opus-4-6",
|
||||||
agent: {},
|
agent: {},
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { OhMyOpenCodeConfig } from "../config";
|
import type { OhMyOpenAgentConfig } from "../config";
|
||||||
import type { ModelCacheState } from "../plugin-state";
|
import type { ModelCacheState } from "../plugin-state";
|
||||||
import { log } from "../shared";
|
import { log } from "../shared";
|
||||||
import { applyAgentConfig } from "./agent-config-handler";
|
import { applyAgentConfig } from "./agent-config-handler";
|
||||||
@@ -12,7 +12,7 @@ export { resolveCategoryConfig } from "./category-config-resolver";
|
|||||||
|
|
||||||
export interface ConfigHandlerDeps {
|
export interface ConfigHandlerDeps {
|
||||||
ctx: { directory: string; client?: any };
|
ctx: { directory: string; client?: any };
|
||||||
pluginConfig: OhMyOpenCodeConfig;
|
pluginConfig: OhMyOpenAgentConfig;
|
||||||
modelCacheState: ModelCacheState;
|
modelCacheState: ModelCacheState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/// <reference types="bun-types" />
|
/// <reference types="bun-types" />
|
||||||
|
|
||||||
import { describe, test, expect, spyOn, beforeEach, afterEach } from "bun:test"
|
import { describe, test, expect, spyOn, beforeEach, afterEach } from "bun:test"
|
||||||
import type { OhMyOpenCodeConfig } from "../config"
|
import type { OhMyOpenAgentConfig } from "../config"
|
||||||
|
|
||||||
import * as mcpLoader from "../features/claude-code-mcp-loader"
|
import * as mcpLoader from "../features/claude-code-mcp-loader"
|
||||||
import * as mcpModule from "../mcp"
|
import * as mcpModule from "../mcp"
|
||||||
@@ -24,12 +24,10 @@ afterEach(() => {
|
|||||||
;(shared.log as any)?.mockRestore?.()
|
;(shared.log as any)?.mockRestore?.()
|
||||||
})
|
})
|
||||||
|
|
||||||
function createPluginConfig(overrides: Partial<OhMyOpenCodeConfig> = {}): OhMyOpenCodeConfig {
|
function createPluginConfig(overrides: Partial<OhMyOpenAgentConfig> = {}): OhMyOpenAgentConfig { return {
|
||||||
return {
|
disabled_mcps: [],
|
||||||
disabled_mcps: [],
|
...overrides,
|
||||||
...overrides,
|
} as OhMyOpenAgentConfig }
|
||||||
} as OhMyOpenCodeConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
const EMPTY_PLUGIN_COMPONENTS = {
|
const EMPTY_PLUGIN_COMPONENTS = {
|
||||||
commands: {},
|
commands: {},
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { OhMyOpenCodeConfig } from "../config";
|
import type { OhMyOpenAgentConfig } from "../config";
|
||||||
import { loadMcpConfigs } from "../features/claude-code-mcp-loader";
|
import { loadMcpConfigs } from "../features/claude-code-mcp-loader";
|
||||||
import { createBuiltinMcps } from "../mcp";
|
import { createBuiltinMcps } from "../mcp";
|
||||||
import type { PluginComponents } from "./plugin-components-loader";
|
import type { PluginComponents } from "./plugin-components-loader";
|
||||||
@@ -27,7 +27,7 @@ function captureUserDisabledMcps(
|
|||||||
|
|
||||||
export async function applyMcpConfig(params: {
|
export async function applyMcpConfig(params: {
|
||||||
config: Record<string, unknown>;
|
config: Record<string, unknown>;
|
||||||
pluginConfig: OhMyOpenCodeConfig;
|
pluginConfig: OhMyOpenAgentConfig;
|
||||||
pluginComponents: PluginComponents;
|
pluginComponents: PluginComponents;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
const disabledMcps = params.pluginConfig.disabled_mcps ?? [];
|
const disabledMcps = params.pluginConfig.disabled_mcps ?? [];
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { OhMyOpenCodeConfig } from "../config";
|
import type { OhMyOpenAgentConfig } from "../config";
|
||||||
import { loadAllPluginComponents } from "../features/claude-code-plugin-loader";
|
import { loadAllPluginComponents } from "../features/claude-code-plugin-loader";
|
||||||
import { addConfigLoadError, log } from "../shared";
|
import { addConfigLoadError, log } from "../shared";
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ const EMPTY_PLUGIN_COMPONENTS: PluginComponents = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export async function loadPluginComponents(params: {
|
export async function loadPluginComponents(params: {
|
||||||
pluginConfig: OhMyOpenCodeConfig;
|
pluginConfig: OhMyOpenAgentConfig;
|
||||||
}): Promise<PluginComponents> {
|
}): Promise<PluginComponents> {
|
||||||
const pluginsEnabled = params.pluginConfig.claude_code?.plugins ?? true;
|
const pluginsEnabled = params.pluginConfig.claude_code?.plugins ?? true;
|
||||||
if (!pluginsEnabled) {
|
if (!pluginsEnabled) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { describe, it, expect, beforeEach, afterEach } from "bun:test"
|
import { describe, it, expect, beforeEach, afterEach } from "bun:test"
|
||||||
import { applyToolConfig } from "./tool-config-handler"
|
import { applyToolConfig } from "./tool-config-handler"
|
||||||
import type { OhMyOpenCodeConfig } from "../config"
|
import type { OhMyOpenAgentConfig } from "../config"
|
||||||
|
|
||||||
function createParams(overrides: {
|
function createParams(overrides: {
|
||||||
taskSystem?: boolean
|
taskSystem?: boolean
|
||||||
@@ -15,7 +15,7 @@ function createParams(overrides: {
|
|||||||
config: { tools: {}, permission: {} } as Record<string, unknown>,
|
config: { tools: {}, permission: {} } as Record<string, unknown>,
|
||||||
pluginConfig: {
|
pluginConfig: {
|
||||||
experimental: { task_system: overrides.taskSystem ?? false },
|
experimental: { task_system: overrides.taskSystem ?? false },
|
||||||
} as OhMyOpenCodeConfig,
|
} as OhMyOpenAgentConfig,
|
||||||
agentResult: agentResult as Record<string, unknown>,
|
agentResult: agentResult as Record<string, unknown>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { OhMyOpenCodeConfig } from "../config";
|
import type { OhMyOpenAgentConfig } from "../config";
|
||||||
import { getAgentDisplayName } from "../shared/agent-display-names";
|
import { getAgentDisplayName } from "../shared/agent-display-names";
|
||||||
|
|
||||||
type AgentWithPermission = { permission?: Record<string, unknown> };
|
type AgentWithPermission = { permission?: Record<string, unknown> };
|
||||||
@@ -22,7 +22,7 @@ function agentByKey(agentResult: Record<string, unknown>, key: string): AgentWit
|
|||||||
|
|
||||||
export function applyToolConfig(params: {
|
export function applyToolConfig(params: {
|
||||||
config: Record<string, unknown>;
|
config: Record<string, unknown>;
|
||||||
pluginConfig: OhMyOpenCodeConfig;
|
pluginConfig: OhMyOpenAgentConfig;
|
||||||
agentResult: Record<string, unknown>;
|
agentResult: Record<string, unknown>;
|
||||||
}): void {
|
}): void {
|
||||||
const denyTodoTools = params.pluginConfig.experimental?.task_system
|
const denyTodoTools = params.pluginConfig.experimental?.task_system
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { PluginContext, PluginInterface, ToolsRecord } from "./plugin/types"
|
import type { PluginContext, PluginInterface, ToolsRecord } from "./plugin/types"
|
||||||
import type { OhMyOpenCodeConfig } from "./config"
|
import type { OhMyOpenAgentConfig } from "./config"
|
||||||
|
|
||||||
import { createChatParamsHandler } from "./plugin/chat-params"
|
import { createChatParamsHandler } from "./plugin/chat-params"
|
||||||
import { createChatHeadersHandler } from "./plugin/chat-headers"
|
import { createChatHeadersHandler } from "./plugin/chat-headers"
|
||||||
@@ -15,7 +15,7 @@ import type { Managers } from "./create-managers"
|
|||||||
|
|
||||||
export function createPluginInterface(args: {
|
export function createPluginInterface(args: {
|
||||||
ctx: PluginContext
|
ctx: PluginContext
|
||||||
pluginConfig: OhMyOpenCodeConfig
|
pluginConfig: OhMyOpenAgentConfig
|
||||||
firstMessageVariantGate: {
|
firstMessageVariantGate: {
|
||||||
shouldOverride: (sessionID: string) => boolean
|
shouldOverride: (sessionID: string) => boolean
|
||||||
markApplied: (sessionID: string) => void
|
markApplied: (sessionID: string) => void
|
||||||
|
|||||||
@@ -1,24 +1,20 @@
|
|||||||
import type { AvailableCategory } from "../agents/dynamic-agent-prompt-builder"
|
import type { AvailableCategory } from "../agents/dynamic-agent-prompt-builder"
|
||||||
import type { OhMyOpenCodeConfig } from "../config"
|
import type { OhMyOpenAgentConfig } from "../config"
|
||||||
import { CATEGORY_DESCRIPTIONS } from "../tools/delegate-task/constants"
|
import { CATEGORY_DESCRIPTIONS } from "../tools/delegate-task/constants"
|
||||||
import { mergeCategories } from "../shared/merge-categories"
|
import { mergeCategories } from "../shared/merge-categories"
|
||||||
|
|
||||||
export function createAvailableCategories(
|
export function createAvailableCategories(pluginConfig: OhMyOpenAgentConfig): AvailableCategory[] { const categories = mergeCategories(pluginConfig.categories)
|
||||||
pluginConfig: OhMyOpenCodeConfig,
|
|
||||||
): AvailableCategory[] {
|
|
||||||
const categories = mergeCategories(pluginConfig.categories)
|
|
||||||
|
|
||||||
return Object.entries(categories).map(([name, categoryConfig]) => {
|
return Object.entries(categories).map(([name, categoryConfig]) => {
|
||||||
const model =
|
const model =
|
||||||
typeof categoryConfig.model === "string" ? categoryConfig.model : undefined
|
typeof categoryConfig.model === "string" ? categoryConfig.model : undefined
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
description:
|
description:
|
||||||
pluginConfig.categories?.[name]?.description ??
|
pluginConfig.categories?.[name]?.description ??
|
||||||
CATEGORY_DESCRIPTIONS[name] ??
|
CATEGORY_DESCRIPTIONS[name] ??
|
||||||
"General tasks",
|
"General tasks",
|
||||||
model,
|
model,
|
||||||
}
|
}
|
||||||
})
|
}) }
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { OhMyOpenCodeConfig } from "../config"
|
import type { OhMyOpenAgentConfig } from "../config"
|
||||||
import type { PluginContext } from "./types"
|
import type { PluginContext } from "./types"
|
||||||
|
|
||||||
import { hasConnectedProvidersCache } from "../shared"
|
import { hasConnectedProvidersCache } from "../shared"
|
||||||
@@ -37,7 +37,7 @@ function isStartWorkHookOutput(value: unknown): value is StartWorkHookOutput {
|
|||||||
|
|
||||||
export function createChatMessageHandler(args: {
|
export function createChatMessageHandler(args: {
|
||||||
ctx: PluginContext
|
ctx: PluginContext
|
||||||
pluginConfig: OhMyOpenCodeConfig
|
pluginConfig: OhMyOpenAgentConfig
|
||||||
firstMessageVariantGate: FirstMessageVariantGate
|
firstMessageVariantGate: FirstMessageVariantGate
|
||||||
hooks: CreatedHooks
|
hooks: CreatedHooks
|
||||||
}): (
|
}): (
|
||||||
|
|||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
import type { OhMyOpenCodeConfig } from "../config";
|
import type { OhMyOpenAgentConfig } from "../config";
|
||||||
import type { PluginContext } from "./types";
|
import type { PluginContext } from "./types";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -107,7 +107,7 @@ function applyUserConfiguredFallbackChain(
|
|||||||
sessionID: string,
|
sessionID: string,
|
||||||
agentName: string,
|
agentName: string,
|
||||||
currentProviderID: string,
|
currentProviderID: string,
|
||||||
pluginConfig: OhMyOpenCodeConfig,
|
pluginConfig: OhMyOpenAgentConfig,
|
||||||
): void {
|
): void {
|
||||||
const agentKey = getAgentConfigKey(agentName);
|
const agentKey = getAgentConfigKey(agentName);
|
||||||
const configuredFallbackModels = getFallbackModelsForSession(sessionID, agentKey, pluginConfig);
|
const configuredFallbackModels = getFallbackModelsForSession(sessionID, agentKey, pluginConfig);
|
||||||
@@ -127,7 +127,7 @@ function isCompactionAgent(agent: string): boolean {
|
|||||||
type EventInput = Parameters<NonNullable<NonNullable<CreatedHooks["writeExistingFileGuard"]>["event"]>>[0];
|
type EventInput = Parameters<NonNullable<NonNullable<CreatedHooks["writeExistingFileGuard"]>["event"]>>[0];
|
||||||
export function createEventHandler(args: {
|
export function createEventHandler(args: {
|
||||||
ctx: PluginContext;
|
ctx: PluginContext;
|
||||||
pluginConfig: OhMyOpenCodeConfig;
|
pluginConfig: OhMyOpenAgentConfig;
|
||||||
firstMessageVariantGate: FirstMessageVariantGate;
|
firstMessageVariantGate: FirstMessageVariantGate;
|
||||||
managers: Managers;
|
managers: Managers;
|
||||||
hooks: CreatedHooks;
|
hooks: CreatedHooks;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { HookName, OhMyOpenCodeConfig } from "../../config"
|
import type { HookName, OhMyOpenAgentConfig } from "../../config"
|
||||||
import type { BackgroundManager } from "../../features/background-agent"
|
import type { BackgroundManager } from "../../features/background-agent"
|
||||||
import type { PluginContext } from "../types"
|
import type { PluginContext } from "../types"
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ type SessionRecovery = {
|
|||||||
|
|
||||||
export function createContinuationHooks(args: {
|
export function createContinuationHooks(args: {
|
||||||
ctx: PluginContext
|
ctx: PluginContext
|
||||||
pluginConfig: OhMyOpenCodeConfig
|
pluginConfig: OhMyOpenAgentConfig
|
||||||
isHookEnabled: (hookName: HookName) => boolean
|
isHookEnabled: (hookName: HookName) => boolean
|
||||||
safeHookEnabled: boolean
|
safeHookEnabled: boolean
|
||||||
backgroundManager: BackgroundManager
|
backgroundManager: BackgroundManager
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { HookName, OhMyOpenCodeConfig } from "../../config"
|
import type { HookName, OhMyOpenAgentConfig } from "../../config"
|
||||||
import type { PluginContext } from "../types"
|
import type { PluginContext } from "../types"
|
||||||
import type { ModelCacheState } from "../../plugin-state"
|
import type { ModelCacheState } from "../../plugin-state"
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ import { createTransformHooks } from "./create-transform-hooks"
|
|||||||
|
|
||||||
export function createCoreHooks(args: {
|
export function createCoreHooks(args: {
|
||||||
ctx: PluginContext
|
ctx: PluginContext
|
||||||
pluginConfig: OhMyOpenCodeConfig
|
pluginConfig: OhMyOpenAgentConfig
|
||||||
modelCacheState: ModelCacheState
|
modelCacheState: ModelCacheState
|
||||||
isHookEnabled: (hookName: HookName) => boolean
|
isHookEnabled: (hookName: HookName) => boolean
|
||||||
safeHookEnabled: boolean
|
safeHookEnabled: boolean
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { OhMyOpenCodeConfig, HookName } from "../../config"
|
import type { OhMyOpenAgentConfig, HookName } from "../../config"
|
||||||
import type { ModelCacheState } from "../../plugin-state"
|
import type { ModelCacheState } from "../../plugin-state"
|
||||||
import type { PluginContext } from "../types"
|
import type { PluginContext } from "../types"
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ export type SessionHooks = {
|
|||||||
|
|
||||||
export function createSessionHooks(args: {
|
export function createSessionHooks(args: {
|
||||||
ctx: PluginContext
|
ctx: PluginContext
|
||||||
pluginConfig: OhMyOpenCodeConfig
|
pluginConfig: OhMyOpenAgentConfig
|
||||||
modelCacheState: ModelCacheState
|
modelCacheState: ModelCacheState
|
||||||
isHookEnabled: (hookName: HookName) => boolean
|
isHookEnabled: (hookName: HookName) => boolean
|
||||||
safeHookEnabled: boolean
|
safeHookEnabled: boolean
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { AvailableSkill } from "../../agents/dynamic-agent-prompt-builder"
|
import type { AvailableSkill } from "../../agents/dynamic-agent-prompt-builder"
|
||||||
import type { HookName, OhMyOpenCodeConfig } from "../../config"
|
import type { HookName, OhMyOpenAgentConfig } from "../../config"
|
||||||
import type { LoadedSkill } from "../../features/opencode-skill-loader/types"
|
import type { LoadedSkill } from "../../features/opencode-skill-loader/types"
|
||||||
import type { PluginContext } from "../types"
|
import type { PluginContext } from "../types"
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ export type SkillHooks = {
|
|||||||
|
|
||||||
export function createSkillHooks(args: {
|
export function createSkillHooks(args: {
|
||||||
ctx: PluginContext
|
ctx: PluginContext
|
||||||
pluginConfig: OhMyOpenCodeConfig
|
pluginConfig: OhMyOpenAgentConfig
|
||||||
isHookEnabled: (hookName: HookName) => boolean
|
isHookEnabled: (hookName: HookName) => boolean
|
||||||
safeHookEnabled: boolean
|
safeHookEnabled: boolean
|
||||||
mergedSkills: LoadedSkill[]
|
mergedSkills: LoadedSkill[]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { HookName, OhMyOpenCodeConfig } from "../../config"
|
import type { HookName, OhMyOpenAgentConfig } from "../../config"
|
||||||
import type { ModelCacheState } from "../../plugin-state"
|
import type { ModelCacheState } from "../../plugin-state"
|
||||||
import type { PluginContext } from "../types"
|
import type { PluginContext } from "../types"
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ export type ToolGuardHooks = {
|
|||||||
|
|
||||||
export function createToolGuardHooks(args: {
|
export function createToolGuardHooks(args: {
|
||||||
ctx: PluginContext
|
ctx: PluginContext
|
||||||
pluginConfig: OhMyOpenCodeConfig
|
pluginConfig: OhMyOpenAgentConfig
|
||||||
modelCacheState: ModelCacheState
|
modelCacheState: ModelCacheState
|
||||||
isHookEnabled: (hookName: HookName) => boolean
|
isHookEnabled: (hookName: HookName) => boolean
|
||||||
safeHookEnabled: boolean
|
safeHookEnabled: boolean
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { OhMyOpenCodeConfig } from "../../config"
|
import type { OhMyOpenAgentConfig } from "../../config"
|
||||||
import type { PluginContext } from "../types"
|
import type { PluginContext } from "../types"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -21,7 +21,7 @@ export type TransformHooks = {
|
|||||||
|
|
||||||
export function createTransformHooks(args: {
|
export function createTransformHooks(args: {
|
||||||
ctx: PluginContext
|
ctx: PluginContext
|
||||||
pluginConfig: OhMyOpenCodeConfig
|
pluginConfig: OhMyOpenAgentConfig
|
||||||
isHookEnabled: (hookName: string) => boolean
|
isHookEnabled: (hookName: string) => boolean
|
||||||
safeHookEnabled?: boolean
|
safeHookEnabled?: boolean
|
||||||
}): TransformHooks {
|
}): TransformHooks {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { mkdirSync, rmSync, writeFileSync } from "node:fs"
|
|||||||
import { tmpdir } from "node:os"
|
import { tmpdir } from "node:os"
|
||||||
import { join } from "node:path"
|
import { join } from "node:path"
|
||||||
|
|
||||||
import { OhMyOpenCodeConfigSchema } from "../config"
|
import { OhMyOpenAgentConfigSchema } from "../config"
|
||||||
import * as mcpLoader from "../features/claude-code-mcp-loader"
|
import * as mcpLoader from "../features/claude-code-mcp-loader"
|
||||||
import * as skillLoader from "../features/opencode-skill-loader"
|
import * as skillLoader from "../features/opencode-skill-loader"
|
||||||
import { createSkillContext } from "./skill-context"
|
import { createSkillContext } from "./skill-context"
|
||||||
@@ -60,7 +60,7 @@ describe("createSkillContext", () => {
|
|||||||
"getSystemMcpServerNames",
|
"getSystemMcpServerNames",
|
||||||
).mockReturnValue(new Set<string>())
|
).mockReturnValue(new Set<string>())
|
||||||
|
|
||||||
const pluginConfig = OhMyOpenCodeConfigSchema.parse({
|
const pluginConfig = OhMyOpenAgentConfigSchema.parse({
|
||||||
browser_automation_engine: { provider: "agent-browser" },
|
browser_automation_engine: { provider: "agent-browser" },
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { AvailableSkill } from "../agents/dynamic-agent-prompt-builder"
|
import type { AvailableSkill } from "../agents/dynamic-agent-prompt-builder"
|
||||||
import type { OhMyOpenCodeConfig } from "../config"
|
import type { OhMyOpenAgentConfig } from "../config"
|
||||||
import type { BrowserAutomationProvider } from "../config/schema/browser-automation"
|
import type { BrowserAutomationProvider } from "../config/schema/browser-automation"
|
||||||
import type {
|
import type {
|
||||||
LoadedSkill,
|
LoadedSkill,
|
||||||
@@ -49,7 +49,7 @@ function filterProviderGatedSkills(
|
|||||||
|
|
||||||
export async function createSkillContext(args: {
|
export async function createSkillContext(args: {
|
||||||
directory: string
|
directory: string
|
||||||
pluginConfig: OhMyOpenCodeConfig
|
pluginConfig: OhMyOpenAgentConfig
|
||||||
}): Promise<SkillContext> {
|
}): Promise<SkillContext> {
|
||||||
const { directory, pluginConfig } = args
|
const { directory, pluginConfig } = args
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { ToolDefinition } from "@opencode-ai/plugin"
|
|||||||
import type {
|
import type {
|
||||||
AvailableCategory,
|
AvailableCategory,
|
||||||
} from "../agents/dynamic-agent-prompt-builder"
|
} from "../agents/dynamic-agent-prompt-builder"
|
||||||
import type { OhMyOpenCodeConfig } from "../config"
|
import type { OhMyOpenAgentConfig } from "../config"
|
||||||
import type { PluginContext, ToolsRecord } from "./types"
|
import type { PluginContext, ToolsRecord } from "./types"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -41,7 +41,7 @@ export type ToolRegistryResult = {
|
|||||||
|
|
||||||
export function createToolRegistry(args: {
|
export function createToolRegistry(args: {
|
||||||
ctx: PluginContext
|
ctx: PluginContext
|
||||||
pluginConfig: OhMyOpenCodeConfig
|
pluginConfig: OhMyOpenAgentConfig
|
||||||
managers: Pick<Managers, "backgroundManager" | "tmuxSessionManager" | "skillMcpManager">
|
managers: Pick<Managers, "backgroundManager" | "tmuxSessionManager" | "skillMcpManager">
|
||||||
skillContext: SkillContext
|
skillContext: SkillContext
|
||||||
availableCategories: AvailableCategory[]
|
availableCategories: AvailableCategory[]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { OhMyOpenCodeConfig } from "../config"
|
import type { OhMyOpenAgentConfig } from "../config"
|
||||||
import type { AgentOverrides } from "../config/schema/agent-overrides"
|
import type { AgentOverrides } from "../config/schema/agent-overrides"
|
||||||
import { getSessionAgent } from "../features/claude-code-session-state"
|
import { getSessionAgent } from "../features/claude-code-session-state"
|
||||||
import { log } from "../shared"
|
import { log } from "../shared"
|
||||||
@@ -58,7 +58,7 @@ function getMessageModel(current: unknown): ModelDescriptor | undefined {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function resolveUltraworkOverride(
|
export function resolveUltraworkOverride(
|
||||||
pluginConfig: OhMyOpenCodeConfig,
|
pluginConfig: OhMyOpenAgentConfig,
|
||||||
inputAgentName: string | undefined,
|
inputAgentName: string | undefined,
|
||||||
output: {
|
output: {
|
||||||
message: Record<string, unknown>
|
message: Record<string, unknown>
|
||||||
@@ -146,7 +146,7 @@ function applyResolvedUltraworkOverride(args: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function applyUltraworkModelOverrideOnMessage(
|
export function applyUltraworkModelOverrideOnMessage(
|
||||||
pluginConfig: OhMyOpenCodeConfig,
|
pluginConfig: OhMyOpenAgentConfig,
|
||||||
inputAgentName: string | undefined,
|
inputAgentName: string | undefined,
|
||||||
output: {
|
output: {
|
||||||
message: Record<string, unknown>
|
message: Record<string, unknown>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { OhMyOpenCodeConfig } from "../config"
|
import type { OhMyOpenAgentConfig } from "../config"
|
||||||
import type { PluginContext } from "./types"
|
import type { PluginContext } from "./types"
|
||||||
|
|
||||||
import { createUnstableAgentBabysitterHook } from "../hooks"
|
import { createUnstableAgentBabysitterHook } from "../hooks"
|
||||||
@@ -7,7 +7,7 @@ import type { BackgroundManager } from "../features/background-agent"
|
|||||||
export function createUnstableAgentBabysitter(args: {
|
export function createUnstableAgentBabysitter(args: {
|
||||||
ctx: PluginContext
|
ctx: PluginContext
|
||||||
backgroundManager: BackgroundManager
|
backgroundManager: BackgroundManager
|
||||||
pluginConfig: OhMyOpenCodeConfig
|
pluginConfig: OhMyOpenAgentConfig
|
||||||
}) {
|
}) {
|
||||||
const { ctx, backgroundManager, pluginConfig } = args
|
const { ctx, backgroundManager, pluginConfig } = args
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import type { OhMyOpenCodeConfig } from "../config"
|
import type { OhMyOpenAgentConfig } from "../config"
|
||||||
import { applyAgentVariant, resolveAgentVariant, resolveVariantForModel } from "./agent-variant"
|
import { applyAgentVariant, resolveAgentVariant, resolveVariantForModel } from "./agent-variant"
|
||||||
|
|
||||||
describe("resolveAgentVariant", () => {
|
describe("resolveAgentVariant", () => {
|
||||||
test("returns undefined when agent name missing", () => {
|
test("returns undefined when agent name missing", () => {
|
||||||
// given
|
// given
|
||||||
const config = {} as OhMyOpenCodeConfig
|
const config = {} as OhMyOpenAgentConfig
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const variant = resolveAgentVariant(config)
|
const variant = resolveAgentVariant(config)
|
||||||
@@ -20,7 +20,7 @@ describe("resolveAgentVariant", () => {
|
|||||||
agents: {
|
agents: {
|
||||||
sisyphus: { variant: "low" },
|
sisyphus: { variant: "low" },
|
||||||
},
|
},
|
||||||
} as OhMyOpenCodeConfig
|
} as OhMyOpenAgentConfig
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const variant = resolveAgentVariant(config, "sisyphus")
|
const variant = resolveAgentVariant(config, "sisyphus")
|
||||||
@@ -38,7 +38,7 @@ describe("resolveAgentVariant", () => {
|
|||||||
categories: {
|
categories: {
|
||||||
ultrabrain: { model: "openai/gpt-5.4", variant: "xhigh" },
|
ultrabrain: { model: "openai/gpt-5.4", variant: "xhigh" },
|
||||||
},
|
},
|
||||||
} as OhMyOpenCodeConfig
|
} as OhMyOpenAgentConfig
|
||||||
|
|
||||||
// when
|
// when
|
||||||
const variant = resolveAgentVariant(config, "sisyphus")
|
const variant = resolveAgentVariant(config, "sisyphus")
|
||||||
@@ -55,7 +55,7 @@ describe("applyAgentVariant", () => {
|
|||||||
agents: {
|
agents: {
|
||||||
sisyphus: { variant: "low" },
|
sisyphus: { variant: "low" },
|
||||||
},
|
},
|
||||||
} as OhMyOpenCodeConfig
|
} as OhMyOpenAgentConfig
|
||||||
const message: { variant?: string } = {}
|
const message: { variant?: string } = {}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -71,7 +71,7 @@ describe("applyAgentVariant", () => {
|
|||||||
agents: {
|
agents: {
|
||||||
sisyphus: { variant: "low" },
|
sisyphus: { variant: "low" },
|
||||||
},
|
},
|
||||||
} as OhMyOpenCodeConfig
|
} as OhMyOpenAgentConfig
|
||||||
const message = { variant: "max" }
|
const message = { variant: "max" }
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -90,7 +90,7 @@ describe("resolveVariantForModel", () => {
|
|||||||
agents: {
|
agents: {
|
||||||
sisyphus: { variant: "high" },
|
sisyphus: { variant: "high" },
|
||||||
},
|
},
|
||||||
} as OhMyOpenCodeConfig
|
} as OhMyOpenAgentConfig
|
||||||
const model = { providerID: "anthropic", modelID: "claude-opus-4-6" }
|
const model = { providerID: "anthropic", modelID: "claude-opus-4-6" }
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -102,7 +102,7 @@ describe("resolveVariantForModel", () => {
|
|||||||
|
|
||||||
test("returns correct variant for anthropic provider", () => {
|
test("returns correct variant for anthropic provider", () => {
|
||||||
// given
|
// given
|
||||||
const config = {} as OhMyOpenCodeConfig
|
const config = {} as OhMyOpenAgentConfig
|
||||||
const model = { providerID: "anthropic", modelID: "claude-opus-4-6" }
|
const model = { providerID: "anthropic", modelID: "claude-opus-4-6" }
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -114,7 +114,7 @@ describe("resolveVariantForModel", () => {
|
|||||||
|
|
||||||
test("returns correct variant for openai provider (hephaestus agent)", () => {
|
test("returns correct variant for openai provider (hephaestus agent)", () => {
|
||||||
// #given hephaestus has openai/gpt-5.3-codex with variant "medium" in its chain
|
// #given hephaestus has openai/gpt-5.3-codex with variant "medium" in its chain
|
||||||
const config = {} as OhMyOpenCodeConfig
|
const config = {} as OhMyOpenAgentConfig
|
||||||
const model = { providerID: "openai", modelID: "gpt-5.3-codex" }
|
const model = { providerID: "openai", modelID: "gpt-5.3-codex" }
|
||||||
|
|
||||||
// #when
|
// #when
|
||||||
@@ -126,7 +126,7 @@ describe("resolveVariantForModel", () => {
|
|||||||
|
|
||||||
test("returns medium for openai/gpt-5.4 in sisyphus chain", () => {
|
test("returns medium for openai/gpt-5.4 in sisyphus chain", () => {
|
||||||
// #given openai/gpt-5.4 is now in sisyphus fallback chain with variant medium
|
// #given openai/gpt-5.4 is now in sisyphus fallback chain with variant medium
|
||||||
const config = {} as OhMyOpenCodeConfig
|
const config = {} as OhMyOpenAgentConfig
|
||||||
const model = { providerID: "openai", modelID: "gpt-5.4" }
|
const model = { providerID: "openai", modelID: "gpt-5.4" }
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -138,7 +138,7 @@ describe("resolveVariantForModel", () => {
|
|||||||
|
|
||||||
test("returns undefined for provider not in chain", () => {
|
test("returns undefined for provider not in chain", () => {
|
||||||
// given
|
// given
|
||||||
const config = {} as OhMyOpenCodeConfig
|
const config = {} as OhMyOpenAgentConfig
|
||||||
const model = { providerID: "unknown-provider", modelID: "some-model" }
|
const model = { providerID: "unknown-provider", modelID: "some-model" }
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -150,7 +150,7 @@ describe("resolveVariantForModel", () => {
|
|||||||
|
|
||||||
test("returns undefined for unknown agent", () => {
|
test("returns undefined for unknown agent", () => {
|
||||||
// given
|
// given
|
||||||
const config = {} as OhMyOpenCodeConfig
|
const config = {} as OhMyOpenAgentConfig
|
||||||
const model = { providerID: "anthropic", modelID: "claude-opus-4-6" }
|
const model = { providerID: "anthropic", modelID: "claude-opus-4-6" }
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -162,7 +162,7 @@ describe("resolveVariantForModel", () => {
|
|||||||
|
|
||||||
test("returns variant for zai-coding-plan provider without variant", () => {
|
test("returns variant for zai-coding-plan provider without variant", () => {
|
||||||
// given
|
// given
|
||||||
const config = {} as OhMyOpenCodeConfig
|
const config = {} as OhMyOpenAgentConfig
|
||||||
const model = { providerID: "zai-coding-plan", modelID: "glm-5" }
|
const model = { providerID: "zai-coding-plan", modelID: "glm-5" }
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -178,7 +178,7 @@ describe("resolveVariantForModel", () => {
|
|||||||
agents: {
|
agents: {
|
||||||
"custom-agent": { category: "ultrabrain" },
|
"custom-agent": { category: "ultrabrain" },
|
||||||
},
|
},
|
||||||
} as OhMyOpenCodeConfig
|
} as OhMyOpenAgentConfig
|
||||||
const model = { providerID: "openai", modelID: "gpt-5.4" }
|
const model = { providerID: "openai", modelID: "gpt-5.4" }
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -190,7 +190,7 @@ describe("resolveVariantForModel", () => {
|
|||||||
|
|
||||||
test("returns correct variant for oracle agent with openai", () => {
|
test("returns correct variant for oracle agent with openai", () => {
|
||||||
// given
|
// given
|
||||||
const config = {} as OhMyOpenCodeConfig
|
const config = {} as OhMyOpenAgentConfig
|
||||||
const model = { providerID: "openai", modelID: "gpt-5.4" }
|
const model = { providerID: "openai", modelID: "gpt-5.4" }
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -202,7 +202,7 @@ describe("resolveVariantForModel", () => {
|
|||||||
|
|
||||||
test("returns correct variant for oracle agent with anthropic", () => {
|
test("returns correct variant for oracle agent with anthropic", () => {
|
||||||
// given
|
// given
|
||||||
const config = {} as OhMyOpenCodeConfig
|
const config = {} as OhMyOpenAgentConfig
|
||||||
const model = { providerID: "anthropic", modelID: "claude-opus-4-6" }
|
const model = { providerID: "anthropic", modelID: "claude-opus-4-6" }
|
||||||
|
|
||||||
// when
|
// when
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { OhMyOpenCodeConfig } from "../config"
|
import type { OhMyOpenAgentConfig } from "../config"
|
||||||
import { AGENT_MODEL_REQUIREMENTS, CATEGORY_MODEL_REQUIREMENTS } from "./model-requirements"
|
import { AGENT_MODEL_REQUIREMENTS, CATEGORY_MODEL_REQUIREMENTS } from "./model-requirements"
|
||||||
|
|
||||||
export function resolveAgentVariant(
|
export function resolveAgentVariant(
|
||||||
config: OhMyOpenCodeConfig,
|
config: OhMyOpenAgentConfig,
|
||||||
agentName?: string
|
agentName?: string
|
||||||
): string | undefined {
|
): string | undefined {
|
||||||
if (!agentName) {
|
if (!agentName) {
|
||||||
@@ -33,7 +33,7 @@ export function resolveAgentVariant(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function resolveVariantForModel(
|
export function resolveVariantForModel(
|
||||||
config: OhMyOpenCodeConfig,
|
config: OhMyOpenAgentConfig,
|
||||||
agentName: string,
|
agentName: string,
|
||||||
currentModel: { providerID: string; modelID: string },
|
currentModel: { providerID: string; modelID: string },
|
||||||
): string | undefined {
|
): string | undefined {
|
||||||
@@ -87,7 +87,7 @@ function findVariantInChain(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function applyAgentVariant(
|
export function applyAgentVariant(
|
||||||
config: OhMyOpenCodeConfig,
|
config: OhMyOpenAgentConfig,
|
||||||
agentName: string | undefined,
|
agentName: string | undefined,
|
||||||
message: { variant?: string }
|
message: { variant?: string }
|
||||||
): void {
|
): void {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { PluginInput } from "@opencode-ai/plugin";
|
import type { PluginInput } from "@opencode-ai/plugin";
|
||||||
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool";
|
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import type { OhMyOpenCodeConfig } from "../../config/schema";
|
import type { OhMyOpenAgentConfig } from "../../config/schema";
|
||||||
import type { TaskObject } from "./types";
|
import type { TaskObject } from "./types";
|
||||||
import { TaskObjectSchema, TaskCreateInputSchema } from "./types";
|
import { TaskObjectSchema, TaskCreateInputSchema } from "./types";
|
||||||
import {
|
import {
|
||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
import { syncTaskTodoUpdate } from "./todo-sync";
|
import { syncTaskTodoUpdate } from "./todo-sync";
|
||||||
|
|
||||||
export function createTaskCreateTool(
|
export function createTaskCreateTool(
|
||||||
config: Partial<OhMyOpenCodeConfig>,
|
config: Partial<OhMyOpenAgentConfig>,
|
||||||
ctx?: PluginInput,
|
ctx?: PluginInput,
|
||||||
): ToolDefinition {
|
): ToolDefinition {
|
||||||
return tool({
|
return tool({
|
||||||
@@ -58,7 +58,7 @@ Calculate dependencies carefully to maximize parallel execution:
|
|||||||
|
|
||||||
async function handleCreate(
|
async function handleCreate(
|
||||||
args: Record<string, unknown>,
|
args: Record<string, unknown>,
|
||||||
config: Partial<OhMyOpenCodeConfig>,
|
config: Partial<OhMyOpenAgentConfig>,
|
||||||
ctx: PluginInput | undefined,
|
ctx: PluginInput | undefined,
|
||||||
context: { sessionID: string },
|
context: { sessionID: string },
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool"
|
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool"
|
||||||
import { join } from "path"
|
import { join } from "path"
|
||||||
import type { OhMyOpenCodeConfig } from "../../config/schema"
|
import type { OhMyOpenAgentConfig } from "../../config/schema"
|
||||||
import { TaskGetInputSchema, TaskObjectSchema } from "./types"
|
import { TaskGetInputSchema, TaskObjectSchema } from "./types"
|
||||||
import { getTaskDir, readJsonSafe } from "../../features/claude-tasks/storage"
|
import { getTaskDir, readJsonSafe } from "../../features/claude-tasks/storage"
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ function parseTaskId(id: string): string | null {
|
|||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTaskGetTool(config: Partial<OhMyOpenCodeConfig>): ToolDefinition {
|
export function createTaskGetTool(config: Partial<OhMyOpenAgentConfig>): ToolDefinition {
|
||||||
return tool({
|
return tool({
|
||||||
description: `Retrieve a task by ID.
|
description: `Retrieve a task by ID.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool"
|
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool"
|
||||||
import { join } from "path"
|
import { join } from "path"
|
||||||
import { existsSync, readdirSync } from "fs"
|
import { existsSync, readdirSync } from "fs"
|
||||||
import type { OhMyOpenCodeConfig } from "../../config/schema"
|
import type { OhMyOpenAgentConfig } from "../../config/schema"
|
||||||
import type { TaskObject, TaskStatus } from "./types"
|
import type { TaskObject, TaskStatus } from "./types"
|
||||||
import { TaskObjectSchema } from "./types"
|
import { TaskObjectSchema } from "./types"
|
||||||
import { readJsonSafe, getTaskDir } from "../../features/claude-tasks/storage"
|
import { readJsonSafe, getTaskDir } from "../../features/claude-tasks/storage"
|
||||||
@@ -14,7 +14,7 @@ interface TaskSummary {
|
|||||||
blockedBy: string[]
|
blockedBy: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTaskList(config: Partial<OhMyOpenCodeConfig>): ToolDefinition {
|
export function createTaskList(config: Partial<OhMyOpenAgentConfig>): ToolDefinition {
|
||||||
return tool({
|
return tool({
|
||||||
description: `List all active tasks with summary information.
|
description: `List all active tasks with summary information.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { PluginInput } from "@opencode-ai/plugin";
|
import type { PluginInput } from "@opencode-ai/plugin";
|
||||||
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool";
|
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import type { OhMyOpenCodeConfig } from "../../config/schema";
|
import type { OhMyOpenAgentConfig } from "../../config/schema";
|
||||||
import { TaskObjectSchema, TaskUpdateInputSchema } from "./types";
|
import { TaskObjectSchema, TaskUpdateInputSchema } from "./types";
|
||||||
import {
|
import {
|
||||||
getTaskDir,
|
getTaskDir,
|
||||||
@@ -19,7 +19,7 @@ function parseTaskId(id: string): string | null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createTaskUpdateTool(
|
export function createTaskUpdateTool(
|
||||||
config: Partial<OhMyOpenCodeConfig>,
|
config: Partial<OhMyOpenAgentConfig>,
|
||||||
ctx?: PluginInput,
|
ctx?: PluginInput,
|
||||||
): ToolDefinition {
|
): ToolDefinition {
|
||||||
return tool({
|
return tool({
|
||||||
@@ -70,7 +70,7 @@ Properly managed dependencies enable maximum parallel execution.`,
|
|||||||
|
|
||||||
async function handleUpdate(
|
async function handleUpdate(
|
||||||
args: Record<string, unknown>,
|
args: Record<string, unknown>,
|
||||||
config: Partial<OhMyOpenCodeConfig>,
|
config: Partial<OhMyOpenAgentConfig>,
|
||||||
ctx: PluginInput | undefined,
|
ctx: PluginInput | undefined,
|
||||||
context: { sessionID: string },
|
context: { sessionID: string },
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
|
|||||||
Reference in New Issue
Block a user