@alfe.ai/integrations 0.0.21 → 0.0.23

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
@@ -380,6 +380,8 @@ interface RuntimeApplier {
380
380
  applySkill(name: string, srcPath: string): Promise<void>;
381
381
  /** Install a skill from ClawHub registry */
382
382
  applyClawHubSkill(slug: string): Promise<void>;
383
+ /** Remove a ClawHub-installed skill from this runtime */
384
+ removeClawHubSkill(slug: string): Promise<void>;
383
385
  /** Remove a skill directory from this runtime */
384
386
  removeSkill(name: string): Promise<void>;
385
387
  /** Deep-merge config into the runtime's agent configuration */
@@ -533,6 +535,11 @@ declare class IntegrationManager {
533
535
  * List all installed integrations.
534
536
  */
535
537
  list(): IntegrationInfo[];
538
+ /**
539
+ * Check if an integration's install directory and manifest file exist on disk.
540
+ * Returns false if the state says installed but files are missing (corrupted install).
541
+ */
542
+ isInstallIntact(integrationId: string): boolean;
536
543
  /**
537
544
  * Get a specific integration by name.
538
545
  */
@@ -715,6 +722,7 @@ declare class OpenClawApplier implements RuntimeApplier {
715
722
  removePlugin(pkg: string): Promise<void>;
716
723
  applySkill(name: string, srcPath: string): Promise<void>;
717
724
  applyClawHubSkill(slug: string): Promise<void>;
725
+ removeClawHubSkill(slug: string): Promise<void>;
718
726
  removeSkill(name: string): Promise<void>;
719
727
  /**
720
728
  * Apply integration config to the OpenClaw runtime via `openclaw config set`.
@@ -812,6 +820,8 @@ interface IIntegrationManager {
812
820
  reinstall(integrationId: string, version: string, config: unknown): Promise<{
813
821
  configApplied: boolean;
814
822
  }>;
823
+ /** Check if an integration's install directory and manifest are intact on disk */
824
+ isInstallIntact(integrationId: string): Promise<boolean>;
815
825
  }
816
826
  declare class IntegrationManagerAdapter implements IIntegrationManager {
817
827
  private readonly manager;
@@ -831,6 +841,7 @@ declare class IntegrationManagerAdapter implements IIntegrationManager {
831
841
  reinstall(integrationId: string, version: string, config: unknown): Promise<{
832
842
  configApplied: boolean;
833
843
  }>;
844
+ isInstallIntact(integrationId: string): Promise<boolean>;
834
845
  }
835
846
  //#endregion
836
847
  export { type HookEnvOptions, type HookResult, type IIntegrationManager, type InstalledInfo, Installer, InstallerError, type IntegrationConfigureParams, type IntegrationHealthParams, type IntegrationInfo, type IntegrationInstallParams, IntegrationManager, IntegrationManagerAdapter, type IntegrationManagerOptions, type IntegrationRemoveParams, LockManager, OpenClawApplier, type OpenClawApplierOptions, Registry, type RegistryEntry, type RegistryFetcher, type RegistryIndex, RegistryResolveError, type ResolvedIntegration, Resolver, type RuntimeApplier, type RuntimeDesiredState, type RuntimeLockFile, type RuntimePluginEntry, type RuntimeSkillEntry, StateManager, buildHookEnv, resolveInstallsForRuntime, runHook, runHookWithContext };
package/dist/index.js CHANGED
@@ -855,7 +855,21 @@ var IntegrationManager = class {
855
855
  const { name, version, config } = params;
856
856
  if (!name) return this.err("INVALID_PARAMS", "Integration name is required");
857
857
  const existing = this.state.get(name);
858
- if (existing && existing.status !== "error") return this.err("ALREADY_INSTALLED", `Integration "${name}" is already installed (status: ${existing.status})`);
858
+ if (existing) {
859
+ if (existing.status === "installed" || existing.status === "configured" || existing.status === "active") {
860
+ this.log.info(`Integration "${name}" already installed (status: ${existing.status}) — skipping`);
861
+ return {
862
+ ok: true,
863
+ payload: {
864
+ id: name,
865
+ version: existing.version,
866
+ status: existing.status,
867
+ alreadyInstalled: true
868
+ }
869
+ };
870
+ }
871
+ if (existing.status === "installing") return this.err("ALREADY_INSTALLING", `Integration "${name}" is currently being installed`);
872
+ }
859
873
  this.log.info(`Installing integration: ${name}${version ? `@${version}` : ""}`);
860
874
  this.state.set(name, {
861
875
  status: "installing",
@@ -993,7 +1007,11 @@ var IntegrationManager = class {
993
1007
  try {
994
1008
  const installPath = this.installer.getInstallPath(integrationId);
995
1009
  const manifestPath = join(installPath, "alfe-integration.yaml");
996
- if (!existsSync(manifestPath)) return this.err("MANIFEST_MISSING", `Manifest not found at ${manifestPath}`);
1010
+ if (!existsSync(manifestPath)) {
1011
+ const errorMsg = `Manifest not found at ${manifestPath}`;
1012
+ this.state.setStatus(integrationId, "error", errorMsg);
1013
+ return this.err("MANIFEST_MISSING", errorMsg);
1014
+ }
997
1015
  const manifest = parseManifestFile(manifestPath);
998
1016
  let configApplied = false;
999
1017
  const supportedAgents = manifest.supported_agents;
@@ -1112,7 +1130,8 @@ var IntegrationManager = class {
1112
1130
  for (const skill of entries.skills) {
1113
1131
  this.log.info(`Removing skill ${skill.name} from ${runtimeName}`);
1114
1132
  try {
1115
- await applier.removeSkill(skill.name);
1133
+ if (skill.sourcePath.startsWith("clawhub:")) await applier.removeClawHubSkill(skill.name);
1134
+ else await applier.removeSkill(skill.name);
1116
1135
  } catch (err) {
1117
1136
  this.log.warn(`Failed to remove skill ${skill.name} from ${runtimeName}: ${err instanceof Error ? err.message : String(err)}`);
1118
1137
  }
@@ -1271,6 +1290,13 @@ var IntegrationManager = class {
1271
1290
  }));
1272
1291
  }
1273
1292
  /**
1293
+ * Check if an integration's install directory and manifest file exist on disk.
1294
+ * Returns false if the state says installed but files are missing (corrupted install).
1295
+ */
1296
+ isInstallIntact(integrationId) {
1297
+ return existsSync(join(this.installer.getInstallPath(integrationId), "alfe-integration.yaml"));
1298
+ }
1299
+ /**
1274
1300
  * Get a specific integration by name.
1275
1301
  */
1276
1302
  get(name) {
@@ -1506,15 +1532,30 @@ var OpenClawApplier = class {
1506
1532
  async applyClawHubSkill(slug) {
1507
1533
  log.info({ slug }, "Installing skill from ClawHub");
1508
1534
  try {
1509
- await execFileAsync("clawhub", ["install", slug], { timeout: 6e4 });
1535
+ await execFileAsync("openclaw", [
1536
+ "skills",
1537
+ "install",
1538
+ slug
1539
+ ], { timeout: 6e4 });
1510
1540
  log.info({ slug }, "ClawHub skill installed");
1511
1541
  } catch (err) {
1512
1542
  const msg = err instanceof Error ? err.message : String(err);
1513
- log.warn({
1543
+ log.error({
1514
1544
  slug,
1515
1545
  err: msg
1516
- }, "ClawHub skill install failed — clawhub CLI may not be available");
1546
+ }, "ClawHub skill install failed");
1547
+ }
1548
+ }
1549
+ removeClawHubSkill(slug) {
1550
+ const workspaceSkillsDir = join(this.workspace, "skills", slug);
1551
+ if (existsSync(workspaceSkillsDir)) {
1552
+ rmSync(workspaceSkillsDir, {
1553
+ recursive: true,
1554
+ force: true
1555
+ });
1556
+ log.info({ slug }, "ClawHub skill removed");
1517
1557
  }
1558
+ return Promise.resolve();
1518
1559
  }
1519
1560
  removeSkill(name) {
1520
1561
  const skillPath = join(this.skillsDir, name);
@@ -1644,6 +1685,9 @@ var IntegrationManagerAdapter = class {
1644
1685
  if (!result.ok) throw new Error(result.error?.message ?? `Failed to reinstall ${integrationId}`);
1645
1686
  return { configApplied: result.payload?.configApplied ?? false };
1646
1687
  }
1688
+ isInstallIntact(integrationId) {
1689
+ return Promise.resolve(this.manager.isInstallIntact(integrationId));
1690
+ }
1647
1691
  };
1648
1692
  //#endregion
1649
1693
  export { Installer, InstallerError, IntegrationManager, IntegrationManagerAdapter, LockManager, OpenClawApplier, Registry, RegistryResolveError, Resolver, StateManager, buildHookEnv, resolveInstallsForRuntime, runHook, runHookWithContext };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfe.ai/integrations",
3
- "version": "0.0.21",
3
+ "version": "0.0.23",
4
4
  "description": "Integration lifecycle management for Alfe — registry, resolution, installation, and state",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",