automagik-genie
Version:
Self-evolving AI agent orchestration framework with Model Context Protocol support
145 lines (144 loc) • 5.48 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.recordStartupWarning = recordStartupWarning;
exports.getStartupWarnings = getStartupWarnings;
exports.clearStartupWarnings = clearStartupWarnings;
exports.buildDefaultConfig = buildDefaultConfig;
exports.loadConfig = loadConfig;
exports.resolvePaths = resolvePaths;
exports.prepareDirectories = prepareDirectories;
exports.applyDefaults = applyDefaults;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const utils_1 = require("./utils");
const paths_1 = require("./paths");
let YAML = null;
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
YAML = require('yaml');
}
catch (_) {
// yaml module optional
}
const BASE_CONFIG = {
defaults: {
executor: 'OPENCODE',
executorVariant: 'DEFAULT',
background: false
},
paths: {
baseDir: undefined,
tasksFile: '.genie/state/tasks.json',
logsDir: '.genie/state/agents/logs',
backgroundDir: '.genie/state/agents/background'
},
forge: {
executors: {}
},
executionModes: {}
};
function resolveConfigPath() {
try {
const root = (0, paths_1.findWorkspaceRoot)();
const projectConfig = path_1.default.join(root, '.genie', 'config.yaml');
if (fs_1.default.existsSync(projectConfig))
return projectConfig;
}
catch (_) { }
return path_1.default.join(path_1.default.dirname(__dirname), 'config.yaml');
}
const CONFIG_PATH = resolveConfigPath();
const startupWarnings = [];
function recordStartupWarning(message) {
startupWarnings.push(message);
}
function getStartupWarnings() {
return [...startupWarnings];
}
function clearStartupWarnings() {
startupWarnings.length = 0;
}
function buildDefaultConfig() {
return (0, utils_1.deepClone)(BASE_CONFIG);
}
function loadConfig() {
let config = (0, utils_1.deepClone)(buildDefaultConfig());
const configFilePath = fs_1.default.existsSync(CONFIG_PATH) ? CONFIG_PATH : null;
if (configFilePath) {
try {
const raw = fs_1.default.readFileSync(configFilePath, 'utf8');
if (raw.trim().length) {
let parsed = {};
if (YAML) {
parsed = YAML.parse(raw) || {};
}
else if (raw.trim().startsWith('{')) {
try {
parsed = JSON.parse(raw);
}
catch {
parsed = {};
}
}
else {
recordStartupWarning('[genie] YAML module unavailable; ignoring config overrides. Install "yaml" to enable parsing.');
parsed = {};
}
config = (0, utils_1.mergeDeep)(config, parsed);
}
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(`Failed to parse ${configFilePath}: ${message}`);
}
config.__configPath = configFilePath;
}
else {
config.__configPath = CONFIG_PATH;
}
// Ensure defaults exist
config.defaults = config.defaults || {};
if (!config.defaults.executor)
config.defaults.executor = 'OPENCODE';
if (!config.defaults.executorVariant)
config.defaults.executorVariant = 'DEFAULT';
config.defaults.background = config.defaults.background ?? false;
config.forge = config.forge || { executors: {} };
config.forge.executors = config.forge.executors || {};
config.executionModes = config.executionModes || {};
return config;
}
function resolvePaths(paths) {
const baseDir = paths.baseDir ? path_1.default.resolve(paths.baseDir) : (0, paths_1.findWorkspaceRoot)();
const tasksFile = paths.tasksFile
? path_1.default.resolve(baseDir, paths.tasksFile)
: path_1.default.join(baseDir, '.genie/state/tasks.json');
return {
baseDir,
tasksFile,
logsDir: paths.logsDir || path_1.default.join(baseDir, '.genie/state/agents/logs'),
backgroundDir: paths.backgroundDir || path_1.default.join(baseDir, '.genie/state/agents/background')
};
}
function prepareDirectories(paths) {
[paths.logsDir, paths.backgroundDir, path_1.default.dirname(paths.tasksFile)].forEach((dir) => {
if (!fs_1.default.existsSync(dir)) {
fs_1.default.mkdirSync(dir, { recursive: true });
}
});
}
function applyDefaults(options, defaults) {
// Only apply config defaults if user hasn't explicitly set --background or --no-background
// The run command defaults to foreground (interactive) mode, so we don't force background: true
// Users can still pass --background to enable headless mode
if (!options.backgroundExplicit && defaults?.background !== undefined) {
// Respect explicit config override, but don't force background: true by default
// This allows the run command to default to foreground (interactive) mode
options.background = defaults.background;
}
// Note: if backgroundExplicit is false and defaults.background is undefined,
// options.background stays as initialized (false), enabling foreground mode
}