Files
oh-my-opencode/src/shared/permission-compat.ts
T
Ivan Marshall Widjaja 0fada4d0fc fix(config): allow Sisyphus-Junior agent customization via oh-my-opencode.json (#648)
* fix(config): allow Sisyphus-Junior agent customization via oh-my-opencode.json

Allow users to configure Sisyphus-Junior agent via agents["Sisyphus-Junior"]
in oh-my-opencode.json, removing hardcoded defaults while preserving safety
constraints.
Closes #623
Changes:
- Add "Sisyphus-Junior" to AgentOverridesSchema and OverridableAgentNameSchema
- Create createSisyphusJuniorAgentWithOverrides() helper with guardrails
- Update config-handler to use override helper instead of hardcoded values
- Fix README category wording (runtime presets, not separate agents)
Honored override fields:
- model, temperature, top_p, tools, permission, description, color, prompt_append
Safety guardrails enforced post-merge:
- mode forced to "subagent" (cannot change)
- prompt is append-only (base discipline text preserved)
- blocked tools (task, sisyphus_task, call_omo_agent) always denied
- disable: true ignores override block, uses defaults
Category interaction:
- sisyphus_task(category=...) runs use the base Sisyphus-Junior agent config
- Category model/temperature overrides take precedence at request time
- To change model for a category, set categories.<cat>.model (not agent override)
- Categories are runtime presets applied to Sisyphus-Junior, not separate agents
Tests: 15 new tests in sisyphus-junior.test.ts, 3 new schema tests

Co-Authored-By: Sisyphus <sisyphus@mengmota.com>

* test(sisyphus-junior): add guard assertion for prompt anchor text

Add validation that baseEndIndex is not -1 before using it for ordering
assertion. Previously, if "Dense > verbose." text changed in the base
prompt, indexOf would return -1 and any positive appendIndex would pass.

Co-Authored-By: Sisyphus <sisyphus@mengmota.com>

---------

Co-authored-by: Sisyphus <sisyphus@mengmota.com>
2026-01-12 17:46:47 +09:00

82 lines
2.2 KiB
TypeScript

import { supportsNewPermissionSystem } from "./opencode-version"
export { supportsNewPermissionSystem }
export type PermissionValue = "ask" | "allow" | "deny"
export interface LegacyToolsFormat {
tools: Record<string, boolean>
}
export interface NewPermissionFormat {
permission: Record<string, PermissionValue>
}
export type VersionAwareRestrictions = LegacyToolsFormat | NewPermissionFormat
export function createAgentToolRestrictions(
denyTools: string[]
): VersionAwareRestrictions {
if (supportsNewPermissionSystem()) {
return {
permission: Object.fromEntries(
denyTools.map((tool) => [tool, "deny" as const])
),
}
}
return {
tools: Object.fromEntries(denyTools.map((tool) => [tool, false])),
}
}
export function migrateToolsToPermission(
tools: Record<string, boolean>
): Record<string, PermissionValue> {
return Object.fromEntries(
Object.entries(tools).map(([key, value]) => [
key,
value ? ("allow" as const) : ("deny" as const),
])
)
}
export function migratePermissionToTools(
permission: Record<string, PermissionValue>
): Record<string, boolean> {
return Object.fromEntries(
Object.entries(permission)
.filter(([, value]) => value !== "ask")
.map(([key, value]) => [key, value === "allow"])
)
}
export function migrateAgentConfig(
config: Record<string, unknown>
): Record<string, unknown> {
const result = { ...config }
if (supportsNewPermissionSystem()) {
if (result.tools && typeof result.tools === "object") {
const existingPermission =
(result.permission as Record<string, PermissionValue>) || {}
const migratedPermission = migrateToolsToPermission(
result.tools as Record<string, boolean>
)
result.permission = { ...migratedPermission, ...existingPermission }
delete result.tools
}
} else {
if (result.permission && typeof result.permission === "object") {
const existingTools = (result.tools as Record<string, boolean>) || {}
const migratedTools = migratePermissionToTools(
result.permission as Record<string, PermissionValue>
)
result.tools = { ...migratedTools, ...existingTools }
delete result.permission
}
}
return result
}