@alfe.ai/integrations 0.0.6 → 0.0.8

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.d.ts CHANGED
@@ -614,6 +614,17 @@ declare class OpenClawApplier implements RuntimeApplier {
614
614
  private configPath;
615
615
  constructor(options: OpenClawApplierOptions);
616
616
  applyPlugin(pkg: string): Promise<void>;
617
+ /**
618
+ * Ensure the plugin is in plugins.allow in openclaw.json.
619
+ * When we skip `openclaw plugins install` (because the plugin dir exists),
620
+ * the allowlist may not include the plugin — add it if missing.
621
+ */
622
+ private ensurePluginsAllow;
623
+ /**
624
+ * Check if a plugin is already installed in ~/.openclaw/extensions/.
625
+ * OpenClaw names extension dirs as {pkg-name-with-dashes}-{hash}.
626
+ */
627
+ private isPluginInstalled;
617
628
  removePlugin(pkg: string): Promise<void>;
618
629
  applySkill(name: string, srcPath: string): Promise<void>;
619
630
  removeSkill(name: string): Promise<void>;
package/dist/index.js CHANGED
@@ -662,6 +662,21 @@ async function runHookWithContext(integrationPath, hookScript, options) {
662
662
  * plugins/skills to runtimes. deactivate() removes them.
663
663
  */
664
664
  /**
665
+ * Deep-walk an object and replace `{{config.KEY}}` patterns with values
666
+ * from the per-agent config. Used to compose manifest runtime config
667
+ * with per-agent secrets (e.g., gateway token).
668
+ */
669
+ function interpolateSelfConfig(obj, config) {
670
+ const result = {};
671
+ for (const [key, value] of Object.entries(obj)) if (typeof value === "string") result[key] = value.replace(/\{\{config\.([a-zA-Z0-9_]+)\}\}/g, (_match, configKey) => {
672
+ const val = config[configKey];
673
+ return typeof val === "string" || typeof val === "number" ? String(val) : _match;
674
+ });
675
+ else if (value && typeof value === "object" && !Array.isArray(value)) result[key] = interpolateSelfConfig(value, config);
676
+ else result[key] = value;
677
+ return result;
678
+ }
679
+ /**
665
680
  * Merge universal installs with runtime-specific installs from the manifest.
666
681
  */
667
682
  function resolveInstallsForRuntime(manifest, runtime) {
@@ -871,8 +886,10 @@ var IntegrationManager = class {
871
886
  await applier.applySkill(skillName, srcPath);
872
887
  }
873
888
  if (runtimeConfig && Object.keys(runtimeConfig).length > 0) {
889
+ const agentConfig = entry.config;
890
+ const interpolatedConfig = interpolateSelfConfig(runtimeConfig, agentConfig);
874
891
  this.log.info(`Applying config for ${integrationId} to ${runtimeName}`);
875
- await applier.applyConfig(integrationId, runtimeConfig);
892
+ await applier.applyConfig(integrationId, interpolatedConfig);
876
893
  }
877
894
  if (plugins.length > 0 || skills.length > 0) this.lockManager.addEntries(runtimeName, integrationId, manifest.version, plugins, skills, installPath);
878
895
  }
@@ -1193,16 +1210,51 @@ var OpenClawApplier = class {
1193
1210
  this.configPath = options.configPath ?? join(this.workspace, "config.json");
1194
1211
  }
1195
1212
  async applyPlugin(pkg) {
1213
+ if (this.isPluginInstalled(pkg)) {
1214
+ this.ensurePluginsAllow(pkg);
1215
+ return;
1216
+ }
1196
1217
  await execFileAsync("openclaw", [
1197
1218
  "plugins",
1198
1219
  "install",
1199
1220
  pkg
1200
1221
  ], { timeout: 6e4 });
1201
1222
  }
1223
+ /**
1224
+ * Ensure the plugin is in plugins.allow in openclaw.json.
1225
+ * When we skip `openclaw plugins install` (because the plugin dir exists),
1226
+ * the allowlist may not include the plugin — add it if missing.
1227
+ */
1228
+ ensurePluginsAllow(pkg) {
1229
+ const configPath = join(homedir(), ".openclaw", "openclaw.json");
1230
+ if (!existsSync(configPath)) return;
1231
+ try {
1232
+ const raw = readFileSync(configPath, "utf-8");
1233
+ const config = JSON.parse(raw);
1234
+ const plugins = config.plugins ?? {};
1235
+ const allow = plugins.allow ?? [];
1236
+ if (!allow.includes(pkg)) {
1237
+ plugins.allow = [...allow, pkg];
1238
+ config.plugins = plugins;
1239
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
1240
+ }
1241
+ } catch {}
1242
+ }
1243
+ /**
1244
+ * Check if a plugin is already installed in ~/.openclaw/extensions/.
1245
+ * OpenClaw names extension dirs as {pkg-name-with-dashes}-{hash}.
1246
+ */
1247
+ isPluginInstalled(pkg) {
1248
+ const extensionsDir = join(homedir(), ".openclaw", "extensions");
1249
+ if (!existsSync(extensionsDir)) return false;
1250
+ const prefix = pkg.replaceAll("/", "-");
1251
+ return readdirSync(extensionsDir).some((dir) => dir.startsWith(prefix));
1252
+ }
1202
1253
  async removePlugin(pkg) {
1203
1254
  await execFileAsync("openclaw", [
1204
1255
  "plugins",
1205
1256
  "uninstall",
1257
+ "--force",
1206
1258
  pkg
1207
1259
  ], { timeout: 3e4 });
1208
1260
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfe.ai/integrations",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "Integration lifecycle management for Alfe — registry, resolution, installation, and state",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",