@phronesis-io/openclaw-eigenflux 0.0.3 → 0.0.6

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.
Files changed (67) hide show
  1. package/README.md +15 -161
  2. package/dist/agent-prompt-templates.d.ts +14 -11
  3. package/dist/agent-prompt-templates.d.ts.map +1 -1
  4. package/dist/agent-prompt-templates.js +27 -38
  5. package/dist/agent-prompt-templates.js.map +1 -1
  6. package/dist/cli-executor.d.ts +32 -0
  7. package/dist/cli-executor.d.ts.map +1 -0
  8. package/dist/cli-executor.js +75 -0
  9. package/dist/cli-executor.js.map +1 -0
  10. package/dist/config.d.ts +41 -126
  11. package/dist/config.d.ts.map +1 -1
  12. package/dist/config.js +94 -229
  13. package/dist/config.js.map +1 -1
  14. package/dist/credentials-loader.d.ts +6 -5
  15. package/dist/credentials-loader.d.ts.map +1 -1
  16. package/dist/credentials-loader.js +17 -21
  17. package/dist/credentials-loader.js.map +1 -1
  18. package/dist/index.d.ts +3 -73
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +212 -276
  21. package/dist/index.js.map +1 -1
  22. package/dist/notification-route-resolver.d.ts +24 -2
  23. package/dist/notification-route-resolver.d.ts.map +1 -1
  24. package/dist/notification-route-resolver.js +257 -43
  25. package/dist/notification-route-resolver.js.map +1 -1
  26. package/dist/notifier.d.ts +9 -17
  27. package/dist/notifier.d.ts.map +1 -1
  28. package/dist/notifier.js +133 -66
  29. package/dist/notifier.js.map +1 -1
  30. package/dist/polling-client.d.ts +31 -19
  31. package/dist/polling-client.d.ts.map +1 -1
  32. package/dist/polling-client.js +102 -127
  33. package/dist/polling-client.js.map +1 -1
  34. package/dist/reply-target.d.ts +8 -0
  35. package/dist/reply-target.d.ts.map +1 -0
  36. package/dist/reply-target.js +104 -0
  37. package/dist/reply-target.js.map +1 -0
  38. package/dist/session-route-memory.d.ts +12 -3
  39. package/dist/session-route-memory.d.ts.map +1 -1
  40. package/dist/session-route-memory.js +83 -80
  41. package/dist/session-route-memory.js.map +1 -1
  42. package/dist/stream-client.d.ts +48 -0
  43. package/dist/stream-client.d.ts.map +1 -0
  44. package/dist/stream-client.js +168 -0
  45. package/dist/stream-client.js.map +1 -0
  46. package/openclaw.plugin.json +5 -75
  47. package/package.json +6 -8
  48. package/skills/ef-broadcast/SKILL.md +84 -0
  49. package/skills/ef-broadcast/references/feed.md +127 -0
  50. package/skills/ef-broadcast/references/publish.md +119 -0
  51. package/skills/ef-communication/SKILL.md +95 -0
  52. package/skills/ef-communication/references/message.md +132 -0
  53. package/skills/ef-communication/references/relations.md +215 -0
  54. package/skills/ef-communication/references/stream.md +66 -0
  55. package/skills/ef-profile/SKILL.md +138 -0
  56. package/skills/ef-profile/references/auth.md +103 -0
  57. package/skills/ef-profile/references/config.md +54 -0
  58. package/skills/ef-profile/references/onboarding.md +172 -0
  59. package/skills/ef-profile/references/server-management.md +67 -0
  60. package/dist/gateway-rpc-client.d.ts +0 -26
  61. package/dist/gateway-rpc-client.d.ts.map +0 -1
  62. package/dist/gateway-rpc-client.js +0 -288
  63. package/dist/gateway-rpc-client.js.map +0 -1
  64. package/dist/pm-polling-client.d.ts +0 -52
  65. package/dist/pm-polling-client.d.ts.map +0 -1
  66. package/dist/pm-polling-client.js +0 -182
  67. package/dist/pm-polling-client.js.map +0 -1
package/dist/config.d.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  /**
2
- * Internal configuration for the EigenFlux plugin.
2
+ * Configuration for the EigenFlux plugin.
3
+ *
4
+ * Server management is now handled by the eigenflux CLI.
5
+ * The plugin config only holds plugin-level settings and
6
+ * per-server notification routing overrides.
3
7
  */
4
8
  import { Logger } from './logger';
