* chore: pin bun-types to 1.3.6 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * chore: exclude test files and script from tsconfig 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * refactor: remove sisyphus-swarm feature Remove mailbox types and swarm config schema. Update docs. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * refactor: remove legacy sisyphus-tasks feature Remove old storage and types implementation, replaced by claude-tasks. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(claude-tasks): add task schema and storage utilities - Task schema with Zod validation (pending, in_progress, completed, deleted) - Storage utilities: getTaskDir, readJsonSafe, writeJsonAtomic, acquireLock - Atomic writes with temp file + rename - File-based locking with 30s stale threshold 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(tools/task): add task object schemas Add Zod schemas for task CRUD operations input validation. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(tools): add TaskCreate tool Create new tasks with sequential ID generation and lock-based concurrency. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(tools): add TaskGet tool Retrieve task by ID with null-safe handling. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(tools): add TaskUpdate tool with claim validation Update tasks with status transitions and owner claim validation. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(tools): add TaskList tool and exports - TaskList for summary view of all tasks - Export all claude-tasks tool factories from index 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(hooks): add task-reminder hook Remind agents to use task tools after 10 turns without task operations. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(config): add disabled_tools setting and tasks-todowrite-disabler hook - Add disabled_tools config option to disable specific tools by name - Register tasks-todowrite-disabler hook name in schema 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(config-handler): add task_* and teammate tool permissions Grant task_* and teammate permissions to atlas, sisyphus, prometheus, and sisyphus-junior agents. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(delegate-task): add execute option for task execution Add optional execute field with task_id and task_dir for task-based delegation. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * fix(truncator): add type guard for non-string outputs Prevent crashes when output is not a string by adding typeof checks. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * chore: export config types and update task-resume-info - Export SisyphusConfig and SisyphusTasksConfig types - Add task_tool to TARGET_TOOLS list 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * refactor(storage): remove team namespace, use flat task directory * feat(task): implement unified task tool with all 5 actions * fix(hooks): update task-reminder to track unified task tool * refactor(tools): register unified task tool, remove 4 separate tools * chore(cleanup): remove old 4-tool task implementation * refactor(config): use new_task_system_enabled as top-level flag - Add new_task_system_enabled to OhMyOpenCodeConfigSchema - Remove enabled from SisyphusTasksConfigSchema (keep storage_path, claude_code_compat) - Update index.ts to gate on new_task_system_enabled - Update plugin-config.ts default for config initialization - Update test configs in task.test.ts and storage.test.ts Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * fix: resolve typecheck and test failures - Add explicit ToolDefinition return type to createTask function - Fix planDemoteConfig to use 'subagent' mode instead of 'all' --------- Co-authored-by: justsisyphus <justsisyphus@users.noreply.github.com> Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
502 lines
19 KiB
TypeScript
502 lines
19 KiB
TypeScript
import { createBuiltinAgents } from "../agents";
|
|
import { createSisyphusJuniorAgentWithOverrides } from "../agents/sisyphus-junior";
|
|
import {
|
|
loadUserCommands,
|
|
loadProjectCommands,
|
|
loadOpencodeGlobalCommands,
|
|
loadOpencodeProjectCommands,
|
|
} from "../features/claude-code-command-loader";
|
|
import { loadBuiltinCommands } from "../features/builtin-commands";
|
|
import {
|
|
loadUserSkills,
|
|
loadProjectSkills,
|
|
loadOpencodeGlobalSkills,
|
|
loadOpencodeProjectSkills,
|
|
discoverUserClaudeSkills,
|
|
discoverProjectClaudeSkills,
|
|
discoverOpencodeGlobalSkills,
|
|
discoverOpencodeProjectSkills,
|
|
} from "../features/opencode-skill-loader";
|
|
import {
|
|
loadUserAgents,
|
|
loadProjectAgents,
|
|
} from "../features/claude-code-agent-loader";
|
|
import { loadMcpConfigs } from "../features/claude-code-mcp-loader";
|
|
import { loadAllPluginComponents } from "../features/claude-code-plugin-loader";
|
|
import { createBuiltinMcps } from "../mcp";
|
|
import type { OhMyOpenCodeConfig } from "../config";
|
|
import { log, fetchAvailableModels, readConnectedProvidersCache, resolveModelPipeline } from "../shared";
|
|
import { getOpenCodeConfigPaths } from "../shared/opencode-config-dir";
|
|
import { migrateAgentConfig } from "../shared/permission-compat";
|
|
import { AGENT_NAME_MAP } from "../shared/migration";
|
|
import { AGENT_MODEL_REQUIREMENTS } from "../shared/model-requirements";
|
|
import { PROMETHEUS_SYSTEM_PROMPT, PROMETHEUS_PERMISSION } from "../agents/prometheus";
|
|
import { DEFAULT_CATEGORIES } from "../tools/delegate-task/constants";
|
|
import type { ModelCacheState } from "../plugin-state";
|
|
import type { CategoryConfig } from "../config/schema";
|
|
|
|
export interface ConfigHandlerDeps {
|
|
ctx: { directory: string; client?: any };
|
|
pluginConfig: OhMyOpenCodeConfig;
|
|
modelCacheState: ModelCacheState;
|
|
}
|
|
|
|
export function resolveCategoryConfig(
|
|
categoryName: string,
|
|
userCategories?: Record<string, CategoryConfig>
|
|
): CategoryConfig | undefined {
|
|
return userCategories?.[categoryName] ?? DEFAULT_CATEGORIES[categoryName];
|
|
}
|
|
|
|
const CORE_AGENT_ORDER = ["sisyphus", "hephaestus", "prometheus", "atlas"] as const;
|
|
|
|
function reorderAgentsByPriority(agents: Record<string, unknown>): Record<string, unknown> {
|
|
const ordered: Record<string, unknown> = {};
|
|
const seen = new Set<string>();
|
|
|
|
for (const key of CORE_AGENT_ORDER) {
|
|
if (Object.prototype.hasOwnProperty.call(agents, key)) {
|
|
ordered[key] = agents[key];
|
|
seen.add(key);
|
|
}
|
|
}
|
|
|
|
for (const [key, value] of Object.entries(agents)) {
|
|
if (!seen.has(key)) {
|
|
ordered[key] = value;
|
|
}
|
|
}
|
|
|
|
return ordered;
|
|
}
|
|
|
|
export function createConfigHandler(deps: ConfigHandlerDeps) {
|
|
const { ctx, pluginConfig, modelCacheState } = deps;
|
|
|
|
return async (config: Record<string, unknown>) => {
|
|
type ProviderConfig = {
|
|
options?: { headers?: Record<string, string> };
|
|
models?: Record<string, { limit?: { context?: number } }>;
|
|
};
|
|
const providers = config.provider as
|
|
| Record<string, ProviderConfig>
|
|
| undefined;
|
|
|
|
const anthropicBeta =
|
|
providers?.anthropic?.options?.headers?.["anthropic-beta"];
|
|
modelCacheState.anthropicContext1MEnabled =
|
|
anthropicBeta?.includes("context-1m") ?? false;
|
|
|
|
if (providers) {
|
|
for (const [providerID, providerConfig] of Object.entries(providers)) {
|
|
const models = providerConfig?.models;
|
|
if (models) {
|
|
for (const [modelID, modelConfig] of Object.entries(models)) {
|
|
const contextLimit = modelConfig?.limit?.context;
|
|
if (contextLimit) {
|
|
modelCacheState.modelContextLimitsCache.set(
|
|
`${providerID}/${modelID}`,
|
|
contextLimit
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const pluginComponents = (pluginConfig.claude_code?.plugins ?? true)
|
|
? await loadAllPluginComponents({
|
|
enabledPluginsOverride: pluginConfig.claude_code?.plugins_override,
|
|
})
|
|
: {
|
|
commands: {},
|
|
skills: {},
|
|
agents: {},
|
|
mcpServers: {},
|
|
hooksConfigs: [],
|
|
plugins: [],
|
|
errors: [],
|
|
};
|
|
|
|
if (pluginComponents.plugins.length > 0) {
|
|
log(`Loaded ${pluginComponents.plugins.length} Claude Code plugins`, {
|
|
plugins: pluginComponents.plugins.map((p) => `${p.name}@${p.version}`),
|
|
});
|
|
}
|
|
|
|
if (pluginComponents.errors.length > 0) {
|
|
log(`Plugin load errors`, { errors: pluginComponents.errors });
|
|
}
|
|
|
|
// Migrate disabled_agents from old names to new names
|
|
const migratedDisabledAgents = (pluginConfig.disabled_agents ?? []).map(agent => {
|
|
return AGENT_NAME_MAP[agent.toLowerCase()] ?? AGENT_NAME_MAP[agent] ?? agent
|
|
}) as typeof pluginConfig.disabled_agents
|
|
|
|
const includeClaudeSkillsForAwareness = pluginConfig.claude_code?.skills ?? true;
|
|
const [
|
|
discoveredUserSkills,
|
|
discoveredProjectSkills,
|
|
discoveredOpencodeGlobalSkills,
|
|
discoveredOpencodeProjectSkills,
|
|
] = await Promise.all([
|
|
includeClaudeSkillsForAwareness ? discoverUserClaudeSkills() : Promise.resolve([]),
|
|
includeClaudeSkillsForAwareness ? discoverProjectClaudeSkills() : Promise.resolve([]),
|
|
discoverOpencodeGlobalSkills(),
|
|
discoverOpencodeProjectSkills(),
|
|
]);
|
|
|
|
const allDiscoveredSkills = [
|
|
...discoveredOpencodeProjectSkills,
|
|
...discoveredProjectSkills,
|
|
...discoveredOpencodeGlobalSkills,
|
|
...discoveredUserSkills,
|
|
];
|
|
|
|
const browserProvider = pluginConfig.browser_automation_engine?.provider ?? "playwright";
|
|
// config.model represents the currently active model in OpenCode (including UI selection)
|
|
// Pass it as uiSelectedModel so it takes highest priority in model resolution
|
|
const currentModel = config.model as string | undefined;
|
|
const builtinAgents = await createBuiltinAgents(
|
|
migratedDisabledAgents,
|
|
pluginConfig.agents,
|
|
ctx.directory,
|
|
undefined, // systemDefaultModel - let fallback chain handle this
|
|
pluginConfig.categories,
|
|
pluginConfig.git_master,
|
|
allDiscoveredSkills,
|
|
ctx.client,
|
|
browserProvider,
|
|
currentModel // uiSelectedModel - takes highest priority
|
|
);
|
|
|
|
// Claude Code agents: Do NOT apply permission migration
|
|
// Claude Code uses whitelist-based tools format which is semantically different
|
|
// from OpenCode's denylist-based permission system
|
|
const userAgents = (pluginConfig.claude_code?.agents ?? true)
|
|
? loadUserAgents()
|
|
: {};
|
|
const projectAgents = (pluginConfig.claude_code?.agents ?? true)
|
|
? loadProjectAgents()
|
|
: {};
|
|
|
|
// Plugin agents: Apply permission migration for compatibility
|
|
const rawPluginAgents = pluginComponents.agents;
|
|
const pluginAgents = Object.fromEntries(
|
|
Object.entries(rawPluginAgents).map(([k, v]) => [
|
|
k,
|
|
v ? migrateAgentConfig(v as Record<string, unknown>) : v,
|
|
])
|
|
);
|
|
|
|
const isSisyphusEnabled = pluginConfig.sisyphus_agent?.disabled !== true;
|
|
const builderEnabled =
|
|
pluginConfig.sisyphus_agent?.default_builder_enabled ?? false;
|
|
const plannerEnabled =
|
|
pluginConfig.sisyphus_agent?.planner_enabled ?? true;
|
|
const replacePlan = pluginConfig.sisyphus_agent?.replace_plan ?? true;
|
|
|
|
type AgentConfig = Record<
|
|
string,
|
|
Record<string, unknown> | undefined
|
|
> & {
|
|
build?: Record<string, unknown>;
|
|
plan?: Record<string, unknown>;
|
|
explore?: { tools?: Record<string, unknown> };
|
|
librarian?: { tools?: Record<string, unknown> };
|
|
"multimodal-looker"?: { tools?: Record<string, unknown> };
|
|
atlas?: { tools?: Record<string, unknown> };
|
|
sisyphus?: { tools?: Record<string, unknown> };
|
|
};
|
|
const configAgent = config.agent as AgentConfig | undefined;
|
|
|
|
if (isSisyphusEnabled && builtinAgents.sisyphus) {
|
|
(config as { default_agent?: string }).default_agent = "sisyphus";
|
|
|
|
const agentConfig: Record<string, unknown> = {
|
|
sisyphus: builtinAgents.sisyphus,
|
|
};
|
|
|
|
agentConfig["sisyphus-junior"] = createSisyphusJuniorAgentWithOverrides(
|
|
pluginConfig.agents?.["sisyphus-junior"],
|
|
config.model as string | undefined
|
|
);
|
|
|
|
if (builderEnabled) {
|
|
const { name: _buildName, ...buildConfigWithoutName } =
|
|
configAgent?.build ?? {};
|
|
const migratedBuildConfig = migrateAgentConfig(
|
|
buildConfigWithoutName as Record<string, unknown>
|
|
);
|
|
const openCodeBuilderOverride =
|
|
pluginConfig.agents?.["OpenCode-Builder"];
|
|
const openCodeBuilderBase = {
|
|
...migratedBuildConfig,
|
|
description: `${configAgent?.build?.description ?? "Build agent"} (OpenCode default)`,
|
|
};
|
|
|
|
agentConfig["OpenCode-Builder"] = openCodeBuilderOverride
|
|
? { ...openCodeBuilderBase, ...openCodeBuilderOverride }
|
|
: openCodeBuilderBase;
|
|
}
|
|
|
|
if (plannerEnabled) {
|
|
const { name: _planName, mode: _planMode, ...planConfigWithoutName } =
|
|
configAgent?.plan ?? {};
|
|
const migratedPlanConfig = migrateAgentConfig(
|
|
planConfigWithoutName as Record<string, unknown>
|
|
);
|
|
const prometheusOverride =
|
|
pluginConfig.agents?.["prometheus"] as
|
|
| (Record<string, unknown> & {
|
|
category?: string
|
|
model?: string
|
|
variant?: string
|
|
reasoningEffort?: string
|
|
textVerbosity?: string
|
|
thinking?: { type: string; budgetTokens?: number }
|
|
temperature?: number
|
|
top_p?: number
|
|
maxTokens?: number
|
|
})
|
|
| undefined;
|
|
|
|
const categoryConfig = prometheusOverride?.category
|
|
? resolveCategoryConfig(
|
|
prometheusOverride.category,
|
|
pluginConfig.categories
|
|
)
|
|
: undefined;
|
|
|
|
const prometheusRequirement = AGENT_MODEL_REQUIREMENTS["prometheus"];
|
|
const connectedProviders = readConnectedProvidersCache();
|
|
// IMPORTANT: Do NOT pass ctx.client to fetchAvailableModels during plugin initialization.
|
|
// Calling client API (e.g., client.provider.list()) from config handler causes deadlock:
|
|
// - Plugin init waits for server response
|
|
// - Server waits for plugin init to complete before handling requests
|
|
// Use cache-only mode instead. If cache is unavailable, fallback chain uses first model.
|
|
// See: https://github.com/code-yeongyu/oh-my-opencode/issues/1301
|
|
const availableModels = await fetchAvailableModels(undefined, {
|
|
connectedProviders: connectedProviders ?? undefined,
|
|
});
|
|
|
|
const modelResolution = resolveModelPipeline({
|
|
intent: {
|
|
uiSelectedModel: currentModel,
|
|
userModel: prometheusOverride?.model ?? categoryConfig?.model,
|
|
},
|
|
constraints: { availableModels },
|
|
policy: {
|
|
fallbackChain: prometheusRequirement?.fallbackChain,
|
|
systemDefaultModel: undefined,
|
|
},
|
|
});
|
|
const resolvedModel = modelResolution?.model;
|
|
const resolvedVariant = modelResolution?.variant;
|
|
|
|
const variantToUse = prometheusOverride?.variant ?? resolvedVariant;
|
|
const reasoningEffortToUse = prometheusOverride?.reasoningEffort ?? categoryConfig?.reasoningEffort;
|
|
const textVerbosityToUse = prometheusOverride?.textVerbosity ?? categoryConfig?.textVerbosity;
|
|
const thinkingToUse = prometheusOverride?.thinking ?? categoryConfig?.thinking;
|
|
const temperatureToUse = prometheusOverride?.temperature ?? categoryConfig?.temperature;
|
|
const topPToUse = prometheusOverride?.top_p ?? categoryConfig?.top_p;
|
|
const maxTokensToUse = prometheusOverride?.maxTokens ?? categoryConfig?.maxTokens;
|
|
const prometheusBase = {
|
|
name: "prometheus",
|
|
...(resolvedModel ? { model: resolvedModel } : {}),
|
|
...(variantToUse ? { variant: variantToUse } : {}),
|
|
mode: "all" as const,
|
|
prompt: PROMETHEUS_SYSTEM_PROMPT,
|
|
permission: PROMETHEUS_PERMISSION,
|
|
description: `${configAgent?.plan?.description ?? "Plan agent"} (Prometheus - OhMyOpenCode)`,
|
|
color: (configAgent?.plan?.color as string) ?? "#9D4EDD", // Amethyst Purple - wisdom/foresight
|
|
...(temperatureToUse !== undefined ? { temperature: temperatureToUse } : {}),
|
|
...(topPToUse !== undefined ? { top_p: topPToUse } : {}),
|
|
...(maxTokensToUse !== undefined ? { maxTokens: maxTokensToUse } : {}),
|
|
...(categoryConfig?.tools ? { tools: categoryConfig.tools } : {}),
|
|
...(thinkingToUse ? { thinking: thinkingToUse } : {}),
|
|
...(reasoningEffortToUse !== undefined
|
|
? { reasoningEffort: reasoningEffortToUse }
|
|
: {}),
|
|
...(textVerbosityToUse !== undefined
|
|
? { textVerbosity: textVerbosityToUse }
|
|
: {}),
|
|
};
|
|
|
|
// Properly handle prompt_append for Prometheus
|
|
// Extract prompt_append and append it to prompt instead of shallow spread
|
|
// Fixes: https://github.com/code-yeongyu/oh-my-opencode/issues/723
|
|
if (prometheusOverride) {
|
|
const { prompt_append, ...restOverride } = prometheusOverride as Record<string, unknown> & { prompt_append?: string };
|
|
const merged = { ...prometheusBase, ...restOverride };
|
|
if (prompt_append && merged.prompt) {
|
|
merged.prompt = merged.prompt + "\n" + prompt_append;
|
|
}
|
|
agentConfig["prometheus"] = merged;
|
|
} else {
|
|
agentConfig["prometheus"] = prometheusBase;
|
|
}
|
|
}
|
|
|
|
const filteredConfigAgents = configAgent
|
|
? Object.fromEntries(
|
|
Object.entries(configAgent)
|
|
.filter(([key]) => {
|
|
if (key === "build") return false;
|
|
if (key === "plan" && replacePlan) return false;
|
|
// Filter out agents that oh-my-opencode provides to prevent
|
|
// OpenCode defaults from overwriting user config in oh-my-opencode.json
|
|
// See: https://github.com/code-yeongyu/oh-my-opencode/issues/472
|
|
if (key in builtinAgents) return false;
|
|
return true;
|
|
})
|
|
.map(([key, value]) => [
|
|
key,
|
|
value ? migrateAgentConfig(value as Record<string, unknown>) : value,
|
|
])
|
|
)
|
|
: {};
|
|
|
|
const migratedBuild = configAgent?.build
|
|
? migrateAgentConfig(configAgent.build as Record<string, unknown>)
|
|
: {};
|
|
|
|
const planDemoteConfig = replacePlan && agentConfig["prometheus"]
|
|
? {
|
|
...agentConfig["prometheus"],
|
|
name: "plan",
|
|
mode: "subagent" as const
|
|
}
|
|
: undefined;
|
|
|
|
config.agent = {
|
|
...agentConfig,
|
|
...Object.fromEntries(
|
|
Object.entries(builtinAgents).filter(([k]) => k !== "sisyphus")
|
|
),
|
|
...userAgents,
|
|
...projectAgents,
|
|
...pluginAgents,
|
|
...filteredConfigAgents,
|
|
build: { ...migratedBuild, mode: "subagent", hidden: true },
|
|
...(planDemoteConfig ? { plan: planDemoteConfig } : {}),
|
|
};
|
|
} else {
|
|
config.agent = {
|
|
...builtinAgents,
|
|
...userAgents,
|
|
...projectAgents,
|
|
...pluginAgents,
|
|
...configAgent,
|
|
};
|
|
}
|
|
|
|
if (config.agent) {
|
|
config.agent = reorderAgentsByPriority(config.agent as Record<string, unknown>);
|
|
}
|
|
|
|
const agentResult = config.agent as AgentConfig;
|
|
|
|
config.tools = {
|
|
...(config.tools as Record<string, unknown>),
|
|
"grep_app_*": false,
|
|
LspHover: false,
|
|
LspCodeActions: false,
|
|
LspCodeActionResolve: false,
|
|
"task_*": false,
|
|
teammate: false,
|
|
};
|
|
|
|
type AgentWithPermission = { permission?: Record<string, unknown> };
|
|
|
|
if (agentResult.librarian) {
|
|
const agent = agentResult.librarian as AgentWithPermission;
|
|
agent.permission = { ...agent.permission, "grep_app_*": "allow" };
|
|
}
|
|
if (agentResult["multimodal-looker"]) {
|
|
const agent = agentResult["multimodal-looker"] as AgentWithPermission;
|
|
agent.permission = { ...agent.permission, task: "deny", look_at: "deny" };
|
|
}
|
|
if (agentResult["atlas"]) {
|
|
const agent = agentResult["atlas"] as AgentWithPermission;
|
|
agent.permission = { ...agent.permission, task: "deny", call_omo_agent: "deny", delegate_task: "allow", "task_*": "allow", teammate: "allow" };
|
|
}
|
|
if (agentResult.sisyphus) {
|
|
const agent = agentResult.sisyphus as AgentWithPermission;
|
|
agent.permission = { ...agent.permission, call_omo_agent: "deny", delegate_task: "allow", question: "allow", "task_*": "allow", teammate: "allow" };
|
|
}
|
|
if (agentResult.hephaestus) {
|
|
const agent = agentResult.hephaestus as AgentWithPermission;
|
|
agent.permission = { ...agent.permission, call_omo_agent: "deny", delegate_task: "allow", question: "allow" };
|
|
}
|
|
if (agentResult["prometheus"]) {
|
|
const agent = agentResult["prometheus"] as AgentWithPermission;
|
|
agent.permission = { ...agent.permission, call_omo_agent: "deny", delegate_task: "allow", question: "allow", "task_*": "allow", teammate: "allow" };
|
|
}
|
|
if (agentResult["sisyphus-junior"]) {
|
|
const agent = agentResult["sisyphus-junior"] as AgentWithPermission;
|
|
agent.permission = { ...agent.permission, delegate_task: "allow", "task_*": "allow", teammate: "allow" };
|
|
}
|
|
|
|
config.permission = {
|
|
...(config.permission as Record<string, unknown>),
|
|
webfetch: "allow",
|
|
external_directory: "allow",
|
|
delegate_task: "deny",
|
|
};
|
|
|
|
const mcpResult = (pluginConfig.claude_code?.mcp ?? true)
|
|
? await loadMcpConfigs()
|
|
: { servers: {} };
|
|
|
|
config.mcp = {
|
|
...createBuiltinMcps(pluginConfig.disabled_mcps),
|
|
...(config.mcp as Record<string, unknown>),
|
|
...mcpResult.servers,
|
|
...pluginComponents.mcpServers,
|
|
};
|
|
|
|
const builtinCommands = loadBuiltinCommands(pluginConfig.disabled_commands);
|
|
const systemCommands = (config.command as Record<string, unknown>) ?? {};
|
|
|
|
// Parallel loading of all commands and skills for faster startup
|
|
const includeClaudeCommands = pluginConfig.claude_code?.commands ?? true;
|
|
const includeClaudeSkills = pluginConfig.claude_code?.skills ?? true;
|
|
|
|
const [
|
|
userCommands,
|
|
projectCommands,
|
|
opencodeGlobalCommands,
|
|
opencodeProjectCommands,
|
|
userSkills,
|
|
projectSkills,
|
|
opencodeGlobalSkills,
|
|
opencodeProjectSkills,
|
|
] = await Promise.all([
|
|
includeClaudeCommands ? loadUserCommands() : Promise.resolve({}),
|
|
includeClaudeCommands ? loadProjectCommands() : Promise.resolve({}),
|
|
loadOpencodeGlobalCommands(),
|
|
loadOpencodeProjectCommands(),
|
|
includeClaudeSkills ? loadUserSkills() : Promise.resolve({}),
|
|
includeClaudeSkills ? loadProjectSkills() : Promise.resolve({}),
|
|
loadOpencodeGlobalSkills(),
|
|
loadOpencodeProjectSkills(),
|
|
]);
|
|
|
|
config.command = {
|
|
...builtinCommands,
|
|
...userCommands,
|
|
...userSkills,
|
|
...opencodeGlobalCommands,
|
|
...opencodeGlobalSkills,
|
|
...systemCommands,
|
|
...projectCommands,
|
|
...projectSkills,
|
|
...opencodeProjectCommands,
|
|
...opencodeProjectSkills,
|
|
...pluginComponents.commands,
|
|
...pluginComponents.skills,
|
|
};
|
|
};
|
|
}
|