@alfe.ai/integrations 0.0.30 → 0.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +102 -19
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1509,18 +1509,63 @@ var IntegrationManager = class {
|
|
|
1509
1509
|
const execFileAsync = promisify(execFile);
|
|
1510
1510
|
const log = createLogger("OpenClawApplier");
|
|
1511
1511
|
const DEFAULT_SKILLS_DIR = join(homedir(), ".alfe", "skills");
|
|
1512
|
-
/**
|
|
1513
|
-
* Flatten a nested config object into dot-path key-value pairs.
|
|
1514
|
-
* e.g. { gateway: { bind: "lan" } } → [["gateway.bind", "lan"]]
|
|
1515
|
-
*/
|
|
1516
1512
|
function flattenConfig(obj, prefix = "") {
|
|
1517
|
-
const
|
|
1513
|
+
const entries = [];
|
|
1518
1514
|
for (const [key, val] of Object.entries(obj)) {
|
|
1515
|
+
if (key.includes(".")) {
|
|
1516
|
+
entries.push({
|
|
1517
|
+
kind: "subtree",
|
|
1518
|
+
parentPath: prefix,
|
|
1519
|
+
dottedKey: key,
|
|
1520
|
+
value: val
|
|
1521
|
+
});
|
|
1522
|
+
continue;
|
|
1523
|
+
}
|
|
1519
1524
|
const path = prefix ? `${prefix}.${key}` : key;
|
|
1520
|
-
if (val !== null && typeof val === "object" && !Array.isArray(val))
|
|
1521
|
-
else
|
|
1525
|
+
if (val !== null && typeof val === "object" && !Array.isArray(val)) entries.push(...flattenConfig(val, path));
|
|
1526
|
+
else entries.push({
|
|
1527
|
+
kind: "leaf",
|
|
1528
|
+
path,
|
|
1529
|
+
value: val
|
|
1530
|
+
});
|
|
1522
1531
|
}
|
|
1523
|
-
return
|
|
1532
|
+
return entries;
|
|
1533
|
+
}
|
|
1534
|
+
function partitionEntries(entries) {
|
|
1535
|
+
const leaves = [];
|
|
1536
|
+
const subtreesByParent = /* @__PURE__ */ new Map();
|
|
1537
|
+
for (const entry of entries) {
|
|
1538
|
+
if (entry.kind === "leaf") {
|
|
1539
|
+
leaves.push({
|
|
1540
|
+
path: entry.path,
|
|
1541
|
+
value: entry.value
|
|
1542
|
+
});
|
|
1543
|
+
continue;
|
|
1544
|
+
}
|
|
1545
|
+
if (!entry.parentPath) throw new Error(`OpenClawApplier: top-level config keys containing dots are not supported (key: "${entry.dottedKey}")`);
|
|
1546
|
+
let bucket = subtreesByParent.get(entry.parentPath);
|
|
1547
|
+
if (!bucket) {
|
|
1548
|
+
bucket = /* @__PURE__ */ new Map();
|
|
1549
|
+
subtreesByParent.set(entry.parentPath, bucket);
|
|
1550
|
+
}
|
|
1551
|
+
bucket.set(entry.dottedKey, entry.value);
|
|
1552
|
+
}
|
|
1553
|
+
return {
|
|
1554
|
+
leaves,
|
|
1555
|
+
subtreesByParent
|
|
1556
|
+
};
|
|
1557
|
+
}
|
|
1558
|
+
async function readParentObject(parentPath) {
|
|
1559
|
+
try {
|
|
1560
|
+
const { stdout } = await execFileAsync("openclaw", [
|
|
1561
|
+
"config",
|
|
1562
|
+
"get",
|
|
1563
|
+
parentPath
|
|
1564
|
+
], { timeout: 1e4 });
|
|
1565
|
+
const parsed = JSON.parse(stdout.trim());
|
|
1566
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
|
|
1567
|
+
} catch {}
|
|
1568
|
+
return {};
|
|
1524
1569
|
}
|
|
1525
1570
|
var OpenClawApplier = class {
|
|
1526
1571
|
runtime = "openclaw";
|
|
@@ -1623,8 +1668,8 @@ var OpenClawApplier = class {
|
|
|
1623
1668
|
* plugins under 2026.5+, which made force-mode skip its uninstall step.
|
|
1624
1669
|
*/
|
|
1625
1670
|
isPluginInstalled(pkg) {
|
|
1626
|
-
if (existsSync(join(
|
|
1627
|
-
const extensionsDir = join(
|
|
1671
|
+
if (existsSync(join(this.home, "npm", "node_modules", ...pkg.split("/")))) return true;
|
|
1672
|
+
const extensionsDir = join(this.home, "extensions");
|
|
1628
1673
|
if (!existsSync(extensionsDir)) return false;
|
|
1629
1674
|
const prefix = pkg.replaceAll("/", "-") + "-";
|
|
1630
1675
|
return readdirSync(extensionsDir).some((dir) => dir.startsWith(prefix) && /^[0-9a-f]+$/i.test(dir.slice(prefix.length)));
|
|
@@ -1695,21 +1740,36 @@ var OpenClawApplier = class {
|
|
|
1695
1740
|
integrations[integrationId] = config;
|
|
1696
1741
|
tracking._integrations = integrations;
|
|
1697
1742
|
this.writeTracking(tracking);
|
|
1698
|
-
const
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1743
|
+
const { leaves, subtreesByParent } = partitionEntries(flattenConfig(config));
|
|
1744
|
+
for (const [parentPath, dottedKvs] of subtreesByParent) {
|
|
1745
|
+
const merged = { ...await readParentObject(parentPath) };
|
|
1746
|
+
for (const [k, v] of dottedKvs) merged[k] = v;
|
|
1747
|
+
try {
|
|
1748
|
+
await execFileAsync("openclaw", [
|
|
1749
|
+
"config",
|
|
1750
|
+
"set",
|
|
1751
|
+
parentPath,
|
|
1752
|
+
JSON.stringify(merged)
|
|
1753
|
+
], { timeout: 1e4 });
|
|
1754
|
+
} catch (err) {
|
|
1755
|
+
log.error({
|
|
1756
|
+
err: err instanceof Error ? err.message : String(err),
|
|
1757
|
+
parentPath
|
|
1758
|
+
}, "Failed to set config subtree via openclaw config set");
|
|
1759
|
+
throw err;
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
if (leaves.length > 0) try {
|
|
1703
1763
|
await execFileAsync("openclaw", [
|
|
1704
1764
|
"config",
|
|
1705
1765
|
"set",
|
|
1706
1766
|
"--batch-json",
|
|
1707
|
-
JSON.stringify(
|
|
1767
|
+
JSON.stringify(leaves)
|
|
1708
1768
|
], { timeout: 1e4 });
|
|
1709
1769
|
} catch (err) {
|
|
1710
1770
|
log.error({
|
|
1711
1771
|
err: err instanceof Error ? err.message : String(err),
|
|
1712
|
-
batch
|
|
1772
|
+
batch: leaves
|
|
1713
1773
|
}, "Failed to set config via openclaw config set --batch-json");
|
|
1714
1774
|
throw err;
|
|
1715
1775
|
}
|
|
@@ -1725,8 +1785,8 @@ var OpenClawApplier = class {
|
|
|
1725
1785
|
const integrations = tracking._integrations ?? {};
|
|
1726
1786
|
if (!(integrationId in integrations)) return;
|
|
1727
1787
|
const integrationConfig = integrations[integrationId];
|
|
1728
|
-
const
|
|
1729
|
-
for (const
|
|
1788
|
+
const { leaves, subtreesByParent } = partitionEntries(flattenConfig(integrationConfig));
|
|
1789
|
+
for (const { path } of leaves) try {
|
|
1730
1790
|
await execFileAsync("openclaw", [
|
|
1731
1791
|
"config",
|
|
1732
1792
|
"unset",
|
|
@@ -1738,6 +1798,29 @@ var OpenClawApplier = class {
|
|
|
1738
1798
|
path
|
|
1739
1799
|
}, "Failed to unset config via openclaw config unset");
|
|
1740
1800
|
}
|
|
1801
|
+
for (const [parentPath, dottedKvs] of subtreesByParent) {
|
|
1802
|
+
const existing = await readParentObject(parentPath);
|
|
1803
|
+
const remaining = Object.fromEntries(Object.entries(existing).filter(([k]) => !dottedKvs.has(k)));
|
|
1804
|
+
if (Object.keys(existing).length === 0) continue;
|
|
1805
|
+
try {
|
|
1806
|
+
if (Object.keys(remaining).length === 0) await execFileAsync("openclaw", [
|
|
1807
|
+
"config",
|
|
1808
|
+
"unset",
|
|
1809
|
+
parentPath
|
|
1810
|
+
], { timeout: 1e4 });
|
|
1811
|
+
else await execFileAsync("openclaw", [
|
|
1812
|
+
"config",
|
|
1813
|
+
"set",
|
|
1814
|
+
parentPath,
|
|
1815
|
+
JSON.stringify(remaining)
|
|
1816
|
+
], { timeout: 1e4 });
|
|
1817
|
+
} catch (err) {
|
|
1818
|
+
log.warn({
|
|
1819
|
+
err: err instanceof Error ? err.message : String(err),
|
|
1820
|
+
parentPath
|
|
1821
|
+
}, "Failed to update parent config during remove");
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1741
1824
|
tracking._integrations = Object.fromEntries(Object.entries(integrations).filter(([key]) => key !== integrationId));
|
|
1742
1825
|
this.writeTracking(tracking);
|
|
1743
1826
|
}
|
package/package.json
CHANGED