5
9
  export type NotificationRouteOverrides = {
@@ -9,32 +13,7 @@ export type NotificationRouteOverrides = {
9
13
  replyTo: boolean;
10
14
  replyAccountId: boolean;
11
15
  };
12
- export type EigenFluxServerConfig = {
13
- enabled?: boolean;
14
- name?: string;
15
- endpoint?: string;
16
- workdir?: string;
17
- pollInterval?: number;
18
- pmPollInterval?: number;
19
- sessionKey?: string;
20
- agentId?: string;
21
- replyChannel?: string;
22
- replyTo?: string;
23
- replyAccountId?: string;
24
- };
25
- export type EigenFluxPluginConfig = {
26
- gatewayUrl?: string;
27
- gatewayToken?: string;
28
- openclawCliBin?: string;
29
- servers?: EigenFluxServerConfig[];
30
- };
31
- export type ResolvedEigenFluxServerConfig = {
32
- enabled: boolean;
33
- name: string;
34
- endpoint: string;
35
- workdir: string;
36
- pollIntervalSec: number;
37
- pmPollIntervalSec: number;
16
+ export type RoutingConfig = {
38
17
  sessionKey: string;
39
18
  agentId: string;
40
19
  replyChannel?: string;
@@ -42,127 +21,63 @@ export type ResolvedEigenFluxServerConfig = {
42
21
  replyAccountId?: string;
43
22
  routeOverrides: NotificationRouteOverrides;
44
23
  };
24
+ export type DiscoveredServer = {
25
+ name: string;
26
+ endpoint: string;
27
+ stream_endpoint?: string;
28
+ current: boolean;
29
+ };
30
+ export type EigenFluxPluginConfig = {
31
+ eigenfluxBin?: string;
32
+ skills?: string[];
33
+ openclawCliBin?: string;
34
+ serverRouting?: Record<string, {
35
+ sessionKey?: string;
36
+ agentId?: string;
37
+ replyChannel?: string;
38
+ replyTo?: string;
39
+ replyAccountId?: string;
40
+ }>;
41
+ };
45
42
  export type ResolvedEigenFluxPluginConfig = {
46
- gatewayUrl: string;
47
- gatewayToken?: string;
43
+ eigenfluxBin: string;
44
+ skills: string[];
48
45
  openclawCliBin: string;
49
- servers: ResolvedEigenFluxServerConfig[];
46
+ serverRouting: Record<string, RoutingConfig>;
50
47
  };
51
- type GlobalGatewayConfig = {
52
- gateway?: {
53
- auth?: {
54
- token?: string;
55
- };
56
- };
48
+ export type DiscoveryResult = {
49
+ kind: 'ok';
50
+ servers: DiscoveredServer[];
51
+ } | {
52
+ kind: 'not_installed';
53
+ bin: string;
57
54
  };
55
+ export declare function discoverServers(eigenfluxBin: string, logger?: Logger): Promise<DiscoveryResult>;
56
+ export declare function resolveEigenfluxHome(): string;
57
+ export declare function resolvePluginConfig(pluginConfig: unknown, logger?: Logger): ResolvedEigenFluxPluginConfig;
58
58
  export declare function expandHomeDir(input: string): string;
59
- export declare function resolveServerSkillPath(server: {
60
- endpoint: string;
61
- workdir: string;
62
- }): string;
63
- export declare function resolvePluginConfig(pluginConfig: unknown, globalConfig?: GlobalGatewayConfig, logger?: Logger): ResolvedEigenFluxPluginConfig;
64
59
  export declare const PLUGIN_CONFIG: {
65
- readonly DEFAULT_SERVER_NAME: "eigenflux";
66
- readonly DEFAULT_ENDPOINT: "https://www.eigenflux.ai";
67
- readonly DEFAULT_GATEWAY_URL: "ws://127.0.0.1:18789";
60
+ readonly DEFAULT_EIGENFLUX_BIN: "eigenflux";
68
61
  readonly DEFAULT_SESSION_KEY: "main";
69
62
  readonly DEFAULT_AGENT_ID: "main";
70
63
  readonly DEFAULT_OPENCLAW_CLI_BIN: "openclaw";
71
- readonly DEFAULT_POLL_INTERVAL_SEC: 300;
72
- readonly DEFAULT_PM_POLL_INTERVAL_SEC: 60;
73
- readonly MIN_POLL_INTERVAL_SEC: 10;
74
- readonly MAX_POLL_INTERVAL_SEC: number;
75
64
  readonly HOST_KIND: "openclaw";
76
- readonly CREDENTIALS_FILE: "credentials.json";
77
- readonly PLUGIN_VERSION: "0.0.3";
78
- readonly USER_AGENT: string;
65
+ readonly PLUGIN_VERSION: "0.0.5";
79
66
  };
80
- export declare function buildEigenFluxRequestHeaders(accessToken: string): Record<string, string>;
81
67
  export declare const PLUGIN_CONFIG_SCHEMA: {
82
68
  readonly type: "object";
83
69
  readonly additionalProperties: false;
84
70
  readonly properties: {
85
- readonly gatewayUrl: {
71
+ readonly eigenfluxBin: {
86
72
  readonly type: "string";
87
- readonly description: "OpenClaw Gateway WebSocket URL used for Gateway RPC fallback";
88
- readonly default: "ws://127.0.0.1:18789";
89
- };
90
- readonly gatewayToken: {
91
- readonly type: "string";
92
- readonly description: "Optional gateway token override used for Gateway RPC fallback";
73
+ readonly description: "Path to the eigenflux CLI binary";
74
+ readonly default: "eigenflux";
93
75
  };
94
76
  readonly openclawCliBin: {
95
77
  readonly type: "string";
96
78
  readonly description: "OpenClaw CLI binary used by runtime command fallbacks";
97
79
  readonly default: "openclaw";
98
80
  };
99
- readonly servers: {
100
- readonly type: "array";
101
- readonly description: "Server list. When empty or when no server named eigenflux is provided, the plugin prepends a default eigenflux server.";
102
- readonly default: readonly [];
103
- readonly items: {
104
- readonly type: "object";
105
- readonly additionalProperties: false;
106
- readonly properties: {
107
- readonly enabled: {
108
- readonly type: "boolean";
109
- readonly description: "Enable or disable background polling for this server";
110
- readonly default: true;
111
- };
112
- readonly name: {
113
- readonly type: "string";
114
- readonly description: "Server name used for routing, workdir defaults, and diagnostics";
115
- readonly default: "eigenflux";
116
- };
117
- readonly endpoint: {
118
- readonly type: "string";
119
- readonly description: "EigenFlux API base URL for this server";
120
- readonly default: "https://www.eigenflux.ai";
121
- };
122
- readonly workdir: {
123
- readonly type: "string";
124
- readonly description: "Directory used to store server credentials and remembered session state";
125
- };
126
- readonly pollInterval: {
127
- readonly type: "integer";
128
- readonly minimum: 10;
129
- readonly maximum: number;
130
- readonly description: "Feed polling interval in seconds for this server";
131
- readonly default: 300;
132
- };
133
- readonly pmPollInterval: {
134
- readonly type: "integer";
135
- readonly minimum: 10;
136
- readonly maximum: number;
137
- readonly description: "Private message polling interval in seconds for this server";
138
- readonly default: 60;
139
- };
140
- readonly sessionKey: {
141
- readonly type: "string";
142
- readonly description: "Target session key used by runtime.subagent and heartbeat fallback";
143
- readonly default: "main";
144
- };
145
- readonly agentId: {
146
- readonly type: "string";
147
- readonly description: "Agent id used by Gateway agent and CLI fallbacks";
148
- readonly default: "main";
149
- };
150
- readonly replyChannel: {
151
- readonly type: "string";
152
- readonly description: "Explicit reply channel used by Gateway agent and CLI fallbacks";
153
- };
154
- readonly replyTo: {
155
- readonly type: "string";
156
- readonly description: "Explicit reply target used by Gateway agent and CLI fallbacks";
157
- };
158
- readonly replyAccountId: {
159
- readonly type: "string";
160
- readonly description: "Optional reply account id for multi-account channel delivery";
161
- };
162
- };
163
- };
164
- };
165
81
  };
166
82
  };
167
- export {};
168
83
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAelC,MAAM,MAAM,0BAA0B,GAAG;IACvC,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,qBAAqB,EAAE,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,0BAA0B,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,6BAA6B,EAAE,CAAC;CAC1C,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,OAAO,CAAC,EAAE;QACR,IAAI,CAAC,EAAE;YACL,KAAK,CAAC,EAAE,MAAM,CAAC;SAChB,CAAC;KACH,CAAC;CACH,CAAC;AA4NF,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQnD;AAUD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,MAAM,CAMT;AAED,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,OAAO,EACrB,YAAY,CAAC,EAAE,mBAAmB,EAClC,MAAM,CAAC,EAAE,MAAM,GACd,6BAA6B,CAe/B;AAgED,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;CAehB,CAAC;AAEX,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQxF;AAED,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BvB,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAalC,MAAM,MAAM,0BAA0B,GAAG;IACvC,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,0BAA0B,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC,CAAC;CACJ,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CAC9C,CAAC;AA8FF,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,gBAAgB,EAAE,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3C,wBAAsB,eAAe,CACnC,YAAY,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,eAAe,CAAC,CA0B1B;AAID,wBAAgB,oBAAoB,IAAI,MAAM,CAU7C;AA6BD,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,OAAO,EACrB,MAAM,CAAC,EAAE,MAAM,GACd,6BAA6B,CAuB/B;AAID,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQnD;AAED,eAAO,MAAM,aAAa;;;;;;;CAOhB,CAAC;AAEX,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;CAevB,CAAC"}
package/dist/config.js CHANGED
@@ -1,6 +1,10 @@
1
1
  "use strict";
2
2
  /**
3
- * Internal configuration for the EigenFlux plugin.
3
+ * Configuration for the EigenFlux plugin.
4
+ *
5
+ * Server management is now handled by the eigenflux CLI.
6
+ * The plugin config only holds plugin-level settings and
7
+ * per-server notification routing overrides.
4
8
  */
5
9
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
10
  if (k2 === undefined) k2 = k;
@@ -37,45 +41,21 @@ var __importStar = (this && this.__importStar) || (function () {
37
41
  })();
38
42
  Object.defineProperty(exports, "__esModule", { value: true });
39
43
  exports.PLUGIN_CONFIG_SCHEMA = exports.PLUGIN_CONFIG = void 0;
40
- exports.expandHomeDir = expandHomeDir;
41
- exports.resolveServerSkillPath = resolveServerSkillPath;
44
+ exports.discoverServers = discoverServers;
45
+ exports.resolveEigenfluxHome = resolveEigenfluxHome;
42
46
  exports.resolvePluginConfig = resolvePluginConfig;
43
- exports.buildEigenFluxRequestHeaders = buildEigenFluxRequestHeaders;
44
- const fs = __importStar(require("fs"));
47
+ exports.expandHomeDir = expandHomeDir;
45
48
  const os = __importStar(require("os"));
46
49
  const path = __importStar(require("path"));
47
- const PLUGIN_VERSION = '0.0.3';
48
- const DEFAULT_SERVER_NAME = 'eigenflux';
49
- const DEFAULT_ENDPOINT = 'https://www.eigenflux.ai';
50
- const DEFAULT_GATEWAY_URL = 'ws://127.0.0.1:18789';
50
+ const reply_target_1 = require("./reply-target");
51
+ const cli_executor_1 = require("./cli-executor");
52
+ const PLUGIN_VERSION = '0.0.5';
53
+ const DEFAULT_EIGENFLUX_BIN = 'eigenflux';
51
54
  const DEFAULT_SESSION_KEY = 'main';
52
55
  const DEFAULT_AGENT_ID = 'main';
53
56
  const DEFAULT_OPENCLAW_CLI_BIN = 'openclaw';
54
- const DEFAULT_POLL_INTERVAL_SEC = 300;
55
- const DEFAULT_PM_POLL_INTERVAL_SEC = 60;
56
- const MIN_POLL_INTERVAL_SEC = 10;
57
- const MAX_POLL_INTERVAL_SEC = 24 * 60 * 60;
58
57
  const HOST_KIND = 'openclaw';
59
- function detectOpenClawVersion() {
60
- try {
61
- // eslint-disable-next-line @typescript-eslint/no-require-imports
62
- const pkg = require('openclaw/package.json');
63
- return pkg.version;
64
- }
65
- catch {
66
- return undefined;
67
- }
68
- }
69
- function buildUserAgent() {
70
- const parts = [];
71
- parts.push(`node/${process.version.replace(/^v/, '')}`);
72
- parts.push(`(${os.platform()}; ${os.arch()}; ${os.release()})`);
73
- const openclawVersion = detectOpenClawVersion();
74
- if (openclawVersion) {
75
- parts.push(`openclaw/${openclawVersion}`);
76
- }
77
- return parts.join(' ');
78
- }
58
+ // ─── Helpers ────────────────────────────────────────────────────────────────
79
59
  function isRecord(value) {
80
60
  return typeof value === 'object' && value !== null && !Array.isArray(value);
81
61
  }
@@ -86,30 +66,6 @@ function readNonEmptyString(value) {
86
66
  const trimmed = value.trim();
87
67
  return trimmed.length > 0 ? trimmed : undefined;
88
68
  }
89
- function parsePositiveInteger(value, fallback) {
90
- if (typeof value === 'number' && Number.isFinite(value) && value > 0) {
91
- return Math.floor(value);
92
- }
93
- if (typeof value === 'string') {
94
- const parsed = parseInt(value, 10);
95
- if (Number.isFinite(parsed) && parsed > 0) {
96
- return parsed;
97
- }
98
- }
99
- return fallback;
100
- }
101
- function parsePollingIntervalSeconds(value, fallback, options) {
102
- const parsed = parsePositiveInteger(value, fallback);
103
- if (parsed < MIN_POLL_INTERVAL_SEC) {
104
- options.logger?.warn(`${options.fieldName} for server "${options.serverName}" is below ${MIN_POLL_INTERVAL_SEC}s; clamping to ${MIN_POLL_INTERVAL_SEC}s`);
105
- return MIN_POLL_INTERVAL_SEC;
106
- }
107
- if (parsed <= MAX_POLL_INTERVAL_SEC) {
108
- return parsed;
109
- }
110
- options.logger?.warn(`${options.fieldName} for server "${options.serverName}" exceeds ${MAX_POLL_INTERVAL_SEC}s; clamping to ${MAX_POLL_INTERVAL_SEC}s`);
111
- return MAX_POLL_INTERVAL_SEC;
112
- }
113
69
  function isSessionPeerShape(value) {
114
70
  const normalized = value?.trim().toLowerCase();
115
71
  return (normalized === 'direct' ||
@@ -132,85 +88,108 @@ function deriveNotificationRoute(sessionKey) {
132
88
  agentId,
133
89
  replyChannel: readNonEmptyString(parts[2]),
134
90
  replyAccountId: readNonEmptyString(parts[3]),
135
- replyTo: readNonEmptyString(parts.slice(5).join(':')),
91
+ replyTo: (0, reply_target_1.normalizeReplyTarget)(parts.slice(5).join(':'), {
92
+ channel: readNonEmptyString(parts[2]),
93
+ sessionKey: trimmed,
94
+ }),
136
95
  };
137
96
  }
138
97
  if (parts.length >= 5 && isSessionPeerShape(parts[3])) {
139
98
  return {
140
99
  agentId,
141
100
  replyChannel: readNonEmptyString(parts[2]),
142
- replyTo: readNonEmptyString(parts.slice(4).join(':')),
101
+ replyTo: (0, reply_target_1.normalizeReplyTarget)(parts.slice(4).join(':'), {
102
+ channel: readNonEmptyString(parts[2]),
103
+ sessionKey: trimmed,
104
+ }),
143
105
  };
144
106
  }
145
107
  return { agentId };
146
108
  }
147
109
  function createRouteOverrides(normalized) {
110
+ const sessionKey = readNonEmptyString(normalized.sessionKey);
111
+ const agentId = readNonEmptyString(normalized.agentId);
112
+ const replyChannel = readNonEmptyString(normalized.replyChannel);
113
+ const replyTo = readNonEmptyString(normalized.replyTo);
114
+ const replyAccountId = readNonEmptyString(normalized.replyAccountId);
148
115
  return {
149
- sessionKey: readNonEmptyString(normalized.sessionKey) !== undefined,
150
- agentId: readNonEmptyString(normalized.agentId) !== undefined,
151
- replyChannel: readNonEmptyString(normalized.replyChannel) !== undefined,
152
- replyTo: readNonEmptyString(normalized.replyTo) !== undefined,
153
- replyAccountId: readNonEmptyString(normalized.replyAccountId) !== undefined,
116
+ sessionKey: sessionKey !== undefined && sessionKey !== DEFAULT_SESSION_KEY,
117
+ agentId: agentId !== undefined &&
118
+ agentId !== DEFAULT_AGENT_ID &&
119
+ !(sessionKey && deriveNotificationRoute(sessionKey).agentId === agentId),
120
+ replyChannel: replyChannel !== undefined,
121
+ replyTo: replyTo !== undefined,
122
+ replyAccountId: replyAccountId !== undefined,
154
123
  };
155
124
  }
156
- function hasExplicitDefaultServer(servers) {
157
- return servers.some((server) => readNonEmptyString(server.name)?.toLowerCase() === DEFAULT_SERVER_NAME);
158
- }
159
- function normalizeServersInput(config) {
160
- const explicitServers = Array.isArray(config.servers)
161
- ? config.servers.filter(isRecord)
162
- : [];
163
- if (!hasExplicitDefaultServer(explicitServers)) {
164
- return [{}, ...explicitServers];
165
- }
166
- return explicitServers;
167
- }
168
- function createServerName(baseName, usedNames) {
169
- if (!usedNames.has(baseName)) {
170
- usedNames.add(baseName);
171
- return baseName;
172
- }
173
- let suffix = 2;
174
- while (usedNames.has(`${baseName}-${suffix}`)) {
175
- suffix += 1;
125
+ async function discoverServers(eigenfluxBin, logger) {
126
+ const result = await (0, cli_executor_1.execEigenflux)(eigenfluxBin, ['server', 'list', '--format', 'json'], { logger });
127
+ if (result.kind === 'success') {
128
+ if (Array.isArray(result.data)) {
129
+ return { kind: 'ok', servers: result.data };
130
+ }
131
+ logger?.warn('eigenflux server list returned non-array data');
132
+ return { kind: 'ok', servers: [] };
133
+ }
134
+ if (result.kind === 'not_installed') {
135
+ return { kind: 'not_installed', bin: result.bin };
136
+ }
137
+ if (result.kind === 'auth_required') {
138
+ logger?.warn('eigenflux server list: auth required (unexpected)');
139
+ return { kind: 'ok', servers: [] };
140
+ }
141
+ logger?.error(`eigenflux server list failed: ${result.error.message}`);
142
+ return { kind: 'ok', servers: [] };
143
+ }
144
+ // ─── EigenFlux Home ─────────────────────────────────────────────────────────
145
+ function resolveEigenfluxHome() {
146
+ const envHome = process.env.EIGENFLUX_HOME;
147
+ if (envHome) {
148
+ const expanded = expandHomeDir(envHome);
149
+ if (!expanded.endsWith('.eigenflux')) {
150
+ return path.join(expanded, '.eigenflux');
151
+ }
152
+ return expanded;
176
153
  }
177
- const uniqueName = `${baseName}-${suffix}`;
178
- usedNames.add(uniqueName);
179
- return uniqueName;
154
+ return path.join(os.homedir(), '.eigenflux');
180
155
  }
181
- function resolveServerConfig(serverConfig, index, usedNames, logger) {
182
- const normalized = isRecord(serverConfig) ? serverConfig : {};
183
- const rawName = readNonEmptyString(normalized.name) ??
184
- (index === 0 ? DEFAULT_SERVER_NAME : `server-${index + 1}`);
185
- const name = createServerName(rawName, usedNames);
156
+ // ─── Config Resolution ──────────────────────────────────────────────────────
157
+ function resolveRoutingConfig(raw, logger) {
158
+ const normalized = isRecord(raw) ? raw : {};
186
159
  const sessionKey = readNonEmptyString(normalized.sessionKey) ?? DEFAULT_SESSION_KEY;
187
160
  const derivedRoute = deriveNotificationRoute(sessionKey);
188
- const workdir = expandHomeDir(readNonEmptyString(normalized.workdir) ?? `~/.openclaw/${name}`);
189
- const sessionStorePath = readNonEmptyString(normalized.sessionStorePath);
161
+ const replyChannel = readNonEmptyString(normalized.replyChannel) ?? derivedRoute.replyChannel;
162
+ const replyTo = (0, reply_target_1.normalizeReplyTarget)(readNonEmptyString(normalized.replyTo), {
163
+ channel: replyChannel,
164
+ sessionKey,
165
+ }) ?? derivedRoute.replyTo;
190
166
  return {
191
- enabled: normalized.enabled !== false,
192
- name,
193
- endpoint: readNonEmptyString(normalized.endpoint) ?? DEFAULT_ENDPOINT,
194
- workdir,
195
- pollIntervalSec: parsePollingIntervalSeconds(normalized.pollInterval, DEFAULT_POLL_INTERVAL_SEC, {
196
- fieldName: 'pollInterval',
197
- serverName: name,
198
- logger,
199
- }),
200
- pmPollIntervalSec: parsePollingIntervalSeconds(normalized.pmPollInterval, DEFAULT_PM_POLL_INTERVAL_SEC, {
201
- fieldName: 'pmPollInterval',
202
- serverName: name,
203
- logger,
204
- }),
205
167
  sessionKey,
206
168
  agentId: readNonEmptyString(normalized.agentId) ?? derivedRoute.agentId ?? DEFAULT_AGENT_ID,
207
- replyChannel: readNonEmptyString(normalized.replyChannel) ?? derivedRoute.replyChannel,
208
- replyTo: readNonEmptyString(normalized.replyTo) ?? derivedRoute.replyTo,
169
+ replyChannel,
170
+ replyTo,
209
171
  replyAccountId: readNonEmptyString(normalized.replyAccountId) ?? derivedRoute.replyAccountId,
210
172
  routeOverrides: createRouteOverrides(normalized),
211
- ...(sessionStorePath ? { sessionStorePath: expandHomeDir(sessionStorePath) } : {}),
212
173
  };
213
174
  }
175
+ function resolvePluginConfig(pluginConfig, logger) {
176
+ const normalized = isRecord(pluginConfig) ? pluginConfig : {};
177
+ const rawRouting = isRecord(normalized.serverRouting) ? normalized.serverRouting : {};
178
+ const serverRouting = {};
179
+ for (const [serverName, rawConfig] of Object.entries(rawRouting)) {
180
+ serverRouting[serverName] = resolveRoutingConfig(isRecord(rawConfig) ? rawConfig : undefined, logger);
181
+ }
182
+ const rawSkills = Array.isArray(normalized.skills)
183
+ ? normalized.skills.filter((s) => typeof s === 'string' && s.trim().length > 0)
184
+ : ['ef-broadcast', 'ef-communication'];
185
+ return {
186
+ eigenfluxBin: readNonEmptyString(normalized.eigenfluxBin) ?? DEFAULT_EIGENFLUX_BIN,
187
+ skills: rawSkills,
188
+ openclawCliBin: readNonEmptyString(normalized.openclawCliBin) ?? DEFAULT_OPENCLAW_CLI_BIN,
189
+ serverRouting,
190
+ };
191
+ }
192
+ // ─── Exports ────────────────────────────────────────────────────────────────
214
193
  function expandHomeDir(input) {
215
194
  if (input === '~') {
216
195
  return os.homedir();
@@ -220,142 +199,28 @@ function expandHomeDir(input) {
220
199
  }
221
200
  return input;
222
201
  }
223
- function buildSkillUrl(endpoint) {
224
- try {
225
- return new URL('skill.md', endpoint.endsWith('/') ? endpoint : `${endpoint}/`).toString();
226
- }
227
- catch {
228
- return `${endpoint.replace(/\/+$/u, '')}/skill.md`;
229
- }
230
- }
231
- function resolveServerSkillPath(server) {
232
- const localSkillPath = path.join(server.workdir, 'skill.md');
233
- if (fs.existsSync(localSkillPath)) {
234
- return localSkillPath;
235
- }
236
- return buildSkillUrl(server.endpoint);
237
- }
238
- function resolvePluginConfig(pluginConfig, globalConfig, logger) {
239
- const normalized = isRecord(pluginConfig) ? pluginConfig : {};
240
- const usedNames = new Set();
241
- return {
242
- gatewayUrl: readNonEmptyString(normalized.gatewayUrl) ?? DEFAULT_GATEWAY_URL,
243
- gatewayToken: readNonEmptyString(normalized.gatewayToken) ??
244
- readNonEmptyString(globalConfig?.gateway?.auth?.token),
245
- openclawCliBin: readNonEmptyString(normalized.openclawCliBin) ?? DEFAULT_OPENCLAW_CLI_BIN,
246
- servers: normalizeServersInput(normalized).map((server, index) => resolveServerConfig(server, index, usedNames, logger)),
247
- };
248
- }
249
- const SERVER_CONFIG_SCHEMA = {
250
- type: 'object',
251
- additionalProperties: false,
252
- properties: {
253
- enabled: {
254
- type: 'boolean',
255
- description: 'Enable or disable background polling for this server',
256
- default: true,
257
- },
258
- name: {
259
- type: 'string',
260
- description: 'Server name used for routing, workdir defaults, and diagnostics',
261
- default: DEFAULT_SERVER_NAME,
262
- },
263
- endpoint: {
264
- type: 'string',
265
- description: 'EigenFlux API base URL for this server',
266
- default: DEFAULT_ENDPOINT,
267
- },
268
- workdir: {
269
- type: 'string',
270
- description: 'Directory used to store server credentials and remembered session state',
271
- },
272
- pollInterval: {
273
- type: 'integer',
274
- minimum: MIN_POLL_INTERVAL_SEC,
275
- maximum: MAX_POLL_INTERVAL_SEC,
276
- description: 'Feed polling interval in seconds for this server',
277
- default: DEFAULT_POLL_INTERVAL_SEC,
278
- },
279
- pmPollInterval: {
280
- type: 'integer',
281
- minimum: MIN_POLL_INTERVAL_SEC,
282
- maximum: MAX_POLL_INTERVAL_SEC,
283
- description: 'Private message polling interval in seconds for this server',
284
- default: DEFAULT_PM_POLL_INTERVAL_SEC,
285
- },
286
- sessionKey: {
287
- type: 'string',
288
- description: 'Target session key used by runtime.subagent and heartbeat fallback',
289
- default: DEFAULT_SESSION_KEY,
290
- },
291
- agentId: {
292
- type: 'string',
293
- description: 'Agent id used by Gateway agent and CLI fallbacks',
294
- default: DEFAULT_AGENT_ID,
295
- },
296
- replyChannel: {
297
- type: 'string',
298
- description: 'Explicit reply channel used by Gateway agent and CLI fallbacks',
299
- },
300
- replyTo: {
301
- type: 'string',
302
- description: 'Explicit reply target used by Gateway agent and CLI fallbacks',
303
- },
304
- replyAccountId: {
305
- type: 'string',
306
- description: 'Optional reply account id for multi-account channel delivery',
307
- },
308
- },
309
- };
310
202
  exports.PLUGIN_CONFIG = {
311
- DEFAULT_SERVER_NAME,
312
- DEFAULT_ENDPOINT,
313
- DEFAULT_GATEWAY_URL,
203
+ DEFAULT_EIGENFLUX_BIN,
314
204
  DEFAULT_SESSION_KEY,
315
205
  DEFAULT_AGENT_ID,
316
206
  DEFAULT_OPENCLAW_CLI_BIN,
317
- DEFAULT_POLL_INTERVAL_SEC,
318
- DEFAULT_PM_POLL_INTERVAL_SEC,
319
- MIN_POLL_INTERVAL_SEC,
320
- MAX_POLL_INTERVAL_SEC,
321
207
  HOST_KIND,
322
- CREDENTIALS_FILE: 'credentials.json',
323
208
  PLUGIN_VERSION,
324
- USER_AGENT: buildUserAgent(),
325
209
  };
326
- function buildEigenFluxRequestHeaders(accessToken) {
327
- return {
328
- Authorization: `Bearer ${accessToken}`,
329
- 'Content-Type': 'application/json',
330
- 'User-Agent': exports.PLUGIN_CONFIG.USER_AGENT,
331
- 'X-Plugin-Ver': exports.PLUGIN_CONFIG.PLUGIN_VERSION,
332
- 'X-Host-Kind': exports.PLUGIN_CONFIG.HOST_KIND,
333
- };
334
- }
335
210
  exports.PLUGIN_CONFIG_SCHEMA = {
336
211
  type: 'object',
337
212
  additionalProperties: false,
338
213
  properties: {
339
- gatewayUrl: {
340
- type: 'string',
341
- description: 'OpenClaw Gateway WebSocket URL used for Gateway RPC fallback',
342
- default: DEFAULT_GATEWAY_URL,
343
- },
344
- gatewayToken: {
214
+ eigenfluxBin: {
345
215
  type: 'string',
346
- description: 'Optional gateway token override used for Gateway RPC fallback',
216
+ description: 'Path to the eigenflux CLI binary',
217
+ default: DEFAULT_EIGENFLUX_BIN,
347
218
  },
348
219
  openclawCliBin: {
349
220
  type: 'string',
350
221
  description: 'OpenClaw CLI binary used by runtime command fallbacks',
351
222
  default: DEFAULT_OPENCLAW_CLI_BIN,
352
223
  },
353
- servers: {
354
- type: 'array',
355
- description: 'Server list. When empty or when no server named eigenflux is provided, the plugin prepends a default eigenflux server.',
356
- default: [],
357
- items: SERVER_CONFIG_SCHEMA,
358
- },
359
224
  },
360
225
  };
361
226
  //# sourceMappingURL=config.js.map