openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
99 lines (98 loc) • 3.91 kB
JavaScript
import { t as sanitizeForLog } from "./ansi-BI9w76Cm.js";
import { n as parseToolsBySenderTypedKey } from "./types.tools-2c_JFIK0.js";
import { t as asObjectRecord } from "./object-BsiS9JXh.js";
import { a as resolveConfigPathTarget, t as formatConfigPath } from "./doctor-config-analysis-BUgmtVDJ.js";
//#region src/commands/doctor/shared/legacy-tools-by-sender.ts
function collectLegacyToolsBySenderKeyHits(value, pathParts, hits) {
if (Array.isArray(value)) {
for (const [index, entry] of value.entries()) collectLegacyToolsBySenderKeyHits(entry, [...pathParts, index], hits);
return;
}
const record = asObjectRecord(value);
if (!record) return;
const toolsBySender = asObjectRecord(record.toolsBySender);
if (toolsBySender) {
const path = [...pathParts, "toolsBySender"];
const pathLabel = formatConfigPath(path);
for (const rawKey of Object.keys(toolsBySender)) {
const trimmed = rawKey.trim();
if (!trimmed || trimmed === "*" || parseToolsBySenderTypedKey(trimmed)) continue;
hits.push({
toolsBySenderPath: path,
pathLabel,
key: rawKey,
targetKey: `id:${trimmed}`
});
}
}
for (const [key, nested] of Object.entries(record)) {
if (key === "toolsBySender") continue;
collectLegacyToolsBySenderKeyHits(nested, [...pathParts, key], hits);
}
}
/** Find untyped toolsBySender keys that should be migrated to explicit id: keys. */
function scanLegacyToolsBySenderKeys(cfg) {
const hits = [];
collectLegacyToolsBySenderKeyHits(cfg, [], hits);
return hits;
}
/** Format doctor warnings for legacy untyped toolsBySender keys. */
function collectLegacyToolsBySenderWarnings(params) {
if (params.hits.length === 0) return [];
const sample = params.hits[0];
const sampleLabel = sanitizeForLog(sample ? `${sample.pathLabel}.${sample.key}` : "toolsBySender");
return [
`- Found ${params.hits.length} legacy untyped toolsBySender key${params.hits.length === 1 ? "" : "s"} (for example ${sampleLabel}).`,
"- Untyped sender keys are deprecated; use explicit prefixes (id:, e164:, username:, name:).",
`- Run "${params.doctorFixCommand}" to migrate legacy keys to typed id: entries.`
];
}
/** Migrate untyped toolsBySender keys to typed id: keys where possible. */
function maybeRepairLegacyToolsBySenderKeys(cfg) {
const hits = scanLegacyToolsBySenderKeys(cfg);
if (hits.length === 0) return {
config: cfg,
changes: []
};
const next = structuredClone(cfg);
const summary = /* @__PURE__ */ new Map();
let changed = false;
for (const hit of hits) {
const toolsBySender = asObjectRecord(resolveConfigPathTarget(next, hit.toolsBySenderPath));
if (!toolsBySender || !(hit.key in toolsBySender)) continue;
const row = summary.get(hit.pathLabel) ?? {
migrated: 0,
dropped: 0,
examples: []
};
if (toolsBySender[hit.targetKey] === void 0) {
toolsBySender[hit.targetKey] = toolsBySender[hit.key];
row.migrated++;
if (row.examples.length < 3) row.examples.push(`${hit.key} -> ${hit.targetKey}`);
} else {
row.dropped++;
if (row.examples.length < 3) row.examples.push(`${hit.key} (kept existing ${hit.targetKey})`);
}
delete toolsBySender[hit.key];
summary.set(hit.pathLabel, row);
changed = true;
}
if (!changed) return {
config: cfg,
changes: []
};
const changes = [];
for (const [pathLabel, row] of summary) {
if (row.migrated > 0) {
const suffix = row.examples.length > 0 ? ` (${row.examples.join(", ")})` : "";
changes.push(`- ${pathLabel}: migrated ${row.migrated} legacy key${row.migrated === 1 ? "" : "s"} to typed id: entries${suffix}.`);
}
if (row.dropped > 0) changes.push(`- ${pathLabel}: removed ${row.dropped} legacy key${row.dropped === 1 ? "" : "s"} where typed id: entries already existed.`);
}
return {
config: next,
changes
};
}
//#endregion
export { maybeRepairLegacyToolsBySenderKeys as n, scanLegacyToolsBySenderKeys as r, collectLegacyToolsBySenderWarnings as t };