mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 05:02:07 +00:00
94 lines
2.8 KiB
TypeScript
94 lines
2.8 KiB
TypeScript
/**
|
|
* pi-channels — Config from pi SettingsManager.
|
|
*
|
|
* Reads the "pi-channels" key from settings via SettingsManager,
|
|
* which merges global (~/.pi/agent/settings.json) and project
|
|
* (.pi/settings.json) configs automatically.
|
|
*
|
|
* Example settings.json:
|
|
* {
|
|
* "pi-channels": {
|
|
* "adapters": {
|
|
* "telegram": {
|
|
* "type": "telegram",
|
|
* "botToken": "your-telegram-bot-token"
|
|
* },
|
|
* "slack": {
|
|
* "type": "slack"
|
|
* }
|
|
* },
|
|
* "slack": {
|
|
* "appToken": "xapp-...",
|
|
* "botToken": "xoxb-..."
|
|
* },
|
|
* "routes": {
|
|
* "ops": { "adapter": "telegram", "recipient": "-100987654321" }
|
|
* }
|
|
* }
|
|
* }
|
|
*/
|
|
|
|
import { getAgentDir, SettingsManager } from "@mariozechner/pi-coding-agent";
|
|
import type { ChannelConfig } from "./types.js";
|
|
|
|
const SETTINGS_KEY = "pi-channels";
|
|
|
|
export function loadConfig(cwd: string): ChannelConfig {
|
|
const agentDir = getAgentDir();
|
|
const sm = SettingsManager.create(cwd, agentDir);
|
|
const global = sm.getGlobalSettings() as Record<string, any>;
|
|
const project = sm.getProjectSettings() as Record<string, any>;
|
|
|
|
const globalCh = global?.[SETTINGS_KEY] ?? {};
|
|
const projectCh = project?.[SETTINGS_KEY] ?? {};
|
|
|
|
// Project overrides global (shallow merge of adapters + routes + bridge)
|
|
const merged: ChannelConfig = {
|
|
adapters: {
|
|
...(globalCh.adapters ?? {}),
|
|
...(projectCh.adapters ?? {}),
|
|
} as ChannelConfig["adapters"],
|
|
routes: {
|
|
...(globalCh.routes ?? {}),
|
|
...(projectCh.routes ?? {}),
|
|
},
|
|
bridge: {
|
|
...(globalCh.bridge ?? {}),
|
|
...(projectCh.bridge ?? {}),
|
|
} as ChannelConfig["bridge"],
|
|
};
|
|
|
|
return merged;
|
|
}
|
|
|
|
/**
|
|
* Read a setting from the "pi-channels" config by dotted key path.
|
|
* Useful for adapter-specific secrets that shouldn't live in the adapter config block.
|
|
*
|
|
* Example: getChannelSetting(cwd, "slack.appToken") reads pi-channels.slack.appToken
|
|
*/
|
|
export function getChannelSetting(cwd: string, keyPath: string): unknown {
|
|
const agentDir = getAgentDir();
|
|
const sm = SettingsManager.create(cwd, agentDir);
|
|
const global = sm.getGlobalSettings() as Record<string, any>;
|
|
const project = sm.getProjectSettings() as Record<string, any>;
|
|
|
|
const globalCh = global?.[SETTINGS_KEY] ?? {};
|
|
const projectCh = project?.[SETTINGS_KEY] ?? {};
|
|
|
|
// Walk the dotted path independently in each scope to avoid
|
|
// shallow-merge dropping sibling keys from nested objects.
|
|
function walk(obj: any): unknown {
|
|
let current: any = obj;
|
|
for (const part of keyPath.split(".")) {
|
|
if (current == null || typeof current !== "object") return undefined;
|
|
current = current[part];
|
|
}
|
|
return current;
|
|
}
|
|
|
|
// Project overrides global at the leaf level.
|
|
// Use explicit undefined check so null can be used to unset a global default.
|
|
const projectValue = walk(projectCh);
|
|
return projectValue !== undefined ? projectValue : walk(globalCh);
|
|
}
|