refactor(server): split opencode config/auth/ui-auth into domain modules (#454)
* docs(agents): map opencode module documentation * docs(opencode): document split module responsibilities * refactor(opencode): centralize shared config and file helpers * refactor(opencode): move auth storage helpers into domain module * refactor(opencode): move UI auth implementation into domain module * refactor(opencode): isolate agent scope and CRUD logic * refactor(opencode): isolate command scope and CRUD logic * refactor(opencode): isolate provider config helpers * refactor(opencode): isolate skill discovery and CRUD logic * refactor(opencode): define single public module entrypoint * refactor(opencode): remove legacy opencode-config module * refactor(opencode): remove obsolete opencode-config typings * refactor(opencode): remove legacy opencode-auth module * refactor(opencode): remove legacy ui-auth shim * refactor(server): import opencode APIs from new module paths * refactor(tts): consume auth helpers from opencode domain module * refactor(quota): point claude provider auth import to opencode domain * refactor(quota): point codex provider auth import to opencode domain * refactor(quota): point copilot provider auth import to opencode domain * refactor(quota): point google auth import to opencode domain * refactor(quota): point kimi provider auth import to opencode domain * refactor(quota): point nanogpt provider auth import to opencode domain * refactor(quota): point openai provider auth import to opencode domain * refactor(quota): point openrouter provider auth import to opencode domain * refactor(quota): point zai provider auth import to opencode domain * fix(opencode): restore provider source and disconnect semantics
This commit is contained in:
@@ -0,0 +1,563 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import {
|
||||
CONFIG_FILE,
|
||||
AGENT_DIR,
|
||||
AGENT_SCOPE,
|
||||
ensureDirs,
|
||||
parseMdFile,
|
||||
writeMdFile,
|
||||
readConfigLayers,
|
||||
readConfigFile,
|
||||
writeConfig,
|
||||
getJsonEntrySource,
|
||||
getJsonWriteTarget,
|
||||
isPromptFileReference,
|
||||
resolvePromptFilePath,
|
||||
writePromptFile,
|
||||
} from './shared.js';
|
||||
|
||||
// ============== AGENT SCOPE HELPERS ==============
|
||||
|
||||
/**
|
||||
* Ensure project-level agent directory exists
|
||||
*/
|
||||
function ensureProjectAgentDir(workingDirectory) {
|
||||
const projectAgentDir = path.join(workingDirectory, '.opencode', 'agents');
|
||||
if (!fs.existsSync(projectAgentDir)) {
|
||||
fs.mkdirSync(projectAgentDir, { recursive: true });
|
||||
}
|
||||
const legacyProjectAgentDir = path.join(workingDirectory, '.opencode', 'agent');
|
||||
if (!fs.existsSync(legacyProjectAgentDir)) {
|
||||
fs.mkdirSync(legacyProjectAgentDir, { recursive: true });
|
||||
}
|
||||
return projectAgentDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project-level agent path
|
||||
*/
|
||||
function getProjectAgentPath(workingDirectory, agentName) {
|
||||
const pluralPath = path.join(workingDirectory, '.opencode', 'agents', `${agentName}.md`);
|
||||
const legacyPath = path.join(workingDirectory, '.opencode', 'agent', `${agentName}.md`);
|
||||
if (fs.existsSync(legacyPath) && !fs.existsSync(pluralPath)) return legacyPath;
|
||||
return pluralPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user-level agent path
|
||||
*/
|
||||
function getUserAgentPath(agentName) {
|
||||
const pluralPath = path.join(AGENT_DIR, `${agentName}.md`);
|
||||
const legacyPath = path.join(AGENT_DIR, '..', 'agent', `${agentName}.md`);
|
||||
if (fs.existsSync(legacyPath) && !fs.existsSync(pluralPath)) return legacyPath;
|
||||
return pluralPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine agent scope based on where the .md file exists
|
||||
* Priority: project level > user level > null (built-in only)
|
||||
*/
|
||||
function getAgentScope(agentName, workingDirectory) {
|
||||
if (workingDirectory) {
|
||||
const projectPath = getProjectAgentPath(workingDirectory, agentName);
|
||||
if (fs.existsSync(projectPath)) {
|
||||
return { scope: AGENT_SCOPE.PROJECT, path: projectPath };
|
||||
}
|
||||
}
|
||||
|
||||
const userPath = getUserAgentPath(agentName);
|
||||
if (fs.existsSync(userPath)) {
|
||||
return { scope: AGENT_SCOPE.USER, path: userPath };
|
||||
}
|
||||
|
||||
return { scope: null, path: null };
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path where an agent should be written based on scope
|
||||
*/
|
||||
function getAgentWritePath(agentName, workingDirectory, requestedScope) {
|
||||
// For updates: check existing location first (project takes precedence)
|
||||
const existing = getAgentScope(agentName, workingDirectory);
|
||||
if (existing.path) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
// For new agents or built-in overrides: use requested scope or default to user
|
||||
const scope = requestedScope || AGENT_SCOPE.USER;
|
||||
if (scope === AGENT_SCOPE.PROJECT && workingDirectory) {
|
||||
return {
|
||||
scope: AGENT_SCOPE.PROJECT,
|
||||
path: getProjectAgentPath(workingDirectory, agentName)
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
scope: AGENT_SCOPE.USER,
|
||||
path: getUserAgentPath(agentName)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect where an agent's permission field is currently defined
|
||||
* Priority: project .md > user .md > project JSON > user JSON
|
||||
* Returns: { source: 'md'|'json'|null, scope: 'project'|'user'|null, path: string|null }
|
||||
*/
|
||||
function getAgentPermissionSource(agentName, workingDirectory) {
|
||||
// Check project-level .md first
|
||||
if (workingDirectory) {
|
||||
const projectMdPath = getProjectAgentPath(workingDirectory, agentName);
|
||||
if (fs.existsSync(projectMdPath)) {
|
||||
const { frontmatter } = parseMdFile(projectMdPath);
|
||||
if (frontmatter.permission !== undefined) {
|
||||
return { source: 'md', scope: AGENT_SCOPE.PROJECT, path: projectMdPath };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check user-level .md
|
||||
const userMdPath = getUserAgentPath(agentName);
|
||||
if (fs.existsSync(userMdPath)) {
|
||||
const { frontmatter } = parseMdFile(userMdPath);
|
||||
if (frontmatter.permission !== undefined) {
|
||||
return { source: 'md', scope: AGENT_SCOPE.USER, path: userMdPath };
|
||||
}
|
||||
}
|
||||
|
||||
// Check JSON layers (project > user)
|
||||
const layers = readConfigLayers(workingDirectory);
|
||||
|
||||
// Project opencode.json
|
||||
const projectJsonPermission = layers.projectConfig?.agent?.[agentName]?.permission;
|
||||
if (projectJsonPermission !== undefined && layers.paths.projectPath) {
|
||||
return { source: 'json', scope: AGENT_SCOPE.PROJECT, path: layers.paths.projectPath };
|
||||
}
|
||||
|
||||
// User opencode.json
|
||||
const userJsonPermission = layers.userConfig?.agent?.[agentName]?.permission;
|
||||
if (userJsonPermission !== undefined) {
|
||||
return { source: 'json', scope: AGENT_SCOPE.USER, path: layers.paths.userPath };
|
||||
}
|
||||
|
||||
// Custom config (env var)
|
||||
const customJsonPermission = layers.customConfig?.agent?.[agentName]?.permission;
|
||||
if (customJsonPermission !== undefined && layers.paths.customPath) {
|
||||
return { source: 'json', scope: 'custom', path: layers.paths.customPath };
|
||||
}
|
||||
|
||||
return { source: null, scope: null, path: null };
|
||||
}
|
||||
|
||||
function mergePermissionWithNonWildcards(newPermission, permissionSource, agentName) {
|
||||
if (!permissionSource.source || !permissionSource.path) {
|
||||
return newPermission;
|
||||
}
|
||||
|
||||
let existingPermission = null;
|
||||
if (permissionSource.source === 'md') {
|
||||
const { frontmatter } = parseMdFile(permissionSource.path);
|
||||
existingPermission = frontmatter.permission;
|
||||
} else if (permissionSource.source === 'json') {
|
||||
const config = readConfigFile(permissionSource.path);
|
||||
existingPermission = config?.agent?.[agentName]?.permission;
|
||||
}
|
||||
|
||||
if (!existingPermission || typeof existingPermission === 'string') {
|
||||
return newPermission;
|
||||
}
|
||||
|
||||
if (newPermission == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof newPermission === 'string') {
|
||||
return newPermission;
|
||||
}
|
||||
|
||||
const nonWildcardPatterns = {};
|
||||
for (const [permKey, permValue] of Object.entries(existingPermission)) {
|
||||
if (permKey === '*') continue;
|
||||
|
||||
if (typeof permValue === 'object' && permValue !== null && !Array.isArray(permValue)) {
|
||||
const nonWildcards = {};
|
||||
for (const [pattern, action] of Object.entries(permValue)) {
|
||||
if (pattern !== '*') {
|
||||
nonWildcards[pattern] = action;
|
||||
}
|
||||
}
|
||||
if (Object.keys(nonWildcards).length > 0) {
|
||||
nonWildcardPatterns[permKey] = nonWildcards;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(nonWildcardPatterns).length === 0) {
|
||||
return newPermission;
|
||||
}
|
||||
|
||||
const merged = { ...newPermission };
|
||||
for (const [permKey, patterns] of Object.entries(nonWildcardPatterns)) {
|
||||
const newValue = merged[permKey];
|
||||
if (typeof newValue === 'string') {
|
||||
merged[permKey] = { '*': newValue, ...patterns };
|
||||
} else if (typeof newValue === 'object' && newValue !== null) {
|
||||
merged[permKey] = { ...patterns, ...newValue };
|
||||
} else {
|
||||
const existingValue = existingPermission[permKey];
|
||||
if (typeof existingValue === 'object' && existingValue !== null) {
|
||||
const wildcard = existingValue['*'];
|
||||
merged[permKey] = wildcard ? { '*': wildcard, ...patterns } : patterns;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
function getAgentSources(agentName, workingDirectory) {
|
||||
const projectPath = workingDirectory ? getProjectAgentPath(workingDirectory, agentName) : null;
|
||||
const projectExists = projectPath && fs.existsSync(projectPath);
|
||||
|
||||
const userPath = getUserAgentPath(agentName);
|
||||
const userExists = fs.existsSync(userPath);
|
||||
|
||||
const mdPath = projectExists ? projectPath : (userExists ? userPath : null);
|
||||
const mdExists = !!mdPath;
|
||||
const mdScope = projectExists ? AGENT_SCOPE.PROJECT : (userExists ? AGENT_SCOPE.USER : null);
|
||||
|
||||
const layers = readConfigLayers(workingDirectory);
|
||||
const jsonSource = getJsonEntrySource(layers, 'agent', agentName);
|
||||
const jsonSection = jsonSource.section;
|
||||
const jsonPath = jsonSource.path || layers.paths.customPath || layers.paths.projectPath || layers.paths.userPath;
|
||||
const jsonScope = jsonSource.path === layers.paths.projectPath ? AGENT_SCOPE.PROJECT : AGENT_SCOPE.USER;
|
||||
|
||||
const sources = {
|
||||
md: {
|
||||
exists: mdExists,
|
||||
path: mdPath,
|
||||
scope: mdScope,
|
||||
fields: []
|
||||
},
|
||||
json: {
|
||||
exists: jsonSource.exists,
|
||||
path: jsonPath,
|
||||
scope: jsonSource.exists ? jsonScope : null,
|
||||
fields: []
|
||||
},
|
||||
projectMd: {
|
||||
exists: projectExists,
|
||||
path: projectPath
|
||||
},
|
||||
userMd: {
|
||||
exists: userExists,
|
||||
path: userPath
|
||||
}
|
||||
};
|
||||
|
||||
if (mdExists) {
|
||||
const { frontmatter, body } = parseMdFile(mdPath);
|
||||
sources.md.fields = Object.keys(frontmatter);
|
||||
if (body) {
|
||||
sources.md.fields.push('prompt');
|
||||
}
|
||||
}
|
||||
|
||||
if (jsonSection) {
|
||||
sources.json.fields = Object.keys(jsonSection);
|
||||
}
|
||||
|
||||
return sources;
|
||||
}
|
||||
|
||||
function getAgentConfig(agentName, workingDirectory) {
|
||||
const projectPath = workingDirectory ? getProjectAgentPath(workingDirectory, agentName) : null;
|
||||
const projectExists = projectPath && fs.existsSync(projectPath);
|
||||
|
||||
const userPath = getUserAgentPath(agentName);
|
||||
const userExists = fs.existsSync(userPath);
|
||||
|
||||
if (projectExists || userExists) {
|
||||
const mdPath = projectExists ? projectPath : userPath;
|
||||
const { frontmatter, body } = parseMdFile(mdPath);
|
||||
|
||||
return {
|
||||
source: 'md',
|
||||
scope: projectExists ? AGENT_SCOPE.PROJECT : AGENT_SCOPE.USER,
|
||||
config: {
|
||||
...frontmatter,
|
||||
...(typeof body === 'string' && body.length > 0 ? { prompt: body } : {}),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const layers = readConfigLayers(workingDirectory);
|
||||
const jsonSource = getJsonEntrySource(layers, 'agent', agentName);
|
||||
|
||||
if (jsonSource.exists && jsonSource.section) {
|
||||
const scope = jsonSource.path === layers.paths.projectPath ? AGENT_SCOPE.PROJECT : AGENT_SCOPE.USER;
|
||||
return {
|
||||
source: 'json',
|
||||
scope,
|
||||
config: { ...jsonSource.section },
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
source: 'none',
|
||||
scope: null,
|
||||
config: {},
|
||||
};
|
||||
}
|
||||
|
||||
function createAgent(agentName, config, workingDirectory, scope) {
|
||||
ensureDirs();
|
||||
|
||||
const projectPath = workingDirectory ? getProjectAgentPath(workingDirectory, agentName) : null;
|
||||
const userPath = getUserAgentPath(agentName);
|
||||
|
||||
if (projectPath && fs.existsSync(projectPath)) {
|
||||
throw new Error(`Agent ${agentName} already exists as project-level .md file`);
|
||||
}
|
||||
|
||||
if (fs.existsSync(userPath)) {
|
||||
throw new Error(`Agent ${agentName} already exists as user-level .md file`);
|
||||
}
|
||||
|
||||
const layers = readConfigLayers(workingDirectory);
|
||||
const jsonSource = getJsonEntrySource(layers, 'agent', agentName);
|
||||
if (jsonSource.exists) {
|
||||
throw new Error(`Agent ${agentName} already exists in opencode.json`);
|
||||
}
|
||||
|
||||
let targetPath;
|
||||
let targetScope;
|
||||
|
||||
if (scope === AGENT_SCOPE.PROJECT && workingDirectory) {
|
||||
ensureProjectAgentDir(workingDirectory);
|
||||
targetPath = projectPath;
|
||||
targetScope = AGENT_SCOPE.PROJECT;
|
||||
} else {
|
||||
targetPath = userPath;
|
||||
targetScope = AGENT_SCOPE.USER;
|
||||
}
|
||||
|
||||
const { prompt, scope: _scopeFromConfig, ...frontmatter } = config;
|
||||
|
||||
writeMdFile(targetPath, frontmatter, prompt || '');
|
||||
console.log(`Created new agent: ${agentName} (scope: ${targetScope}, path: ${targetPath})`);
|
||||
}
|
||||
|
||||
function updateAgent(agentName, updates, workingDirectory) {
|
||||
ensureDirs();
|
||||
|
||||
const { scope, path: mdPath } = getAgentWritePath(agentName, workingDirectory);
|
||||
const mdExists = mdPath && fs.existsSync(mdPath);
|
||||
|
||||
const layers = readConfigLayers(workingDirectory);
|
||||
const jsonSource = getJsonEntrySource(layers, 'agent', agentName);
|
||||
const jsonSection = jsonSource.section;
|
||||
const hasJsonFields = jsonSource.exists && jsonSection && Object.keys(jsonSection).length > 0;
|
||||
const jsonTarget = jsonSource.exists
|
||||
? { config: jsonSource.config, path: jsonSource.path }
|
||||
: getJsonWriteTarget(layers, AGENT_SCOPE.USER);
|
||||
let config = jsonTarget.config || {};
|
||||
|
||||
const isBuiltinOverride = !mdExists && !hasJsonFields;
|
||||
|
||||
let targetPath = mdPath;
|
||||
let targetScope = scope;
|
||||
|
||||
if (!mdExists && isBuiltinOverride) {
|
||||
targetPath = getUserAgentPath(agentName);
|
||||
targetScope = AGENT_SCOPE.USER;
|
||||
}
|
||||
|
||||
let mdData = mdExists ? parseMdFile(mdPath) : (isBuiltinOverride ? { frontmatter: {}, body: '' } : null);
|
||||
|
||||
let mdModified = false;
|
||||
let jsonModified = false;
|
||||
const creatingNewMd = isBuiltinOverride;
|
||||
|
||||
for (const [field, value] of Object.entries(updates)) {
|
||||
if (field === 'prompt') {
|
||||
const normalizedValue = typeof value === 'string' ? value : (value == null ? '' : String(value));
|
||||
|
||||
if (mdExists || creatingNewMd) {
|
||||
if (mdData) {
|
||||
mdData.body = normalizedValue;
|
||||
mdModified = true;
|
||||
}
|
||||
continue;
|
||||
} else if (isPromptFileReference(jsonSection?.prompt)) {
|
||||
const promptFilePath = resolvePromptFilePath(jsonSection.prompt);
|
||||
if (!promptFilePath) {
|
||||
throw new Error(`Invalid prompt file reference for agent ${agentName}`);
|
||||
}
|
||||
writePromptFile(promptFilePath, normalizedValue);
|
||||
continue;
|
||||
} else if (isPromptFileReference(normalizedValue)) {
|
||||
if (!config.agent) config.agent = {};
|
||||
if (!config.agent[agentName]) config.agent[agentName] = {};
|
||||
config.agent[agentName].prompt = normalizedValue;
|
||||
jsonModified = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!config.agent) config.agent = {};
|
||||
if (!config.agent[agentName]) config.agent[agentName] = {};
|
||||
config.agent[agentName].prompt = normalizedValue;
|
||||
jsonModified = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (field === 'permission') {
|
||||
const permissionSource = getAgentPermissionSource(agentName, workingDirectory);
|
||||
const newPermission = mergePermissionWithNonWildcards(value, permissionSource, agentName);
|
||||
|
||||
if (permissionSource.source === 'md') {
|
||||
const existingMdData = parseMdFile(permissionSource.path);
|
||||
existingMdData.frontmatter.permission = newPermission;
|
||||
writeMdFile(permissionSource.path, existingMdData.frontmatter, existingMdData.body);
|
||||
console.log(`Updated permission in .md file: ${permissionSource.path}`);
|
||||
} else if (permissionSource.source === 'json') {
|
||||
const existingConfig = readConfigFile(permissionSource.path);
|
||||
if (!existingConfig.agent) existingConfig.agent = {};
|
||||
if (!existingConfig.agent[agentName]) existingConfig.agent[agentName] = {};
|
||||
existingConfig.agent[agentName].permission = newPermission;
|
||||
writeConfig(existingConfig, permissionSource.path);
|
||||
console.log(`Updated permission in JSON: ${permissionSource.path}`);
|
||||
} else {
|
||||
if ((mdExists || creatingNewMd) && mdData) {
|
||||
mdData.frontmatter.permission = newPermission;
|
||||
mdModified = true;
|
||||
} else if (hasJsonFields) {
|
||||
if (!config.agent) config.agent = {};
|
||||
if (!config.agent[agentName]) config.agent[agentName] = {};
|
||||
config.agent[agentName].permission = newPermission;
|
||||
jsonModified = true;
|
||||
} else {
|
||||
const writeTarget = workingDirectory
|
||||
? { config: layers.projectConfig || {}, path: layers.paths.projectPath || layers.paths.userPath }
|
||||
: { config: layers.userConfig || {}, path: layers.paths.userPath };
|
||||
if (!writeTarget.config.agent) writeTarget.config.agent = {};
|
||||
if (!writeTarget.config.agent[agentName]) writeTarget.config.agent[agentName] = {};
|
||||
writeTarget.config.agent[agentName].permission = newPermission;
|
||||
writeConfig(writeTarget.config, writeTarget.path);
|
||||
console.log(`Created permission in JSON: ${writeTarget.path}`);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const inMd = mdData?.frontmatter?.[field] !== undefined;
|
||||
const inJson = jsonSection?.[field] !== undefined;
|
||||
|
||||
if (value === null) {
|
||||
if (mdData && inMd) {
|
||||
delete mdData.frontmatter[field];
|
||||
mdModified = true;
|
||||
}
|
||||
|
||||
if (inJson && config.agent?.[agentName]) {
|
||||
delete config.agent[agentName][field];
|
||||
|
||||
if (Object.keys(config.agent[agentName]).length === 0) {
|
||||
delete config.agent[agentName];
|
||||
}
|
||||
if (Object.keys(config.agent).length === 0) {
|
||||
delete config.agent;
|
||||
}
|
||||
|
||||
jsonModified = true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inJson) {
|
||||
if (!config.agent) config.agent = {};
|
||||
if (!config.agent[agentName]) config.agent[agentName] = {};
|
||||
config.agent[agentName][field] = value;
|
||||
jsonModified = true;
|
||||
} else if (inMd || creatingNewMd) {
|
||||
if (mdData) {
|
||||
mdData.frontmatter[field] = value;
|
||||
mdModified = true;
|
||||
}
|
||||
} else {
|
||||
if ((mdExists || creatingNewMd) && mdData) {
|
||||
mdData.frontmatter[field] = value;
|
||||
mdModified = true;
|
||||
} else {
|
||||
if (!config.agent) config.agent = {};
|
||||
if (!config.agent[agentName]) config.agent[agentName] = {};
|
||||
config.agent[agentName][field] = value;
|
||||
jsonModified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mdModified && mdData) {
|
||||
writeMdFile(targetPath, mdData.frontmatter, mdData.body);
|
||||
}
|
||||
|
||||
if (jsonModified) {
|
||||
writeConfig(config, jsonTarget.path || CONFIG_FILE);
|
||||
}
|
||||
|
||||
console.log(`Updated agent: ${agentName} (scope: ${targetScope}, md: ${mdModified}, json: ${jsonModified})`);
|
||||
}
|
||||
|
||||
function deleteAgent(agentName, workingDirectory) {
|
||||
let deleted = false;
|
||||
|
||||
if (workingDirectory) {
|
||||
const projectPath = getProjectAgentPath(workingDirectory, agentName);
|
||||
if (fs.existsSync(projectPath)) {
|
||||
fs.unlinkSync(projectPath);
|
||||
console.log(`Deleted project-level agent .md file: ${projectPath}`);
|
||||
deleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
const userPath = getUserAgentPath(agentName);
|
||||
if (fs.existsSync(userPath)) {
|
||||
fs.unlinkSync(userPath);
|
||||
console.log(`Deleted user-level agent .md file: ${userPath}`);
|
||||
deleted = true;
|
||||
}
|
||||
|
||||
const layers = readConfigLayers(workingDirectory);
|
||||
const jsonSource = getJsonEntrySource(layers, 'agent', agentName);
|
||||
if (jsonSource.exists && jsonSource.config && jsonSource.path) {
|
||||
if (!jsonSource.config.agent) jsonSource.config.agent = {};
|
||||
delete jsonSource.config.agent[agentName];
|
||||
writeConfig(jsonSource.config, jsonSource.path);
|
||||
console.log(`Removed agent from opencode.json: ${agentName}`);
|
||||
deleted = true;
|
||||
}
|
||||
|
||||
if (!deleted) {
|
||||
const jsonTarget = getJsonWriteTarget(layers, workingDirectory ? AGENT_SCOPE.PROJECT : AGENT_SCOPE.USER);
|
||||
const targetConfig = jsonTarget.config || {};
|
||||
if (!targetConfig.agent) targetConfig.agent = {};
|
||||
targetConfig.agent[agentName] = { disable: true };
|
||||
writeConfig(targetConfig, jsonTarget.path || CONFIG_FILE);
|
||||
console.log(`Disabled built-in agent: ${agentName}`);
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
ensureProjectAgentDir,
|
||||
getProjectAgentPath,
|
||||
getUserAgentPath,
|
||||
getAgentScope,
|
||||
getAgentWritePath,
|
||||
getAgentPermissionSource,
|
||||
getAgentSources,
|
||||
getAgentConfig,
|
||||
createAgent,
|
||||
updateAgent,
|
||||
deleteAgent,
|
||||
};
|
||||
Reference in New Issue
Block a user