@alfe.ai/integrations 0.1.0 → 0.1.2

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
@@ -293,19 +293,16 @@ declare class McpApplier {
293
293
  * (the manager preserves `addedAt`). Returns the list of ids that
294
294
  * actually landed in the store.
295
295
  *
296
- * Awaits `manager.flush()` before returning so the openclaw.json
297
- * mirror write has fired by the time the caller proceeds. Without
298
- * this, an integration activation's success ack would race ahead of
299
- * the runtime's openclaw.json update — the cloud would see
300
- * `actual.status = active` while OpenClaw still has the stale MCP
301
- * set in memory, violating the actual-status protocol contract.
296
+ * Store writes are durable before each `manager.addServer` resolves,
297
+ * so the caller can ack the activation as soon as this returns —
298
+ * the daemon-hosted bundler will pick the change up via the store
299
+ * watcher and reconcile its children.
302
300
  */
303
301
  applyForIntegration(integrationId: string, servers: McpServerDeclaration[], mergedConfig: Record<string, unknown>): Promise<string[]>;
304
302
  /**
305
- * Drop every entry owned by this integration. Like `applyForIntegration`,
306
- * awaits the mirror flush so the runtime is signalled before the call
307
- * resolves the uninstall ack shouldn't outrun openclaw.json being
308
- * cleaned up.
303
+ * Drop every entry owned by this integration. Store writes are
304
+ * durable before `removeServersByOwner` resolves; the daemon's
305
+ * bundler reconciles via the store watcher.
309
306
  */
310
307
  removeForIntegration(integrationId: string): Promise<string[]>;
311
308
  private resolveEnv;
package/dist/index.js CHANGED
@@ -1162,6 +1162,13 @@ var IntegrationManager = class {
1162
1162
  this.log.info(`Deactivating integration: ${integrationId}`);
1163
1163
  try {
1164
1164
  const removed = this.lockManager.removeEntries(integrationId);
1165
+ const remaining = this.lockManager.read();
1166
+ const claimedPluginsByRuntime = /* @__PURE__ */ new Map();
1167
+ const claimedSkillsByRuntime = /* @__PURE__ */ new Map();
1168
+ for (const [rtName, state] of Object.entries(remaining.runtimes)) {
1169
+ claimedPluginsByRuntime.set(rtName, new Set(state.plugins.map((p) => p.package)));
1170
+ claimedSkillsByRuntime.set(rtName, new Set(state.skills.map((s) => s.name)));
1171
+ }
1165
1172
  for (const [runtimeName, entries] of Object.entries(removed)) {
1166
1173
  const applier = this.runtimeAppliers.get(runtimeName);
1167
1174
  if (!applier) {
@@ -1172,7 +1179,13 @@ var IntegrationManager = class {
1172
1179
  this.log.warn(`Runtime "${runtimeName}" is not available — skipping removal`);
1173
1180
  continue;
1174
1181
  }
1182
+ const keepPlugins = claimedPluginsByRuntime.get(runtimeName) ?? /* @__PURE__ */ new Set();
1183
+ const keepSkills = claimedSkillsByRuntime.get(runtimeName) ?? /* @__PURE__ */ new Set();
1175
1184
  for (const plugin of entries.plugins) {
1185
+ if (keepPlugins.has(plugin.package)) {
1186
+ this.log.info(`Keeping plugin ${plugin.package} on ${runtimeName} — still claimed by another active integration`);
1187
+ continue;
1188
+ }
1176
1189
  this.log.info(`Removing plugin ${plugin.package} from ${runtimeName}`);
1177
1190
  try {
1178
1191
  await applier.removePlugin(plugin.package);
@@ -1181,6 +1194,10 @@ var IntegrationManager = class {
1181
1194
  }
1182
1195
  }
1183
1196
  for (const skill of entries.skills) {
1197
+ if (keepSkills.has(skill.name)) {
1198
+ this.log.info(`Keeping skill ${skill.name} on ${runtimeName} — still claimed by another active integration`);
1199
+ continue;
1200
+ }
1184
1201
  this.log.info(`Removing skill ${skill.name} from ${runtimeName}`);
1185
1202
  try {
1186
1203
  if (skill.sourcePath.startsWith("clawhub:")) await applier.removeClawHubSkill(skill.name);
@@ -1901,12 +1918,10 @@ var McpApplier = class {
1901
1918
  * (the manager preserves `addedAt`). Returns the list of ids that
1902
1919
  * actually landed in the store.
1903
1920
  *
1904
- * Awaits `manager.flush()` before returning so the openclaw.json
1905
- * mirror write has fired by the time the caller proceeds. Without
1906
- * this, an integration activation's success ack would race ahead of
1907
- * the runtime's openclaw.json update — the cloud would see
1908
- * `actual.status = active` while OpenClaw still has the stale MCP
1909
- * set in memory, violating the actual-status protocol contract.
1921
+ * Store writes are durable before each `manager.addServer` resolves,
1922
+ * so the caller can ack the activation as soon as this returns —
1923
+ * the daemon-hosted bundler will pick the change up via the store
1924
+ * watcher and reconcile its children.
1910
1925
  */
1911
1926
  async applyForIntegration(integrationId, servers, mergedConfig) {
1912
1927
  const owner = `integration:${integrationId}`;
@@ -1928,20 +1943,16 @@ var McpApplier = class {
1928
1943
  });
1929
1944
  applied.push(id);
1930
1945
  }
1931
- await this.manager.flush();
1932
1946
  return applied;
1933
1947
  }
1934
1948
  /**
1935
- * Drop every entry owned by this integration. Like `applyForIntegration`,
1936
- * awaits the mirror flush so the runtime is signalled before the call
1937
- * resolves the uninstall ack shouldn't outrun openclaw.json being
1938
- * cleaned up.
1949
+ * Drop every entry owned by this integration. Store writes are
1950
+ * durable before `removeServersByOwner` resolves; the daemon's
1951
+ * bundler reconciles via the store watcher.
1939
1952
  */
1940
1953
  async removeForIntegration(integrationId) {
1941
1954
  const owner = `integration:${integrationId}`;
1942
- const removed = await this.manager.removeServersByOwner(owner);
1943
- await this.manager.flush();
1944
- return removed;
1955
+ return this.manager.removeServersByOwner(owner);
1945
1956
  }
1946
1957
  async resolveEnv(server, mergedConfig) {
1947
1958
  if (!server.env || Object.keys(server.env).length === 0) return {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfe.ai/integrations",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Integration lifecycle management for Alfe — registry, resolution, installation, and state",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -13,8 +13,8 @@
13
13
  },
14
14
  "dependencies": {
15
15
  "@auriclabs/logger": "^0.1.1",
16
- "@alfe.ai/integration-manifest": "^0.1.0",
17
- "@alfe.ai/mcp-bundler": "^0.1.0"
16
+ "@alfe.ai/integration-manifest": "^0.2.0",
17
+ "@alfe.ai/mcp-bundler": "^0.2.0"
18
18
  },
19
19
  "files": [
20
20
  "dist"