@alfe.ai/integrations 0.0.25 → 0.0.27
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 +14 -3
- package/dist/index.js +41 -31
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -193,6 +193,11 @@ declare class Installer {
|
|
|
193
193
|
* Node module resolution from hook scripts (e.g.
|
|
194
194
|
* ~/.alfe/integrations/console/hooks/post_install.js) walks up to
|
|
195
195
|
* ~/.alfe/integrations/node_modules/ and finds these packages.
|
|
196
|
+
*
|
|
197
|
+
* Uses `"latest"` versions — npm install is always run when node_modules
|
|
198
|
+
* exists to pick up newer published versions (e.g. new API client methods).
|
|
199
|
+
* The in-memory `sharedPackagesReady` flag prevents redundant installs
|
|
200
|
+
* within a single daemon process lifetime.
|
|
196
201
|
*/
|
|
197
202
|
private ensureSharedPackages;
|
|
198
203
|
/**
|
|
@@ -389,7 +394,9 @@ interface RuntimeApplier {
|
|
|
389
394
|
/** The runtime identifier (e.g. 'openclaw', 'nanoclaw') */
|
|
390
395
|
readonly runtime: string;
|
|
391
396
|
/** Install a plugin package into this runtime */
|
|
392
|
-
applyPlugin(pkg: string, integrationInstallPath: string
|
|
397
|
+
applyPlugin(pkg: string, integrationInstallPath: string, opts?: {
|
|
398
|
+
force?: boolean;
|
|
399
|
+
}): Promise<void>;
|
|
393
400
|
/** Remove a plugin package from this runtime */
|
|
394
401
|
removePlugin(pkg: string): Promise<void>;
|
|
395
402
|
/** Copy a skill directory into this runtime's skills location */
|
|
@@ -517,7 +524,9 @@ declare class IntegrationManager {
|
|
|
517
524
|
* 4. Run health_check hook if present
|
|
518
525
|
* 5. Mark as active in state
|
|
519
526
|
*/
|
|
520
|
-
activate(integrationId: string
|
|
527
|
+
activate(integrationId: string, opts?: {
|
|
528
|
+
forcePlugins?: boolean;
|
|
529
|
+
}): Promise<ManagerResponse>;
|
|
521
530
|
/**
|
|
522
531
|
* Deactivate a running integration.
|
|
523
532
|
*
|
|
@@ -728,7 +737,9 @@ declare class OpenClawApplier implements RuntimeApplier {
|
|
|
728
737
|
private skillsDir;
|
|
729
738
|
private trackingPath;
|
|
730
739
|
constructor(options: OpenClawApplierOptions);
|
|
731
|
-
applyPlugin(pkg: string
|
|
740
|
+
applyPlugin(pkg: string, _installPath?: string, opts?: {
|
|
741
|
+
force?: boolean;
|
|
742
|
+
}): Promise<void>;
|
|
732
743
|
/**
|
|
733
744
|
* Ensure the plugin is in plugins.allow in openclaw.json.
|
|
734
745
|
* Uses `openclaw config set` to avoid clobbering OpenClaw's own file format.
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { execFile, spawn } from "node:child_process";
|
|
2
2
|
import { promisify } from "node:util";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
|
-
import { homedir, tmpdir } from "node:os";
|
|
4
|
+
import { homedir, platform, tmpdir } from "node:os";
|
|
5
5
|
import { closeSync, cpSync, existsSync, mkdirSync, mkdtempSync, openSync, readFileSync, readSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { buildConfigValidationSchema, parseManifestFile } from "@alfe.ai/integration-manifest";
|
|
7
7
|
import { createLogger } from "@auriclabs/logger";
|
|
@@ -276,24 +276,15 @@ var Installer = class {
|
|
|
276
276
|
* Node module resolution from hook scripts (e.g.
|
|
277
277
|
* ~/.alfe/integrations/console/hooks/post_install.js) walks up to
|
|
278
278
|
* ~/.alfe/integrations/node_modules/ and finds these packages.
|
|
279
|
+
*
|
|
280
|
+
* Uses `"latest"` versions — npm install is always run when node_modules
|
|
281
|
+
* exists to pick up newer published versions (e.g. new API client methods).
|
|
282
|
+
* The in-memory `sharedPackagesReady` flag prevents redundant installs
|
|
283
|
+
* within a single daemon process lifetime.
|
|
279
284
|
*/
|
|
280
285
|
async ensureSharedPackages() {
|
|
281
286
|
if (this.sharedPackagesReady) return;
|
|
282
287
|
const pkgJsonPath = join(this.basePath, "package.json");
|
|
283
|
-
const nodeModulesExists = existsSync(join(this.basePath, "node_modules"));
|
|
284
|
-
let needsInstall = false;
|
|
285
|
-
if (existsSync(pkgJsonPath)) try {
|
|
286
|
-
const deps = JSON.parse(readFileSync(pkgJsonPath, "utf-8")).dependencies ?? {};
|
|
287
|
-
needsInstall = Object.keys(SHARED_PACKAGES).some((pkg) => !(pkg in deps));
|
|
288
|
-
} catch {
|
|
289
|
-
needsInstall = true;
|
|
290
|
-
}
|
|
291
|
-
else needsInstall = true;
|
|
292
|
-
if (!needsInstall && !nodeModulesExists) needsInstall = true;
|
|
293
|
-
if (!needsInstall) {
|
|
294
|
-
this.sharedPackagesReady = true;
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
288
|
const pkgJson = {
|
|
298
289
|
name: "alfe-integrations-root",
|
|
299
290
|
private: true,
|
|
@@ -663,6 +654,7 @@ function buildHookEnv(options, additionalEnv) {
|
|
|
663
654
|
* 3. Default → "bash"
|
|
664
655
|
*/
|
|
665
656
|
function resolveInterpreter(scriptPath) {
|
|
657
|
+
const isWindows = platform() === "win32";
|
|
666
658
|
try {
|
|
667
659
|
const fd = openSync(scriptPath, "r");
|
|
668
660
|
const buf = Buffer.alloc(256);
|
|
@@ -678,8 +670,13 @@ function resolveInterpreter(scriptPath) {
|
|
|
678
670
|
args: [...parts.slice(1), scriptPath]
|
|
679
671
|
};
|
|
680
672
|
}
|
|
673
|
+
const cmd = shebang.split(/\s+/)[0];
|
|
674
|
+
if (isWindows && cmd.startsWith("/")) return {
|
|
675
|
+
command: cmd.split("/").pop() ?? cmd,
|
|
676
|
+
args: [scriptPath]
|
|
677
|
+
};
|
|
681
678
|
return {
|
|
682
|
-
command:
|
|
679
|
+
command: cmd,
|
|
683
680
|
args: [scriptPath]
|
|
684
681
|
};
|
|
685
682
|
}
|
|
@@ -689,7 +686,7 @@ function resolveInterpreter(scriptPath) {
|
|
|
689
686
|
args: [scriptPath]
|
|
690
687
|
};
|
|
691
688
|
if (scriptPath.endsWith(".py")) return {
|
|
692
|
-
command: "python3",
|
|
689
|
+
command: isWindows ? "python" : "python3",
|
|
693
690
|
args: [scriptPath]
|
|
694
691
|
};
|
|
695
692
|
return {
|
|
@@ -1010,7 +1007,7 @@ var IntegrationManager = class {
|
|
|
1010
1007
|
* 4. Run health_check hook if present
|
|
1011
1008
|
* 5. Mark as active in state
|
|
1012
1009
|
*/
|
|
1013
|
-
async activate(integrationId) {
|
|
1010
|
+
async activate(integrationId, opts) {
|
|
1014
1011
|
const entry = this.state.get(integrationId);
|
|
1015
1012
|
if (!entry) return this.err("NOT_FOUND", `Integration "${integrationId}" is not installed`);
|
|
1016
1013
|
if (entry.status === "active") return {
|
|
@@ -1046,7 +1043,7 @@ var IntegrationManager = class {
|
|
|
1046
1043
|
const { plugins, skills, config: runtimeConfig } = resolveInstallsForRuntime(manifest, runtimeName);
|
|
1047
1044
|
for (const plugin of plugins) {
|
|
1048
1045
|
this.log.info(`Applying plugin ${plugin.package} to ${runtimeName}`);
|
|
1049
|
-
await applier.applyPlugin(plugin.package, installPath);
|
|
1046
|
+
await applier.applyPlugin(plugin.package, installPath, { force: opts?.forcePlugins });
|
|
1050
1047
|
}
|
|
1051
1048
|
for (const skill of skills) if (skill.clawhub) {
|
|
1052
1049
|
this.log.info(`Installing ClawHub skill ${skill.clawhub} to ${runtimeName}`);
|
|
@@ -1064,7 +1061,7 @@ var IntegrationManager = class {
|
|
|
1064
1061
|
await applier.applyConfig(integrationId, interpolatedConfig);
|
|
1065
1062
|
configApplied = true;
|
|
1066
1063
|
}
|
|
1067
|
-
const mcpServers = manifest.mcp_servers;
|
|
1064
|
+
const mcpServers = manifest.mcp_servers ?? [];
|
|
1068
1065
|
if (mcpServers.length > 0) {
|
|
1069
1066
|
const secretEntries = this.secrets.get(integrationId);
|
|
1070
1067
|
const interpolatedServers = interpolateMcpServerEnvs(mcpServers, {
|
|
@@ -1116,6 +1113,7 @@ var IntegrationManager = class {
|
|
|
1116
1113
|
} catch (err) {
|
|
1117
1114
|
const message = err instanceof Error ? err.message : String(err);
|
|
1118
1115
|
this.log.error(`Failed to activate "${integrationId}": ${message}`);
|
|
1116
|
+
this.state.setStatus(integrationId, "error", message);
|
|
1119
1117
|
return this.err("ACTIVATE_FAILED", message);
|
|
1120
1118
|
}
|
|
1121
1119
|
}
|
|
@@ -1284,7 +1282,7 @@ var IntegrationManager = class {
|
|
|
1284
1282
|
if (!uninstallResult.ok) this.log.warn(`Uninstall returned error during reinstall: ${String(uninstallResult.error?.message)} — proceeding with install`);
|
|
1285
1283
|
const installResult = await this.install(params);
|
|
1286
1284
|
if (!installResult.ok) return installResult;
|
|
1287
|
-
return await this.activate(name);
|
|
1285
|
+
return await this.activate(name, { forcePlugins: true });
|
|
1288
1286
|
} catch (err) {
|
|
1289
1287
|
const message = err instanceof Error ? err.message : String(err);
|
|
1290
1288
|
this.log.error(`Failed to reinstall "${name}": ${message}`);
|
|
@@ -1364,11 +1362,11 @@ var IntegrationManager = class {
|
|
|
1364
1362
|
const manifestPath = join(installPath, "alfe-integration.yaml");
|
|
1365
1363
|
if (!existsSync(manifestPath)) continue;
|
|
1366
1364
|
try {
|
|
1367
|
-
const
|
|
1368
|
-
if (
|
|
1365
|
+
const commands = parseManifestFile(manifestPath).commands ?? [];
|
|
1366
|
+
if (commands.length === 0) continue;
|
|
1369
1367
|
result.push({
|
|
1370
1368
|
integrationId: entry.id,
|
|
1371
|
-
commands:
|
|
1369
|
+
commands: commands.map((cmd) => ({
|
|
1372
1370
|
name: cmd.name,
|
|
1373
1371
|
handler: cmd.handler,
|
|
1374
1372
|
resolvedPath: join(installPath, cmd.handler),
|
|
@@ -1488,8 +1486,19 @@ var OpenClawApplier = class {
|
|
|
1488
1486
|
this.skillsDir = options.skillsDir ?? DEFAULT_SKILLS_DIR;
|
|
1489
1487
|
this.trackingPath = options.configPath ?? join(this.workspace, "config.json");
|
|
1490
1488
|
}
|
|
1491
|
-
async applyPlugin(pkg) {
|
|
1489
|
+
async applyPlugin(pkg, _installPath, opts) {
|
|
1492
1490
|
await this.ensurePluginsAllow(pkg);
|
|
1491
|
+
if (opts?.force && this.isPluginInstalled(pkg)) {
|
|
1492
|
+
log.info({ pkg }, "Force mode — uninstalling plugin before reinstall");
|
|
1493
|
+
try {
|
|
1494
|
+
await this.removePlugin(pkg);
|
|
1495
|
+
} catch (err) {
|
|
1496
|
+
log.warn({
|
|
1497
|
+
pkg,
|
|
1498
|
+
err: err instanceof Error ? err.message : String(err)
|
|
1499
|
+
}, "Failed to uninstall plugin during force reinstall — proceeding");
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1493
1502
|
if (!this.isPluginInstalled(pkg)) {
|
|
1494
1503
|
try {
|
|
1495
1504
|
const args = [
|
|
@@ -1549,8 +1558,7 @@ var OpenClawApplier = class {
|
|
|
1549
1558
|
"config",
|
|
1550
1559
|
"set",
|
|
1551
1560
|
"plugins.allow",
|
|
1552
|
-
JSON.stringify(updated)
|
|
1553
|
-
"--strict-json"
|
|
1561
|
+
JSON.stringify(updated)
|
|
1554
1562
|
], { timeout: 1e4 });
|
|
1555
1563
|
} catch (err) {
|
|
1556
1564
|
log.warn({
|
|
@@ -1594,6 +1602,10 @@ var OpenClawApplier = class {
|
|
|
1594
1602
|
log.info({ slug }, "ClawHub skill installed");
|
|
1595
1603
|
} catch (err) {
|
|
1596
1604
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1605
|
+
if (msg.includes("already exists") || msg.includes("Skill already exists")) {
|
|
1606
|
+
log.info({ slug }, "ClawHub skill already installed (skipped)");
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1597
1609
|
log.error({
|
|
1598
1610
|
slug,
|
|
1599
1611
|
err: msg
|
|
@@ -1640,8 +1652,7 @@ var OpenClawApplier = class {
|
|
|
1640
1652
|
"config",
|
|
1641
1653
|
"set",
|
|
1642
1654
|
"--batch-json",
|
|
1643
|
-
JSON.stringify(batch)
|
|
1644
|
-
"--strict-json"
|
|
1655
|
+
JSON.stringify(batch)
|
|
1645
1656
|
], { timeout: 1e4 });
|
|
1646
1657
|
} catch (err) {
|
|
1647
1658
|
log.error({
|
|
@@ -1713,8 +1724,7 @@ var OpenClawApplier = class {
|
|
|
1713
1724
|
"config",
|
|
1714
1725
|
"set",
|
|
1715
1726
|
"--batch-json",
|
|
1716
|
-
JSON.stringify(batch)
|
|
1717
|
-
"--strict-json"
|
|
1727
|
+
JSON.stringify(batch)
|
|
1718
1728
|
], { timeout: 1e4 });
|
|
1719
1729
|
} catch (err) {
|
|
1720
1730
|
log.error({
|
package/package.json
CHANGED