import fs from "node:fs"; import path from "node:path"; import type { OpenClawPluginApi } from "openclaw/plugin-sdk"; import type { ChannelPolicy, DirigentConfig } from "../rules.js"; export type PolicyState = { filePath: string; channelPolicies: Record; }; export const policyState: PolicyState = { filePath: "", channelPolicies: {}, }; export function resolvePoliciesPath(api: OpenClawPluginApi, config: DirigentConfig): string { return api.resolvePath(config.channelPoliciesFile || "~/.openclaw/dirigent-channel-policies.json"); } export function ensurePolicyStateLoaded(api: OpenClawPluginApi, config: DirigentConfig): void { if (policyState.filePath) return; const filePath = resolvePoliciesPath(api, config); policyState.filePath = filePath; try { if (!fs.existsSync(filePath)) { fs.mkdirSync(path.dirname(filePath), { recursive: true }); fs.writeFileSync(filePath, "{}\n", "utf8"); policyState.channelPolicies = {}; return; } const raw = fs.readFileSync(filePath, "utf8"); const parsed = JSON.parse(raw) as Record; policyState.channelPolicies = parsed && typeof parsed === "object" ? parsed : {}; } catch (err) { api.logger.warn(`dirigent: failed init policy file ${filePath}: ${String(err)}`); policyState.channelPolicies = {}; } } export function persistPolicies(api: OpenClawPluginApi): void { if (!policyState.filePath) throw new Error("policy state not initialized"); const dir = path.dirname(policyState.filePath); fs.mkdirSync(dir, { recursive: true }); const tmp = `${policyState.filePath}.tmp`; fs.writeFileSync(tmp, `${JSON.stringify(policyState.channelPolicies, null, 2)}\n`, "utf8"); fs.renameSync(tmp, policyState.filePath); api.logger.info(`dirigent: policy file updated at ${policyState.filePath}`); }