@alfe.ai/integrations 0.0.33 → 0.1.0
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 +76 -196
- package/dist/index.js +160 -134
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import { IntegrationManifest, IntegrationStateEntry, IntegrationStatus, IntegrationsStateFile, McpServerDeclaration, PluginInstall, SkillInstall } from "@alfe.ai/integration-manifest";
|
|
2
|
+
import { Manager } from "@alfe.ai/mcp-bundler";
|
|
3
|
+
|
|
1
4
|
//#region src/registry.d.ts
|
|
5
|
+
|
|
2
6
|
/**
|
|
3
7
|
* Registry — fetches the integration registry index from the integrations service.
|
|
4
8
|
*
|
|
@@ -216,187 +220,16 @@ declare class Installer {
|
|
|
216
220
|
isInstalled(name: string): boolean;
|
|
217
221
|
}
|
|
218
222
|
//#endregion
|
|
219
|
-
//#region ../integration-manifest/dist/index.d.ts
|
|
220
|
-
//#region src/types.d.ts
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* TypeScript types for the Alfe integration manifest (`alfe-integration.yaml`).
|
|
224
|
-
*
|
|
225
|
-
* These are the canonical types used by all packages that interact with
|
|
226
|
-
* integration manifests -- registry, lifecycle manager, CLI, etc.
|
|
227
|
-
*/
|
|
228
|
-
type ConfigFieldType = 'secret' | 'string' | 'number' | 'boolean' | 'enum' | 'select' | 'multi_select' | 'oauth_connect';
|
|
229
|
-
interface SelectOption {
|
|
230
|
-
value: string;
|
|
231
|
-
label: string;
|
|
232
|
-
}
|
|
233
|
-
interface ConfigSchemaField {
|
|
234
|
-
key: string;
|
|
235
|
-
type: ConfigFieldType;
|
|
236
|
-
label: string;
|
|
237
|
-
description?: string;
|
|
238
|
-
required: boolean;
|
|
239
|
-
default?: string | number | boolean;
|
|
240
|
-
/** Who can mutate this field at runtime. Default: 'admin' */
|
|
241
|
-
editable: 'admin' | 'agent';
|
|
242
|
-
/** Only used when type === 'enum' */
|
|
243
|
-
options?: string[];
|
|
244
|
-
/** Structured options for select/multi_select fields */
|
|
245
|
-
select_options?: SelectOption[];
|
|
246
|
-
/** OAuth provider identifier for oauth_connect fields */
|
|
247
|
-
oauth_provider?: string;
|
|
248
|
-
/** Force specific scope groups for OAuth (e.g. ["chat"]) — hides other scopes in the dashboard */
|
|
249
|
-
oauth_scopes?: string[];
|
|
250
|
-
/** Integration ID to patch on OAuth callback (when using a shared OAuth provider) */
|
|
251
|
-
oauth_integration_id?: string;
|
|
252
|
-
/** If true, this field is not shown in the dashboard UI (install wizard or configure modal) */
|
|
253
|
-
hidden?: boolean;
|
|
254
|
-
/** Only show this field if another field has a truthy value (string) or matches a specific value (object) */
|
|
255
|
-
depends_on_field?: string | {
|
|
256
|
-
key: string;
|
|
257
|
-
value: string | number | boolean;
|
|
258
|
-
};
|
|
259
|
-
/** Only show this field if a specific integration is installed */
|
|
260
|
-
depends_on_integration?: string;
|
|
261
|
-
}
|
|
262
|
-
interface McpServerDeclaration {
|
|
263
|
-
/** Unique identifier within this integration */
|
|
264
|
-
id: string;
|
|
265
|
-
/** Command to spawn (e.g., 'npx', 'node', 'xero-mcp-proxy') */
|
|
266
|
-
command: string;
|
|
267
|
-
/** Arguments for the command */
|
|
268
|
-
args?: string[];
|
|
269
|
-
/** Environment variables — supports {{config.KEY}} interpolation from config + secrets */
|
|
270
|
-
env?: Record<string, string>;
|
|
271
|
-
/** Working directory (optional) */
|
|
272
|
-
cwd?: string;
|
|
273
|
-
/** If true, applier skips auto-application — a lifecycle hook manages this MCP server instead */
|
|
274
|
-
hook_managed?: boolean;
|
|
275
|
-
}
|
|
276
|
-
interface CommandDeclaration {
|
|
277
|
-
/** Dot-namespaced command name (e.g. "support.diagnostic") */
|
|
278
|
-
name: string;
|
|
279
|
-
/** Relative path to handler file within integration directory */
|
|
280
|
-
handler: string;
|
|
281
|
-
/** Exported function name (default: "handle") */
|
|
282
|
-
method?: string;
|
|
283
|
-
/** Timeout in milliseconds (default: 30000) */
|
|
284
|
-
timeout_ms?: number;
|
|
285
|
-
/** Human-readable description */
|
|
286
|
-
description?: string;
|
|
287
|
-
}
|
|
288
|
-
interface SkillInstall {
|
|
289
|
-
/** Relative path within the integration repo to the skill directory */
|
|
290
|
-
path?: string;
|
|
291
|
-
/** ClawHub skill slug to install from the registry */
|
|
292
|
-
clawhub?: string;
|
|
293
|
-
}
|
|
294
|
-
interface PluginInstall {
|
|
295
|
-
/** npm package name to install */
|
|
296
|
-
package: string;
|
|
297
|
-
}
|
|
298
|
-
type AgentRuntime = 'openclaw' | 'nanoclaw' | (string & {});
|
|
299
|
-
interface RuntimeInstall {
|
|
300
|
-
plugins?: PluginInstall[];
|
|
301
|
-
skills?: SkillInstall[];
|
|
302
|
-
/** Deep-merged into the runtime's agent config on activation */
|
|
303
|
-
config?: Record<string, unknown>;
|
|
304
|
-
}
|
|
305
|
-
interface InstallTargets {
|
|
306
|
-
/** Universal skills — applied to all runtimes */
|
|
307
|
-
skills?: SkillInstall[];
|
|
308
|
-
/** Universal plugins — applied to all runtimes */
|
|
309
|
-
plugins?: PluginInstall[];
|
|
310
|
-
/** Per-runtime installs */
|
|
311
|
-
runtimes?: Record<AgentRuntime, RuntimeInstall>;
|
|
312
|
-
}
|
|
313
|
-
interface IntegrationHooks {
|
|
314
|
-
pre_install?: string;
|
|
315
|
-
post_install?: string;
|
|
316
|
-
post_activate?: string;
|
|
317
|
-
pre_uninstall?: string;
|
|
318
|
-
post_uninstall?: string;
|
|
319
|
-
health_check?: string;
|
|
320
|
-
}
|
|
321
|
-
interface IntegrationPricingPlan {
|
|
322
|
-
name: string;
|
|
323
|
-
price: number;
|
|
324
|
-
currency?: string;
|
|
325
|
-
interval?: 'month' | 'year';
|
|
326
|
-
}
|
|
327
|
-
interface IntegrationPricing {
|
|
328
|
-
type: 'free' | 'paid' | 'usage';
|
|
329
|
-
/** Single price (shorthand for integrations with one plan) */
|
|
330
|
-
price?: number;
|
|
331
|
-
currency?: string;
|
|
332
|
-
interval?: 'month' | 'year';
|
|
333
|
-
/** Description of usage-based pricing (for type: 'usage') */
|
|
334
|
-
description?: string;
|
|
335
|
-
/** Multiple plans/tiers (e.g., starter, growth, scale) */
|
|
336
|
-
plans?: Record<string, IntegrationPricingPlan>;
|
|
337
|
-
}
|
|
338
|
-
interface IntegrationAuthor {
|
|
339
|
-
name: string;
|
|
340
|
-
url?: string;
|
|
341
|
-
}
|
|
342
|
-
interface IntegrationManifest {
|
|
343
|
-
id: string;
|
|
344
|
-
name: string;
|
|
345
|
-
version: string;
|
|
346
|
-
description: string;
|
|
347
|
-
/** Simple author string (legacy) or structured author object */
|
|
348
|
-
author: string | IntegrationAuthor;
|
|
349
|
-
license: string;
|
|
350
|
-
depends_on: string[];
|
|
351
|
-
min_gateway_version: string;
|
|
352
|
-
installs: InstallTargets;
|
|
353
|
-
config_schema: ConfigSchemaField[];
|
|
354
|
-
capabilities: string[];
|
|
355
|
-
hooks: IntegrationHooks;
|
|
356
|
-
commands: CommandDeclaration[];
|
|
357
|
-
/** MCP servers to configure in the agent runtime */
|
|
358
|
-
mcp_servers: McpServerDeclaration[];
|
|
359
|
-
/** Git repository URL (HTTPS) — not present in YAML, injected by the publish API */
|
|
360
|
-
repository?: string;
|
|
361
|
-
/**
|
|
362
|
-
* Agent runtimes this integration supports.
|
|
363
|
-
* If omitted or empty, the integration is considered universal (all runtimes).
|
|
364
|
-
* Example: ['openclaw'] means this integration only works with OpenClaw.
|
|
365
|
-
*/
|
|
366
|
-
supported_agents?: AgentRuntime[];
|
|
367
|
-
/**
|
|
368
|
-
* Scopes where this integration can be installed.
|
|
369
|
-
* Default: ['agent'] (per-agent only).
|
|
370
|
-
* 'org' means it can be installed at the org level and cascades to all agents.
|
|
371
|
-
*/
|
|
372
|
-
supported_scopes?: ('agent' | 'org')[];
|
|
373
|
-
/** Marketplace metadata */
|
|
374
|
-
publisherId?: string;
|
|
375
|
-
icon?: string;
|
|
376
|
-
pricing?: IntegrationPricing;
|
|
377
|
-
preview_images?: string[];
|
|
378
|
-
/** Long-form features list for the detail view */
|
|
379
|
-
features?: string[];
|
|
380
|
-
}
|
|
381
|
-
type IntegrationStatus = 'installing' | 'installed' | 'configured' | 'active' | 'error';
|
|
382
|
-
interface IntegrationStateEntry {
|
|
383
|
-
status: IntegrationStatus;
|
|
384
|
-
version: string;
|
|
385
|
-
installedAt: string;
|
|
386
|
-
config: Record<string, unknown>;
|
|
387
|
-
error?: string;
|
|
388
|
-
/** Number of consecutive auto-reinstall attempts. Reset on success or explicit reinstall. */
|
|
389
|
-
reinstallAttempts?: number;
|
|
390
|
-
}
|
|
391
|
-
interface IntegrationsStateFile {
|
|
392
|
-
version: number;
|
|
393
|
-
integrations: Record<string, IntegrationStateEntry>;
|
|
394
|
-
}
|
|
395
|
-
//#endregion
|
|
396
223
|
//#region src/runtime-applier.d.ts
|
|
397
224
|
/**
|
|
398
225
|
* RuntimeApplier — interface for applying/removing plugins and skills
|
|
399
226
|
* to a specific agent runtime (OpenClaw, NanoClaw, etc.).
|
|
227
|
+
*
|
|
228
|
+
* Note: MCP server registration is NOT here — it moved to the
|
|
229
|
+
* runtime-agnostic `McpApplier` (`appliers/mcp-applier.ts`) which
|
|
230
|
+
* writes via the bundler manager + openclaw.json mirror. Removing
|
|
231
|
+
* the per-runtime `applyMcpServers` / `removeMcpServers` was part of
|
|
232
|
+
* the bundler-as-primitive cleanup (see `project_mcp_tool_lift_workstream`).
|
|
400
233
|
*/
|
|
401
234
|
interface RuntimeApplier {
|
|
402
235
|
/** The runtime identifier (e.g. 'openclaw', 'nanoclaw') */
|
|
@@ -419,14 +252,65 @@ interface RuntimeApplier {
|
|
|
419
252
|
applyConfig(integrationId: string, config: Record<string, unknown>): Promise<void>;
|
|
420
253
|
/** Remove config previously applied by an integration */
|
|
421
254
|
removeConfig(integrationId: string): Promise<void>;
|
|
422
|
-
/** Configure MCP servers in this runtime */
|
|
423
|
-
applyMcpServers(integrationId: string, servers: McpServerDeclaration[]): Promise<void>;
|
|
424
|
-
/** Remove MCP servers previously applied by an integration */
|
|
425
|
-
removeMcpServers(integrationId: string): Promise<void>;
|
|
426
255
|
/** Check if this runtime is available (e.g. workspace directory exists) */
|
|
427
256
|
isAvailable(): Promise<boolean>;
|
|
428
257
|
}
|
|
429
258
|
//#endregion
|
|
259
|
+
//#region src/appliers/mcp-applier.d.ts
|
|
260
|
+
/**
|
|
261
|
+
* Minimal contract the applier needs from the agent API client.
|
|
262
|
+
* Wider than a single typed method so callers don't have to depend on
|
|
263
|
+
* the exact `AgentApiClient` shape — particularly handy for tests and
|
|
264
|
+
* for the eventual `getCredentials(provider)` generalisation.
|
|
265
|
+
*/
|
|
266
|
+
interface CredentialsResolver {
|
|
267
|
+
getCredentials: (provider: string) => Promise<Record<string, unknown> | undefined>;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Daemon-level platform context exposed to `{{alfe.<key>}}` env
|
|
271
|
+
* interpolation. Reserved namespace so manifests can reference things
|
|
272
|
+
* like the agent's cloud apiUrl (for OAuth redirect URIs) without
|
|
273
|
+
* colliding with user-supplied `{{config.<key>}}`.
|
|
274
|
+
*/
|
|
275
|
+
interface PlatformContext {
|
|
276
|
+
/** The agent's cloud apiUrl (e.g. https://api.alfe.ai). */
|
|
277
|
+
apiUrl?: string;
|
|
278
|
+
}
|
|
279
|
+
interface McpApplierOptions {
|
|
280
|
+
manager: Manager;
|
|
281
|
+
credentials: CredentialsResolver;
|
|
282
|
+
/** Optional — when omitted, `{{alfe.X}}` references are left as-is. */
|
|
283
|
+
platform?: PlatformContext;
|
|
284
|
+
}
|
|
285
|
+
declare class McpApplier {
|
|
286
|
+
private readonly manager;
|
|
287
|
+
private readonly credentials;
|
|
288
|
+
private readonly platform;
|
|
289
|
+
constructor(opts: McpApplierOptions);
|
|
290
|
+
/**
|
|
291
|
+
* Register every server declared by an integration. Idempotent —
|
|
292
|
+
* re-running for the same integration overwrites entries in place
|
|
293
|
+
* (the manager preserves `addedAt`). Returns the list of ids that
|
|
294
|
+
* actually landed in the store.
|
|
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.
|
|
302
|
+
*/
|
|
303
|
+
applyForIntegration(integrationId: string, servers: McpServerDeclaration[], mergedConfig: Record<string, unknown>): Promise<string[]>;
|
|
304
|
+
/**
|
|
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.
|
|
309
|
+
*/
|
|
310
|
+
removeForIntegration(integrationId: string): Promise<string[]>;
|
|
311
|
+
private resolveEnv;
|
|
312
|
+
}
|
|
313
|
+
//#endregion
|
|
430
314
|
//#region src/types.d.ts
|
|
431
315
|
/**
|
|
432
316
|
* Integration command parameter types.
|
|
@@ -462,6 +346,15 @@ interface IntegrationManagerOptions {
|
|
|
462
346
|
lockPath?: string;
|
|
463
347
|
/** Fetcher for the integration registry — should be wired to api-client */
|
|
464
348
|
registryFetcher: RegistryFetcher;
|
|
349
|
+
/**
|
|
350
|
+
* Runtime-agnostic MCP server applier. The manager routes
|
|
351
|
+
* `mcp_servers` declarations through it once per integration (the
|
|
352
|
+
* applier writes to the bundler store + openclaw.json mirror).
|
|
353
|
+
* Required — there is no fallback path; integrations with
|
|
354
|
+
* `mcp_servers` will skip MCP registration silently if this is
|
|
355
|
+
* omitted (the warn log makes this visible).
|
|
356
|
+
*/
|
|
357
|
+
mcpApplier?: McpApplier;
|
|
465
358
|
}
|
|
466
359
|
interface ManagerResponse {
|
|
467
360
|
ok: boolean;
|
|
@@ -496,6 +389,7 @@ declare class IntegrationManager {
|
|
|
496
389
|
private installer;
|
|
497
390
|
private runtimeAppliers;
|
|
498
391
|
private lockManager;
|
|
392
|
+
private mcpApplier;
|
|
499
393
|
/** In-memory secret store — NEVER persisted to disk */
|
|
500
394
|
private secrets;
|
|
501
395
|
constructor(options: IntegrationManagerOptions);
|
|
@@ -825,20 +719,6 @@ declare class OpenClawApplier implements RuntimeApplier {
|
|
|
825
719
|
* then removes them via `openclaw config unset`.
|
|
826
720
|
*/
|
|
827
721
|
removeConfig(integrationId: string): Promise<void>;
|
|
828
|
-
/**
|
|
829
|
-
* Configure MCP servers in OpenClaw via `openclaw config set --batch-json`.
|
|
830
|
-
*
|
|
831
|
-
* Each server is written as `mcp.servers.{integrationId}-{serverId}.*`.
|
|
832
|
-
* Applied servers are tracked in the tracking file for clean removal.
|
|
833
|
-
*/
|
|
834
|
-
applyMcpServers(integrationId: string, servers: McpServerDeclaration[]): Promise<void>;
|
|
835
|
-
/**
|
|
836
|
-
* Remove MCP servers previously applied by an integration.
|
|
837
|
-
*
|
|
838
|
-
* Reads the tracking file to find which `mcp.servers.*` keys this integration set,
|
|
839
|
-
* then removes them via `openclaw config unset`.
|
|
840
|
-
*/
|
|
841
|
-
removeMcpServers(integrationId: string): Promise<void>;
|
|
842
722
|
isAvailable(): Promise<boolean>;
|
|
843
723
|
private readTracking;
|
|
844
724
|
private writeTracking;
|
|
@@ -954,4 +834,4 @@ declare class IntegrationManagerAdapter implements IIntegrationManager {
|
|
|
954
834
|
resetReinstallAttempts(integrationId: string): void;
|
|
955
835
|
}
|
|
956
836
|
//#endregion
|
|
957
|
-
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 };
|
|
837
|
+
export { type CredentialsResolver, 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, McpApplier, type McpApplierOptions, OpenClawApplier, type OpenClawApplierOptions, type PlatformContext, 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
|
@@ -130,7 +130,7 @@ var Resolver = class {
|
|
|
130
130
|
* can resolve them via Node's upward module resolution.
|
|
131
131
|
*/
|
|
132
132
|
const execFileAsync$1 = promisify(execFile);
|
|
133
|
-
const log$
|
|
133
|
+
const log$2 = createLogger("Installer");
|
|
134
134
|
const INTEGRATIONS_DIR = join(homedir(), ".alfe", "integrations");
|
|
135
135
|
const GIT_TIMEOUT_MS = 6e4;
|
|
136
136
|
const NPM_TIMEOUT_MS = 6e4;
|
|
@@ -292,7 +292,7 @@ var Installer = class {
|
|
|
292
292
|
dependencies: { ...SHARED_PACKAGES }
|
|
293
293
|
};
|
|
294
294
|
writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2) + "\n", "utf-8");
|
|
295
|
-
log$
|
|
295
|
+
log$2.info("Installing shared @alfe.ai packages for integration hooks");
|
|
296
296
|
await this.runNpmInstall(this.basePath);
|
|
297
297
|
this.sharedPackagesReady = true;
|
|
298
298
|
}
|
|
@@ -302,7 +302,7 @@ var Installer = class {
|
|
|
302
302
|
*/
|
|
303
303
|
async installLocalDependencies(installPath) {
|
|
304
304
|
if (!existsSync(join(installPath, "package.json"))) return;
|
|
305
|
-
log$
|
|
305
|
+
log$2.info({ path: installPath }, "Installing integration-specific npm dependencies");
|
|
306
306
|
await this.runNpmInstall(installPath);
|
|
307
307
|
}
|
|
308
308
|
async runNpmInstall(cwd) {
|
|
@@ -837,25 +837,6 @@ function interpolateSelfConfig(obj, config) {
|
|
|
837
837
|
return result;
|
|
838
838
|
}
|
|
839
839
|
/**
|
|
840
|
-
* Interpolate `{{config.KEY}}` patterns in MCP server env vars using
|
|
841
|
-
* the merged config + secrets dict. Returns new declarations with
|
|
842
|
-
* interpolated env values; skips hook_managed servers.
|
|
843
|
-
*/
|
|
844
|
-
function interpolateMcpServerEnvs(servers, mergedConfig) {
|
|
845
|
-
return servers.filter((s) => !s.hook_managed).map((server) => {
|
|
846
|
-
if (!server.env) return server;
|
|
847
|
-
const interpolatedEnv = {};
|
|
848
|
-
for (const [key, value] of Object.entries(server.env)) interpolatedEnv[key] = value.replace(/\{\{config\.([a-zA-Z0-9_]+)\}\}/g, (_match, configKey) => {
|
|
849
|
-
const val = mergedConfig[configKey];
|
|
850
|
-
return typeof val === "string" || typeof val === "number" ? String(val) : _match;
|
|
851
|
-
});
|
|
852
|
-
return {
|
|
853
|
-
...server,
|
|
854
|
-
env: interpolatedEnv
|
|
855
|
-
};
|
|
856
|
-
});
|
|
857
|
-
}
|
|
858
|
-
/**
|
|
859
840
|
* Merge universal installs with runtime-specific installs from the manifest.
|
|
860
841
|
*/
|
|
861
842
|
function resolveInstallsForRuntime(manifest, runtime) {
|
|
@@ -875,6 +856,7 @@ var IntegrationManager = class {
|
|
|
875
856
|
installer;
|
|
876
857
|
runtimeAppliers;
|
|
877
858
|
lockManager;
|
|
859
|
+
mcpApplier;
|
|
878
860
|
/** In-memory secret store — NEVER persisted to disk */
|
|
879
861
|
secrets = /* @__PURE__ */ new Map();
|
|
880
862
|
constructor(options) {
|
|
@@ -884,6 +866,7 @@ var IntegrationManager = class {
|
|
|
884
866
|
this.installer = new Installer(options.integrationsDir);
|
|
885
867
|
this.runtimeAppliers = options.runtimeAppliers ?? /* @__PURE__ */ new Map();
|
|
886
868
|
this.lockManager = new LockManager(options.lockPath);
|
|
869
|
+
this.mcpApplier = options.mcpApplier;
|
|
887
870
|
}
|
|
888
871
|
/**
|
|
889
872
|
* Install an integration from the registry.
|
|
@@ -1102,22 +1085,20 @@ var IntegrationManager = class {
|
|
|
1102
1085
|
await applier.applyConfig(integrationId, interpolatedConfig);
|
|
1103
1086
|
configApplied = true;
|
|
1104
1087
|
}
|
|
1105
|
-
const mcpServers = manifest.mcp_servers ?? [];
|
|
1106
|
-
if (mcpServers.length > 0) {
|
|
1107
|
-
const secretEntries = this.secrets.get(integrationId);
|
|
1108
|
-
const interpolatedServers = interpolateMcpServerEnvs(mcpServers, {
|
|
1109
|
-
...entry.config,
|
|
1110
|
-
...secretEntries ? Object.fromEntries(secretEntries) : {}
|
|
1111
|
-
});
|
|
1112
|
-
if (interpolatedServers.length > 0) {
|
|
1113
|
-
this.log.info(`Applying ${String(interpolatedServers.length)} MCP server(s) for ${integrationId} to ${runtimeName}`);
|
|
1114
|
-
await applier.applyMcpServers(integrationId, interpolatedServers);
|
|
1115
|
-
configApplied = true;
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
1088
|
const appliedPlugins = plugins.filter((p) => !pluginFailures.includes(p.package));
|
|
1119
1089
|
if (appliedPlugins.length > 0 || skills.length > 0) this.lockManager.addEntries(runtimeName, integrationId, manifest.version, appliedPlugins, skills, installPath);
|
|
1120
1090
|
}
|
|
1091
|
+
const mcpServers = manifest.mcp_servers ?? [];
|
|
1092
|
+
if (mcpServers.length > 0) if (!this.mcpApplier) this.log.warn(`Integration "${integrationId}" declares ${String(mcpServers.length)} mcp_server(s) but no mcpApplier is wired — skipping MCP registration`);
|
|
1093
|
+
else {
|
|
1094
|
+
const secretEntries = this.secrets.get(integrationId);
|
|
1095
|
+
const mergedConfig = {
|
|
1096
|
+
...entry.config,
|
|
1097
|
+
...secretEntries ? Object.fromEntries(secretEntries) : {}
|
|
1098
|
+
};
|
|
1099
|
+
this.log.info(`Applying ${String(mcpServers.length)} MCP server(s) for ${integrationId} via bundler manager`);
|
|
1100
|
+
await this.mcpApplier.applyForIntegration(integrationId, mcpServers, mergedConfig);
|
|
1101
|
+
}
|
|
1121
1102
|
this.state.setStatus(integrationId, "active");
|
|
1122
1103
|
if (manifest.hooks.post_activate) {
|
|
1123
1104
|
this.log.info(`Running post_activate hook: ${manifest.hooks.post_activate}`);
|
|
@@ -1215,13 +1196,12 @@ var IntegrationManager = class {
|
|
|
1215
1196
|
this.log.warn(`Failed to remove config for ${integrationId} from ${runtimeName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
1216
1197
|
}
|
|
1217
1198
|
}
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
this.log.info(`Removing MCP servers for ${integrationId} from ${runtimeName}`);
|
|
1199
|
+
if (this.mcpApplier) {
|
|
1200
|
+
this.log.info(`Removing MCP servers for ${integrationId} via bundler manager`);
|
|
1221
1201
|
try {
|
|
1222
|
-
await
|
|
1202
|
+
await this.mcpApplier.removeForIntegration(integrationId);
|
|
1223
1203
|
} catch (err) {
|
|
1224
|
-
this.log.warn(`Failed to remove MCP servers for ${integrationId}
|
|
1204
|
+
this.log.warn(`Failed to remove MCP servers for ${integrationId} via bundler manager: ${err instanceof Error ? err.message : String(err)}`);
|
|
1225
1205
|
}
|
|
1226
1206
|
}
|
|
1227
1207
|
this.state.setStatus(integrationId, "configured");
|
|
@@ -1521,7 +1501,7 @@ var IntegrationManager = class {
|
|
|
1521
1501
|
* is stored in a separate tracking file (config.json) for clean removal.
|
|
1522
1502
|
*/
|
|
1523
1503
|
const execFileAsync = promisify(execFile);
|
|
1524
|
-
const log = createLogger("OpenClawApplier");
|
|
1504
|
+
const log$1 = createLogger("OpenClawApplier");
|
|
1525
1505
|
const DEFAULT_SKILLS_DIR = join(homedir(), ".alfe", "skills");
|
|
1526
1506
|
function flattenConfig(obj, prefix = "") {
|
|
1527
1507
|
const entries = [];
|
|
@@ -1599,11 +1579,11 @@ var OpenClawApplier = class {
|
|
|
1599
1579
|
await this.ensurePluginsAllow(pkg);
|
|
1600
1580
|
this.cleanupUntrackedExtensionInstall(pkg);
|
|
1601
1581
|
if (opts?.force && this.isPluginInstalled(pkg)) {
|
|
1602
|
-
log.info({ pkg }, "Force mode — uninstalling plugin before reinstall");
|
|
1582
|
+
log$1.info({ pkg }, "Force mode — uninstalling plugin before reinstall");
|
|
1603
1583
|
try {
|
|
1604
1584
|
await this.removePlugin(pkg);
|
|
1605
1585
|
} catch (err) {
|
|
1606
|
-
log.warn({
|
|
1586
|
+
log$1.warn({
|
|
1607
1587
|
pkg,
|
|
1608
1588
|
err: err instanceof Error ? err.message : String(err)
|
|
1609
1589
|
}, "Failed to uninstall plugin during force reinstall — proceeding");
|
|
@@ -1624,7 +1604,7 @@ var OpenClawApplier = class {
|
|
|
1624
1604
|
} catch (err) {
|
|
1625
1605
|
const errText = err instanceof Error ? `${err.message}\n${err.stderr ?? ""}` : String(err);
|
|
1626
1606
|
if (useUnsafeFlag && errText.includes("unknown option")) {
|
|
1627
|
-
log.info({ pkg }, "OpenClaw does not support --dangerously-force-unsafe-install, retrying without");
|
|
1607
|
+
log$1.info({ pkg }, "OpenClaw does not support --dangerously-force-unsafe-install, retrying without");
|
|
1628
1608
|
await execFileAsync("openclaw", baseArgs, { timeout: 6e4 });
|
|
1629
1609
|
} else throw err;
|
|
1630
1610
|
}
|
|
@@ -1633,7 +1613,7 @@ var OpenClawApplier = class {
|
|
|
1633
1613
|
setTimeout(r, 500);
|
|
1634
1614
|
});
|
|
1635
1615
|
if (!this.isPluginInstalled(pkg)) throw err;
|
|
1636
|
-
log.warn({
|
|
1616
|
+
log$1.warn({
|
|
1637
1617
|
pkg,
|
|
1638
1618
|
err: err instanceof Error ? err.message : String(err)
|
|
1639
1619
|
}, "openclaw plugins install exited with warnings but plugin is installed");
|
|
@@ -1668,7 +1648,7 @@ var OpenClawApplier = class {
|
|
|
1668
1648
|
JSON.stringify(updated)
|
|
1669
1649
|
], { timeout: 1e4 });
|
|
1670
1650
|
} catch (err) {
|
|
1671
|
-
log.warn({
|
|
1651
|
+
log$1.warn({
|
|
1672
1652
|
err: err instanceof Error ? err.message : String(err),
|
|
1673
1653
|
pkg
|
|
1674
1654
|
}, "Failed to set plugins.allow via openclaw config set");
|
|
@@ -1721,12 +1701,12 @@ var OpenClawApplier = class {
|
|
|
1721
1701
|
recursive: true,
|
|
1722
1702
|
force: true
|
|
1723
1703
|
});
|
|
1724
|
-
log.info({
|
|
1704
|
+
log$1.info({
|
|
1725
1705
|
pkg,
|
|
1726
1706
|
removed: fullPath
|
|
1727
1707
|
}, "Removed untracked extensions/ install — will reinstall via npm path");
|
|
1728
1708
|
} catch (err) {
|
|
1729
|
-
log.warn({
|
|
1709
|
+
log$1.warn({
|
|
1730
1710
|
pkg,
|
|
1731
1711
|
removed: fullPath,
|
|
1732
1712
|
err: err instanceof Error ? err.message : String(err)
|
|
@@ -1749,21 +1729,21 @@ var OpenClawApplier = class {
|
|
|
1749
1729
|
return Promise.resolve();
|
|
1750
1730
|
}
|
|
1751
1731
|
async applyClawHubSkill(slug) {
|
|
1752
|
-
log.info({ slug }, "Installing skill from ClawHub");
|
|
1732
|
+
log$1.info({ slug }, "Installing skill from ClawHub");
|
|
1753
1733
|
try {
|
|
1754
1734
|
await execFileAsync("openclaw", [
|
|
1755
1735
|
"skills",
|
|
1756
1736
|
"install",
|
|
1757
1737
|
slug
|
|
1758
1738
|
], { timeout: 6e4 });
|
|
1759
|
-
log.info({ slug }, "ClawHub skill installed");
|
|
1739
|
+
log$1.info({ slug }, "ClawHub skill installed");
|
|
1760
1740
|
} catch (err) {
|
|
1761
1741
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1762
1742
|
if (msg.includes("already exists") || msg.includes("Skill already exists")) {
|
|
1763
|
-
log.info({ slug }, "ClawHub skill already installed (skipped)");
|
|
1743
|
+
log$1.info({ slug }, "ClawHub skill already installed (skipped)");
|
|
1764
1744
|
return;
|
|
1765
1745
|
}
|
|
1766
|
-
log.error({
|
|
1746
|
+
log$1.error({
|
|
1767
1747
|
slug,
|
|
1768
1748
|
err: msg
|
|
1769
1749
|
}, "ClawHub skill install failed");
|
|
@@ -1776,7 +1756,7 @@ var OpenClawApplier = class {
|
|
|
1776
1756
|
recursive: true,
|
|
1777
1757
|
force: true
|
|
1778
1758
|
});
|
|
1779
|
-
log.info({ slug }, "ClawHub skill removed");
|
|
1759
|
+
log$1.info({ slug }, "ClawHub skill removed");
|
|
1780
1760
|
}
|
|
1781
1761
|
return Promise.resolve();
|
|
1782
1762
|
}
|
|
@@ -1812,7 +1792,7 @@ var OpenClawApplier = class {
|
|
|
1812
1792
|
JSON.stringify(merged)
|
|
1813
1793
|
], { timeout: 1e4 });
|
|
1814
1794
|
} catch (err) {
|
|
1815
|
-
log.error({
|
|
1795
|
+
log$1.error({
|
|
1816
1796
|
err: err instanceof Error ? err.message : String(err),
|
|
1817
1797
|
parentPath
|
|
1818
1798
|
}, "Failed to set config subtree via openclaw config set");
|
|
@@ -1827,7 +1807,7 @@ var OpenClawApplier = class {
|
|
|
1827
1807
|
JSON.stringify(leaves)
|
|
1828
1808
|
], { timeout: 1e4 });
|
|
1829
1809
|
} catch (err) {
|
|
1830
|
-
log.error({
|
|
1810
|
+
log$1.error({
|
|
1831
1811
|
err: err instanceof Error ? err.message : String(err),
|
|
1832
1812
|
batch: leaves
|
|
1833
1813
|
}, "Failed to set config via openclaw config set --batch-json");
|
|
@@ -1853,7 +1833,7 @@ var OpenClawApplier = class {
|
|
|
1853
1833
|
path
|
|
1854
1834
|
], { timeout: 1e4 });
|
|
1855
1835
|
} catch (err) {
|
|
1856
|
-
log.warn({
|
|
1836
|
+
log$1.warn({
|
|
1857
1837
|
err: err instanceof Error ? err.message : String(err),
|
|
1858
1838
|
path
|
|
1859
1839
|
}, "Failed to unset config via openclaw config unset");
|
|
@@ -1875,7 +1855,7 @@ var OpenClawApplier = class {
|
|
|
1875
1855
|
JSON.stringify(remaining)
|
|
1876
1856
|
], { timeout: 1e4 });
|
|
1877
1857
|
} catch (err) {
|
|
1878
|
-
log.warn({
|
|
1858
|
+
log$1.warn({
|
|
1879
1859
|
err: err instanceof Error ? err.message : String(err),
|
|
1880
1860
|
parentPath
|
|
1881
1861
|
}, "Failed to update parent config during remove");
|
|
@@ -1884,82 +1864,6 @@ var OpenClawApplier = class {
|
|
|
1884
1864
|
tracking._integrations = Object.fromEntries(Object.entries(integrations).filter(([key]) => key !== integrationId));
|
|
1885
1865
|
this.writeTracking(tracking);
|
|
1886
1866
|
}
|
|
1887
|
-
/**
|
|
1888
|
-
* Configure MCP servers in OpenClaw via `openclaw config set --batch-json`.
|
|
1889
|
-
*
|
|
1890
|
-
* Each server is written as `mcp.servers.{integrationId}-{serverId}.*`.
|
|
1891
|
-
* Applied servers are tracked in the tracking file for clean removal.
|
|
1892
|
-
*/
|
|
1893
|
-
async applyMcpServers(integrationId, servers) {
|
|
1894
|
-
if (servers.length === 0) return;
|
|
1895
|
-
const batch = [];
|
|
1896
|
-
const trackedKeys = [];
|
|
1897
|
-
for (const server of servers) {
|
|
1898
|
-
const prefix = `mcp.servers.${`${integrationId}-${server.id}`}`;
|
|
1899
|
-
batch.push({
|
|
1900
|
-
path: `${prefix}.command`,
|
|
1901
|
-
value: server.command
|
|
1902
|
-
});
|
|
1903
|
-
if (server.args && server.args.length > 0) batch.push({
|
|
1904
|
-
path: `${prefix}.args`,
|
|
1905
|
-
value: server.args
|
|
1906
|
-
});
|
|
1907
|
-
if (server.env) for (const [envKey, envVal] of Object.entries(server.env)) batch.push({
|
|
1908
|
-
path: `${prefix}.env.${envKey}`,
|
|
1909
|
-
value: envVal
|
|
1910
|
-
});
|
|
1911
|
-
if (server.cwd) batch.push({
|
|
1912
|
-
path: `${prefix}.cwd`,
|
|
1913
|
-
value: server.cwd
|
|
1914
|
-
});
|
|
1915
|
-
trackedKeys.push(prefix);
|
|
1916
|
-
}
|
|
1917
|
-
try {
|
|
1918
|
-
await execFileAsync("openclaw", [
|
|
1919
|
-
"config",
|
|
1920
|
-
"set",
|
|
1921
|
-
"--batch-json",
|
|
1922
|
-
JSON.stringify(batch)
|
|
1923
|
-
], { timeout: 1e4 });
|
|
1924
|
-
} catch (err) {
|
|
1925
|
-
log.error({
|
|
1926
|
-
err: err instanceof Error ? err.message : String(err),
|
|
1927
|
-
batch
|
|
1928
|
-
}, "Failed to set MCP server config via openclaw config set --batch-json");
|
|
1929
|
-
throw err;
|
|
1930
|
-
}
|
|
1931
|
-
const tracking = this.readTracking();
|
|
1932
|
-
const mcpTracking = tracking._mcpServers ?? {};
|
|
1933
|
-
mcpTracking[integrationId] = trackedKeys;
|
|
1934
|
-
tracking._mcpServers = mcpTracking;
|
|
1935
|
-
this.writeTracking(tracking);
|
|
1936
|
-
}
|
|
1937
|
-
/**
|
|
1938
|
-
* Remove MCP servers previously applied by an integration.
|
|
1939
|
-
*
|
|
1940
|
-
* Reads the tracking file to find which `mcp.servers.*` keys this integration set,
|
|
1941
|
-
* then removes them via `openclaw config unset`.
|
|
1942
|
-
*/
|
|
1943
|
-
async removeMcpServers(integrationId) {
|
|
1944
|
-
const tracking = this.readTracking();
|
|
1945
|
-
const mcpTracking = tracking._mcpServers ?? {};
|
|
1946
|
-
if (!(integrationId in mcpTracking)) return;
|
|
1947
|
-
const prefixes = mcpTracking[integrationId];
|
|
1948
|
-
for (const prefix of prefixes) try {
|
|
1949
|
-
await execFileAsync("openclaw", [
|
|
1950
|
-
"config",
|
|
1951
|
-
"unset",
|
|
1952
|
-
prefix
|
|
1953
|
-
], { timeout: 1e4 });
|
|
1954
|
-
} catch (err) {
|
|
1955
|
-
log.warn({
|
|
1956
|
-
err: err instanceof Error ? err.message : String(err),
|
|
1957
|
-
prefix
|
|
1958
|
-
}, "Failed to unset MCP server config via openclaw config unset");
|
|
1959
|
-
}
|
|
1960
|
-
tracking._mcpServers = Object.fromEntries(Object.entries(mcpTracking).filter(([key]) => key !== integrationId));
|
|
1961
|
-
this.writeTracking(tracking);
|
|
1962
|
-
}
|
|
1963
1867
|
isAvailable() {
|
|
1964
1868
|
return Promise.resolve(existsSync(this.home));
|
|
1965
1869
|
}
|
|
@@ -1977,6 +1881,128 @@ var OpenClawApplier = class {
|
|
|
1977
1881
|
}
|
|
1978
1882
|
};
|
|
1979
1883
|
//#endregion
|
|
1884
|
+
//#region src/appliers/mcp-applier.ts
|
|
1885
|
+
const log = createLogger("McpApplier");
|
|
1886
|
+
const CONFIG_TEMPLATE_RE = /\{\{config\.([a-zA-Z0-9_]+)\}\}/g;
|
|
1887
|
+
const CREDENTIALS_TEMPLATE_RE = /\{\{credentials\.([a-z0-9-]+)\.([a-zA-Z0-9_]+)\}\}/g;
|
|
1888
|
+
const ALFE_TEMPLATE_RE = /\{\{alfe\.([a-zA-Z0-9_]+)\}\}/g;
|
|
1889
|
+
var McpApplier = class {
|
|
1890
|
+
manager;
|
|
1891
|
+
credentials;
|
|
1892
|
+
platform;
|
|
1893
|
+
constructor(opts) {
|
|
1894
|
+
this.manager = opts.manager;
|
|
1895
|
+
this.credentials = opts.credentials;
|
|
1896
|
+
this.platform = opts.platform ?? {};
|
|
1897
|
+
}
|
|
1898
|
+
/**
|
|
1899
|
+
* Register every server declared by an integration. Idempotent —
|
|
1900
|
+
* re-running for the same integration overwrites entries in place
|
|
1901
|
+
* (the manager preserves `addedAt`). Returns the list of ids that
|
|
1902
|
+
* actually landed in the store.
|
|
1903
|
+
*
|
|
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.
|
|
1910
|
+
*/
|
|
1911
|
+
async applyForIntegration(integrationId, servers, mergedConfig) {
|
|
1912
|
+
const owner = `integration:${integrationId}`;
|
|
1913
|
+
const applied = [];
|
|
1914
|
+
for (const server of servers) {
|
|
1915
|
+
const id = `${integrationId}-${server.id}`;
|
|
1916
|
+
const envResolved = await this.resolveEnv(server, mergedConfig);
|
|
1917
|
+
if (envResolved == null) {
|
|
1918
|
+
log.info({
|
|
1919
|
+
integrationId,
|
|
1920
|
+
server: server.id,
|
|
1921
|
+
provider: server.requires_credentials
|
|
1922
|
+
}, "Skipping MCP server registration — required credentials missing or fetch failed");
|
|
1923
|
+
continue;
|
|
1924
|
+
}
|
|
1925
|
+
await this.manager.addServer(toBundlerConfig(server, envResolved), {
|
|
1926
|
+
id,
|
|
1927
|
+
owner
|
|
1928
|
+
});
|
|
1929
|
+
applied.push(id);
|
|
1930
|
+
}
|
|
1931
|
+
await this.manager.flush();
|
|
1932
|
+
return applied;
|
|
1933
|
+
}
|
|
1934
|
+
/**
|
|
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.
|
|
1939
|
+
*/
|
|
1940
|
+
async removeForIntegration(integrationId) {
|
|
1941
|
+
const owner = `integration:${integrationId}`;
|
|
1942
|
+
const removed = await this.manager.removeServersByOwner(owner);
|
|
1943
|
+
await this.manager.flush();
|
|
1944
|
+
return removed;
|
|
1945
|
+
}
|
|
1946
|
+
async resolveEnv(server, mergedConfig) {
|
|
1947
|
+
if (!server.env || Object.keys(server.env).length === 0) return {};
|
|
1948
|
+
const needsCredentials = server.requires_credentials;
|
|
1949
|
+
let credentialsCache;
|
|
1950
|
+
if (needsCredentials) {
|
|
1951
|
+
try {
|
|
1952
|
+
credentialsCache = await this.credentials.getCredentials(needsCredentials);
|
|
1953
|
+
} catch (err) {
|
|
1954
|
+
log.warn({
|
|
1955
|
+
err: errMsg(err),
|
|
1956
|
+
provider: needsCredentials
|
|
1957
|
+
}, "Credentials fetch threw — skipping MCP registration");
|
|
1958
|
+
return null;
|
|
1959
|
+
}
|
|
1960
|
+
if (!credentialsCache || Object.keys(credentialsCache).length === 0) return null;
|
|
1961
|
+
}
|
|
1962
|
+
const resolved = {};
|
|
1963
|
+
for (const [key, value] of Object.entries(server.env)) {
|
|
1964
|
+
const interpolated = interpolateString(value, mergedConfig, credentialsCache, this.platform);
|
|
1965
|
+
if (needsCredentials && hasCredentialsPlaceholder(interpolated)) {
|
|
1966
|
+
log.warn({
|
|
1967
|
+
provider: needsCredentials,
|
|
1968
|
+
key
|
|
1969
|
+
}, "Credentials interpolation left a placeholder — skipping MCP registration");
|
|
1970
|
+
return null;
|
|
1971
|
+
}
|
|
1972
|
+
resolved[key] = interpolated;
|
|
1973
|
+
}
|
|
1974
|
+
return resolved;
|
|
1975
|
+
}
|
|
1976
|
+
};
|
|
1977
|
+
function hasCredentialsPlaceholder(value) {
|
|
1978
|
+
return /\{\{credentials\.[a-z0-9-]+\.[a-zA-Z0-9_]+\}\}/.test(value);
|
|
1979
|
+
}
|
|
1980
|
+
function interpolateString(value, mergedConfig, credentials, platform) {
|
|
1981
|
+
let next = value.replace(CONFIG_TEMPLATE_RE, (match, configKey) => {
|
|
1982
|
+
const v = mergedConfig[configKey];
|
|
1983
|
+
return typeof v === "string" || typeof v === "number" ? String(v) : match;
|
|
1984
|
+
});
|
|
1985
|
+
if (credentials) next = next.replace(CREDENTIALS_TEMPLATE_RE, (match, _provider, field) => {
|
|
1986
|
+
const v = credentials[field];
|
|
1987
|
+
return typeof v === "string" || typeof v === "number" ? String(v) : match;
|
|
1988
|
+
});
|
|
1989
|
+
next = next.replace(ALFE_TEMPLATE_RE, (match, platformKey) => {
|
|
1990
|
+
const v = platform[platformKey];
|
|
1991
|
+
return typeof v === "string" || typeof v === "number" ? String(v) : match;
|
|
1992
|
+
});
|
|
1993
|
+
return next;
|
|
1994
|
+
}
|
|
1995
|
+
function toBundlerConfig(server, resolvedEnv) {
|
|
1996
|
+
const cfg = { command: server.command };
|
|
1997
|
+
if (server.args && server.args.length > 0) cfg.args = server.args;
|
|
1998
|
+
if (Object.keys(resolvedEnv).length > 0) cfg.env = resolvedEnv;
|
|
1999
|
+
if (server.cwd) cfg.cwd = server.cwd;
|
|
2000
|
+
return cfg;
|
|
2001
|
+
}
|
|
2002
|
+
function errMsg(err) {
|
|
2003
|
+
return err instanceof Error ? err.message : String(err);
|
|
2004
|
+
}
|
|
2005
|
+
//#endregion
|
|
1980
2006
|
//#region src/adapter.ts
|
|
1981
2007
|
var IntegrationManagerAdapter = class {
|
|
1982
2008
|
constructor(manager) {
|
|
@@ -2035,4 +2061,4 @@ var IntegrationManagerAdapter = class {
|
|
|
2035
2061
|
}
|
|
2036
2062
|
};
|
|
2037
2063
|
//#endregion
|
|
2038
|
-
export { Installer, InstallerError, IntegrationManager, IntegrationManagerAdapter, LockManager, OpenClawApplier, Registry, RegistryResolveError, Resolver, StateManager, buildHookEnv, resolveInstallsForRuntime, runHook, runHookWithContext };
|
|
2064
|
+
export { Installer, InstallerError, IntegrationManager, IntegrationManagerAdapter, LockManager, McpApplier, 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
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Integration lifecycle management for Alfe — registry, resolution, installation, and state",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@auriclabs/logger": "^0.1.1",
|
|
16
|
-
"@alfe.ai/integration-manifest": "^0.0
|
|
16
|
+
"@alfe.ai/integration-manifest": "^0.1.0",
|
|
17
|
+
"@alfe.ai/mcp-bundler": "^0.1.0"
|
|
17
18
|
},
|
|
18
19
|
"files": [
|
|
19
20
|
"dist"
|