@phronesis-io/openclaw-eigenflux 0.0.4 → 0.0.7
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/README.md +15 -161
- package/dist/agent-prompt-templates.d.ts +14 -12
- package/dist/agent-prompt-templates.d.ts.map +1 -1
- package/dist/agent-prompt-templates.js +27 -35
- package/dist/agent-prompt-templates.js.map +1 -1
- package/dist/cli-executor.d.ts +32 -0
- package/dist/cli-executor.d.ts.map +1 -0
- package/dist/cli-executor.js +75 -0
- package/dist/cli-executor.js.map +1 -0
- package/dist/config.d.ts +41 -126
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +94 -229
- package/dist/config.js.map +1 -1
- package/dist/credentials-loader.d.ts +6 -5
- package/dist/credentials-loader.d.ts.map +1 -1
- package/dist/credentials-loader.js +17 -21
- package/dist/credentials-loader.js.map +1 -1
- package/dist/index.d.ts +3 -73
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +262 -275
- package/dist/index.js.map +1 -1
- package/dist/notification-route-resolver.d.ts +24 -2
- package/dist/notification-route-resolver.d.ts.map +1 -1
- package/dist/notification-route-resolver.js +258 -43
- package/dist/notification-route-resolver.js.map +1 -1
- package/dist/notifier.d.ts +9 -17
- package/dist/notifier.d.ts.map +1 -1
- package/dist/notifier.js +133 -66
- package/dist/notifier.js.map +1 -1
- package/dist/polling-client.d.ts +31 -19
- package/dist/polling-client.d.ts.map +1 -1
- package/dist/polling-client.js +102 -127
- package/dist/polling-client.js.map +1 -1
- package/dist/reply-target.d.ts +8 -0
- package/dist/reply-target.d.ts.map +1 -0
- package/dist/reply-target.js +104 -0
- package/dist/reply-target.js.map +1 -0
- package/dist/session-route-memory.d.ts +12 -3
- package/dist/session-route-memory.d.ts.map +1 -1
- package/dist/session-route-memory.js +83 -80
- package/dist/session-route-memory.js.map +1 -1
- package/dist/stream-client.d.ts +48 -0
- package/dist/stream-client.d.ts.map +1 -0
- package/dist/stream-client.js +168 -0
- package/dist/stream-client.js.map +1 -0
- package/openclaw.plugin.json +5 -75
- package/package.json +6 -8
- package/skills/ef-broadcast/SKILL.md +84 -0
- package/skills/ef-broadcast/references/feed.md +127 -0
- package/skills/ef-broadcast/references/publish.md +119 -0
- package/skills/ef-communication/SKILL.md +95 -0
- package/skills/ef-communication/references/message.md +132 -0
- package/skills/ef-communication/references/relations.md +215 -0
- package/skills/ef-communication/references/stream.md +66 -0
- package/skills/ef-profile/SKILL.md +138 -0
- package/skills/ef-profile/references/auth.md +103 -0
- package/skills/ef-profile/references/config.md +54 -0
- package/skills/ef-profile/references/onboarding.md +172 -0
- package/skills/ef-profile/references/server-management.md +67 -0
- package/dist/gateway-rpc-client.d.ts +0 -26
- package/dist/gateway-rpc-client.d.ts.map +0 -1
- package/dist/gateway-rpc-client.js +0 -288
- package/dist/gateway-rpc-client.js.map +0 -1
- package/dist/pm-polling-client.d.ts +0 -52
- package/dist/pm-polling-client.d.ts.map +0 -1
- package/dist/pm-polling-client.js +0 -182
- package/dist/pm-polling-client.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,141 +1,227 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const polling_client_1 = require("./polling-client");
|
|
4
|
-
const
|
|
4
|
+
const stream_client_1 = require("./stream-client");
|
|
5
|
+
const cli_executor_1 = require("./cli-executor");
|
|
5
6
|
const logger_1 = require("./logger");
|
|
6
7
|
const credentials_loader_1 = require("./credentials-loader");
|
|
7
8
|
const config_1 = require("./config");
|
|
8
9
|
const notification_route_resolver_1 = require("./notification-route-resolver");
|
|
9
10
|
const agent_prompt_templates_1 = require("./agent-prompt-templates");
|
|
10
11
|
const notifier_1 = require("./notifier");
|
|
12
|
+
const reply_target_1 = require("./reply-target");
|
|
11
13
|
const session_route_memory_1 = require("./session-route-memory");
|
|
12
|
-
const COMMAND_NAMES = ['auth', 'profile', 'servers', 'feed', 'pm', 'here'];
|
|
14
|
+
const COMMAND_NAMES = ['auth', 'profile', 'servers', 'feed', 'pm', 'here', 'version'];
|
|
13
15
|
const COMMAND_NAME_SET = new Set(COMMAND_NAMES);
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
const DEFAULT_ROUTING = {
|
|
17
|
+
sessionKey: config_1.PLUGIN_CONFIG.DEFAULT_SESSION_KEY,
|
|
18
|
+
agentId: config_1.PLUGIN_CONFIG.DEFAULT_AGENT_ID,
|
|
19
|
+
routeOverrides: {
|
|
20
|
+
sessionKey: false,
|
|
21
|
+
agentId: false,
|
|
22
|
+
replyChannel: false,
|
|
23
|
+
replyTo: false,
|
|
24
|
+
replyAccountId: false,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
18
27
|
function register(api) {
|
|
19
|
-
const logger = new logger_1.Logger(api
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
const logger = new logger_1.Logger(resolvePluginLogger(api));
|
|
29
|
+
const pluginConfig = (0, config_1.resolvePluginConfig)(api.pluginConfig, logger);
|
|
30
|
+
const eigenfluxHome = (0, config_1.resolveEigenfluxHome)();
|
|
31
|
+
let runtimes = [];
|
|
32
|
+
let notInstalledPromptDelivered = false;
|
|
33
|
+
// Register a single meta-service that discovers servers on start
|
|
34
|
+
api.registerService({
|
|
35
|
+
id: 'eigenflux:discovery',
|
|
36
|
+
start: async () => {
|
|
37
|
+
logger.info('Starting EigenFlux discovery service...');
|
|
38
|
+
const discovery = await (0, config_1.discoverServers)(pluginConfig.eigenfluxBin, logger);
|
|
39
|
+
if (discovery.kind === 'not_installed') {
|
|
40
|
+
logger.warn(`EigenFlux CLI not installed (bin=${discovery.bin}); delivering install prompt to user`);
|
|
41
|
+
if (!notInstalledPromptDelivered) {
|
|
42
|
+
notInstalledPromptDelivered = true;
|
|
43
|
+
await deliverNotInstalledPrompt(api, logger, pluginConfig, eigenfluxHome, discovery.bin);
|
|
44
|
+
}
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const servers = discovery.servers;
|
|
48
|
+
if (servers.length === 0) {
|
|
49
|
+
logger.warn('No EigenFlux servers discovered; services will not start');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
logger.info(`Discovered ${servers.length} server(s): ${servers.map((s) => s.name).join(', ')}`);
|
|
53
|
+
runtimes = servers.map((server) => createServerRuntime(api, logger, pluginConfig, server, eigenfluxHome));
|
|
54
|
+
for (const runtime of runtimes) {
|
|
55
|
+
logger.info(`Starting services for server=${runtime.server.name}`);
|
|
56
|
+
await runtime.feedPoller.start();
|
|
57
|
+
await runtime.streamClient.start();
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
stop: async () => {
|
|
61
|
+
logger.info('Stopping EigenFlux discovery service...');
|
|
62
|
+
for (const runtime of runtimes) {
|
|
63
|
+
logger.info(`Stopping services for server=${runtime.server.name}`);
|
|
64
|
+
runtime.feedPoller.stop();
|
|
65
|
+
await runtime.streamClient.stop();
|
|
66
|
+
}
|
|
67
|
+
runtimes = [];
|
|
68
|
+
notInstalledPromptDelivered = false;
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
registerCommand(api, logger, pluginConfig, eigenfluxHome, () => runtimes, (next) => {
|
|
72
|
+
runtimes = next;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function resolvePluginLogger(api) {
|
|
76
|
+
const runtimeLogging = api.runtime?.logging;
|
|
77
|
+
if (runtimeLogging && typeof runtimeLogging.getChildLogger === 'function') {
|
|
78
|
+
try {
|
|
79
|
+
const child = runtimeLogging.getChildLogger({ plugin: 'eigenflux' });
|
|
80
|
+
if (child) {
|
|
81
|
+
return child;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// fall through to api.logger
|
|
86
|
+
}
|
|
29
87
|
}
|
|
30
|
-
|
|
31
|
-
registerCommand(api, logger, runtimes);
|
|
32
|
-
logger.info(`EigenFlux activated with ${enabledRuntimes.length}/${runtimes.length} enabled server(s)`);
|
|
88
|
+
return api.logger;
|
|
33
89
|
}
|
|
34
90
|
const plugin = {
|
|
35
91
|
id: 'openclaw-eigenflux',
|
|
36
92
|
name: 'EigenFlux',
|
|
37
|
-
description: 'OpenClaw extension for EigenFlux
|
|
93
|
+
description: 'OpenClaw extension for EigenFlux with CLI-based feed polling and PM streaming',
|
|
38
94
|
configSchema: config_1.PLUGIN_CONFIG_SCHEMA,
|
|
39
95
|
register,
|
|
40
96
|
};
|
|
41
97
|
exports.default = plugin;
|
|
42
|
-
|
|
43
|
-
|
|
98
|
+
const INSTALL_COMMAND = 'curl -fsSL https://eigenflux.ai/install.sh | bash';
|
|
99
|
+
async function deliverNotInstalledPrompt(api, logger, pluginConfig, _eigenfluxHome, bin) {
|
|
100
|
+
// Intentionally no workdir: the bootstrap notifier must not read or persist
|
|
101
|
+
// any remembered session route under <eigenfluxHome>/bootstrap.
|
|
44
102
|
const notifier = new notifier_1.EigenFluxNotifier(api, logger, {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
103
|
+
sessionKey: DEFAULT_ROUTING.sessionKey,
|
|
104
|
+
agentId: DEFAULT_ROUTING.agentId,
|
|
105
|
+
replyChannel: DEFAULT_ROUTING.replyChannel,
|
|
106
|
+
replyTo: DEFAULT_ROUTING.replyTo,
|
|
107
|
+
replyAccountId: DEFAULT_ROUTING.replyAccountId,
|
|
108
|
+
openclawCliBin: pluginConfig.openclawCliBin,
|
|
109
|
+
routeOverrides: DEFAULT_ROUTING.routeOverrides,
|
|
110
|
+
});
|
|
111
|
+
await notifier.deliver((0, agent_prompt_templates_1.buildNotInstalledPromptTemplate)({ bin, installCommand: INSTALL_COMMAND }));
|
|
112
|
+
}
|
|
113
|
+
function createServerRuntime(api, logger, pluginConfig, server, eigenfluxHome) {
|
|
114
|
+
const routing = pluginConfig.serverRouting[server.name] ?? DEFAULT_ROUTING;
|
|
115
|
+
const credentialsLoader = new credentials_loader_1.CredentialsLoader(logger, eigenfluxHome, server.name);
|
|
116
|
+
const notifier = new notifier_1.EigenFluxNotifier(api, logger, {
|
|
117
|
+
eigenfluxBin: pluginConfig.eigenfluxBin,
|
|
118
|
+
serverName: server.name,
|
|
119
|
+
sessionKey: routing.sessionKey,
|
|
120
|
+
agentId: routing.agentId,
|
|
121
|
+
replyChannel: routing.replyChannel,
|
|
122
|
+
replyTo: routing.replyTo,
|
|
123
|
+
replyAccountId: routing.replyAccountId,
|
|
53
124
|
openclawCliBin: pluginConfig.openclawCliBin,
|
|
54
|
-
|
|
55
|
-
routeOverrides: server.routeOverrides,
|
|
125
|
+
routeOverrides: routing.routeOverrides,
|
|
56
126
|
});
|
|
57
127
|
const getPromptContext = () => ({
|
|
58
128
|
serverName: server.name,
|
|
59
|
-
|
|
60
|
-
workdir: server.workdir,
|
|
61
|
-
skillPath: (0, config_1.resolveServerSkillPath)(server),
|
|
129
|
+
eigenfluxHome,
|
|
62
130
|
});
|
|
63
131
|
let lastAuthPromptKey = null;
|
|
64
132
|
const resetAuthPromptGate = () => {
|
|
65
133
|
lastAuthPromptKey = null;
|
|
66
134
|
};
|
|
67
135
|
const notifyAuthRequired = async (authEvent) => {
|
|
68
|
-
const promptKey =
|
|
136
|
+
const promptKey = `auth_required:${server.name}`;
|
|
69
137
|
if (lastAuthPromptKey === promptKey) {
|
|
70
|
-
logger.debug(`Skipping duplicate auth prompt for server=${server.name}
|
|
138
|
+
logger.debug(`Skipping duplicate auth prompt for server=${server.name}`);
|
|
71
139
|
return;
|
|
72
140
|
}
|
|
73
141
|
lastAuthPromptKey = promptKey;
|
|
74
|
-
|
|
75
|
-
await notifier.deliver(buildAuthRequiredMessage(getPromptContext(), {
|
|
76
|
-
authEvent,
|
|
77
|
-
authState,
|
|
78
|
-
}));
|
|
142
|
+
await notifier.deliver((0, agent_prompt_templates_1.buildAuthRequiredPromptTemplate)({ context: getPromptContext() }));
|
|
79
143
|
};
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
144
|
+
const feedPoller = new polling_client_1.EigenFluxPollingClient({
|
|
145
|
+
serverName: server.name,
|
|
146
|
+
eigenfluxBin: pluginConfig.eigenfluxBin,
|
|
147
|
+
resolvePollIntervalSec: () => (0, polling_client_1.readPollIntervalSec)(pluginConfig.eigenfluxBin, server.name, logger),
|
|
84
148
|
logger,
|
|
85
149
|
onFeedPolled: async (payload) => {
|
|
86
150
|
resetAuthPromptGate();
|
|
87
|
-
await notifier.deliver(
|
|
151
|
+
await notifier.deliver((0, agent_prompt_templates_1.buildFeedPayloadPromptTemplate)(payload, getPromptContext()));
|
|
88
152
|
},
|
|
89
153
|
onAuthRequired: notifyAuthRequired,
|
|
90
154
|
});
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
pollIntervalSec: server.pmPollIntervalSec,
|
|
155
|
+
const streamClient = new stream_client_1.EigenFluxStreamClient({
|
|
156
|
+
serverName: server.name,
|
|
157
|
+
eigenfluxBin: pluginConfig.eigenfluxBin,
|
|
95
158
|
logger,
|
|
96
|
-
|
|
159
|
+
onPmEvent: async (event) => {
|
|
97
160
|
resetAuthPromptGate();
|
|
98
|
-
await notifier.deliver(
|
|
161
|
+
await notifier.deliver((0, agent_prompt_templates_1.buildPmStreamEventPromptTemplate)(event, getPromptContext()));
|
|
162
|
+
},
|
|
163
|
+
onAuthRequired: async () => {
|
|
164
|
+
await notifyAuthRequired({ reason: 'auth_required' });
|
|
99
165
|
},
|
|
100
|
-
onAuthRequired: notifyAuthRequired,
|
|
101
166
|
});
|
|
102
167
|
return {
|
|
103
168
|
server,
|
|
169
|
+
routing,
|
|
104
170
|
credentialsLoader,
|
|
105
171
|
notifier,
|
|
106
|
-
|
|
107
|
-
|
|
172
|
+
feedPoller,
|
|
173
|
+
streamClient,
|
|
108
174
|
getPromptContext,
|
|
109
175
|
};
|
|
110
176
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
api.registerService({
|
|
114
|
-
id: `eigenflux:${toServiceIdSegment(runtime.server.name)}`,
|
|
115
|
-
start: async () => {
|
|
116
|
-
logger.info(`Starting EigenFlux polling services for server=${runtime.server.name}`);
|
|
117
|
-
await runtime.pollingClient.start();
|
|
118
|
-
await runtime.pmPollingClient.start();
|
|
119
|
-
},
|
|
120
|
-
stop: async () => {
|
|
121
|
-
logger.info(`Stopping EigenFlux polling services for server=${runtime.server.name}`);
|
|
122
|
-
runtime.pollingClient.stop();
|
|
123
|
-
runtime.pmPollingClient.stop();
|
|
124
|
-
},
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
function registerCommand(api, logger, runtimes) {
|
|
177
|
+
// ─── Command Handler ────────────────────────────────────────────────────────
|
|
178
|
+
function registerCommand(api, logger, pluginConfig, eigenfluxHome, getRuntimes, setRuntimes) {
|
|
129
179
|
if (!api.registerCommand) {
|
|
130
180
|
logger.warn('registerCommand API unavailable; skipping /eigenflux command registration');
|
|
131
181
|
return;
|
|
132
182
|
}
|
|
183
|
+
let inflightDiscovery = null;
|
|
184
|
+
const runDiscovery = async () => {
|
|
185
|
+
const discovery = await (0, config_1.discoverServers)(pluginConfig.eigenfluxBin, logger);
|
|
186
|
+
if (discovery.kind === 'not_installed') {
|
|
187
|
+
return { runtimes: getRuntimes(), notInstalledBin: discovery.bin };
|
|
188
|
+
}
|
|
189
|
+
if (discovery.servers.length === 0) {
|
|
190
|
+
return { runtimes: getRuntimes() };
|
|
191
|
+
}
|
|
192
|
+
const created = discovery.servers.map((server) => createServerRuntime(api, logger, pluginConfig, server, eigenfluxHome));
|
|
193
|
+
setRuntimes(created);
|
|
194
|
+
return { runtimes: created };
|
|
195
|
+
};
|
|
196
|
+
const ensureRuntimes = async () => {
|
|
197
|
+
const existing = getRuntimes();
|
|
198
|
+
if (existing.length > 0) {
|
|
199
|
+
return { runtimes: existing };
|
|
200
|
+
}
|
|
201
|
+
if (!inflightDiscovery) {
|
|
202
|
+
inflightDiscovery = runDiscovery().finally(() => {
|
|
203
|
+
inflightDiscovery = null;
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
return inflightDiscovery;
|
|
207
|
+
};
|
|
133
208
|
api.registerCommand({
|
|
134
209
|
name: 'eigenflux',
|
|
135
|
-
description: 'EigenFlux plugin commands: auth, profile, servers, feed, pm, here',
|
|
210
|
+
description: 'EigenFlux plugin commands: auth, profile, servers, feed, pm, here, version',
|
|
136
211
|
acceptsArgs: true,
|
|
137
212
|
handler: async (ctx) => {
|
|
138
213
|
const parsed = parseCommandArgs(ctx.args);
|
|
214
|
+
if (parsed.command === 'version') {
|
|
215
|
+
return {
|
|
216
|
+
text: await buildVersionText(pluginConfig.eigenfluxBin),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
const { runtimes, notInstalledBin } = await ensureRuntimes();
|
|
220
|
+
if (notInstalledBin && runtimes.length === 0) {
|
|
221
|
+
return {
|
|
222
|
+
text: `EigenFlux CLI not installed (bin=${notInstalledBin}). Install with: ${INSTALL_COMMAND}`,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
139
225
|
if (parsed.command === 'servers') {
|
|
140
226
|
return {
|
|
141
227
|
text: buildServersText(runtimes),
|
|
@@ -148,27 +234,27 @@ function registerCommand(api, logger, runtimes) {
|
|
|
148
234
|
};
|
|
149
235
|
}
|
|
150
236
|
const runtime = selection.runtime;
|
|
151
|
-
await rememberCurrentCommandRouteIfPossible(ctx, runtime.
|
|
237
|
+
await rememberCurrentCommandRouteIfPossible(ctx, runtime, pluginConfig.eigenfluxBin, logger);
|
|
152
238
|
switch (parsed.command) {
|
|
153
239
|
case 'auth':
|
|
154
240
|
return {
|
|
155
|
-
text: buildAuthStatusText(runtime
|
|
241
|
+
text: buildAuthStatusText(runtime),
|
|
156
242
|
};
|
|
157
243
|
case 'profile':
|
|
158
244
|
return {
|
|
159
|
-
text: await buildProfileText(runtime,
|
|
245
|
+
text: await buildProfileText(runtime, pluginConfig.eigenfluxBin),
|
|
160
246
|
};
|
|
161
247
|
case 'feed':
|
|
162
248
|
return {
|
|
163
|
-
text: await buildFeedText(runtime
|
|
249
|
+
text: await buildFeedText(runtime),
|
|
164
250
|
};
|
|
165
251
|
case 'pm':
|
|
166
252
|
return {
|
|
167
|
-
text:
|
|
253
|
+
text: buildPmStatusText(runtime),
|
|
168
254
|
};
|
|
169
255
|
case 'here':
|
|
170
256
|
return {
|
|
171
|
-
text: await buildHereText(ctx, runtime.
|
|
257
|
+
text: await buildHereText(ctx, runtime, pluginConfig.eigenfluxBin, logger),
|
|
172
258
|
};
|
|
173
259
|
default:
|
|
174
260
|
return {
|
|
@@ -200,7 +286,7 @@ function parseCommandArgs(args) {
|
|
|
200
286
|
function selectServerRuntime(runtimes, requestedServerName) {
|
|
201
287
|
if (runtimes.length === 0) {
|
|
202
288
|
return {
|
|
203
|
-
error: 'No EigenFlux servers
|
|
289
|
+
error: 'No EigenFlux servers discovered. Ensure eigenflux CLI is configured with at least one server.',
|
|
204
290
|
};
|
|
205
291
|
}
|
|
206
292
|
if (!requestedServerName) {
|
|
@@ -222,19 +308,19 @@ function selectServerRuntime(runtimes, requestedServerName) {
|
|
|
222
308
|
}
|
|
223
309
|
function buildServersText(runtimes) {
|
|
224
310
|
if (runtimes.length === 0) {
|
|
225
|
-
return 'No EigenFlux servers
|
|
311
|
+
return 'No EigenFlux servers discovered.';
|
|
226
312
|
}
|
|
227
|
-
const defaultRuntime = runtimes[0];
|
|
228
313
|
return [
|
|
229
|
-
'EigenFlux servers:',
|
|
314
|
+
'EigenFlux servers (discovered via CLI):',
|
|
230
315
|
...runtimes.map((runtime) => {
|
|
231
316
|
const flags = [
|
|
232
|
-
runtime.server.
|
|
233
|
-
|
|
317
|
+
runtime.server.current ? 'default' : null,
|
|
318
|
+
runtime.streamClient.isRunning() ? 'streaming' : null,
|
|
234
319
|
]
|
|
235
320
|
.filter(Boolean)
|
|
236
321
|
.join(', ');
|
|
237
|
-
|
|
322
|
+
const suffix = flags ? ` (${flags})` : '';
|
|
323
|
+
return `- ${runtime.server.name}: endpoint=${runtime.server.endpoint}${suffix}`;
|
|
238
324
|
}),
|
|
239
325
|
].join('\n');
|
|
240
326
|
}
|
|
@@ -248,23 +334,13 @@ function buildHelpText(runtimes) {
|
|
|
248
334
|
? `Available servers: ${runtimes.map((runtime) => runtime.server.name).join(', ')}`
|
|
249
335
|
: undefined,
|
|
250
336
|
'',
|
|
251
|
-
'/eigenflux auth',
|
|
252
|
-
'
|
|
253
|
-
'',
|
|
254
|
-
'/eigenflux
|
|
255
|
-
'
|
|
256
|
-
'',
|
|
257
|
-
'/eigenflux
|
|
258
|
-
'List configured EigenFlux servers.',
|
|
259
|
-
'',
|
|
260
|
-
'/eigenflux feed',
|
|
261
|
-
'Run one feed refresh and return the raw feed payload.',
|
|
262
|
-
'',
|
|
263
|
-
'/eigenflux pm',
|
|
264
|
-
'Run one PM fetch and return the raw PM payload.',
|
|
265
|
-
'',
|
|
266
|
-
'/eigenflux here',
|
|
267
|
-
'Remember the current conversation as the default delivery route for the selected server.',
|
|
337
|
+
'/eigenflux auth — Show credential status',
|
|
338
|
+
'/eigenflux profile — Fetch agent profile',
|
|
339
|
+
'/eigenflux servers — List discovered servers',
|
|
340
|
+
'/eigenflux feed — Run one feed refresh',
|
|
341
|
+
'/eigenflux pm — Show PM stream status',
|
|
342
|
+
'/eigenflux here — Remember current conversation as delivery route',
|
|
343
|
+
'/eigenflux version — Show eigenflux CLI version info',
|
|
268
344
|
]
|
|
269
345
|
.filter(Boolean)
|
|
270
346
|
.join('\n');
|
|
@@ -287,98 +363,51 @@ function isInternalAgentSessionKey(value) {
|
|
|
287
363
|
const parts = trimmed.split(':').filter((part) => part.length > 0);
|
|
288
364
|
return parts[0]?.toLowerCase() === 'agent' && parts[2]?.toLowerCase() === 'main';
|
|
289
365
|
}
|
|
290
|
-
function
|
|
291
|
-
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
if (!trimmed) {
|
|
296
|
-
return undefined;
|
|
297
|
-
}
|
|
298
|
-
if (isNormalizedConversationTarget(trimmed)) {
|
|
299
|
-
return trimmed;
|
|
300
|
-
}
|
|
301
|
-
if (channel && trimmed.startsWith(`${channel}:`)) {
|
|
302
|
-
const inner = trimmed.slice(channel.length + 1).trim();
|
|
303
|
-
if (isNormalizedConversationTarget(inner)) {
|
|
304
|
-
return inner;
|
|
305
|
-
}
|
|
306
|
-
return fallbackKind ? `${fallbackKind}:${inner}` : inner;
|
|
307
|
-
}
|
|
308
|
-
return fallbackKind ? `${fallbackKind}:${trimmed}` : trimmed;
|
|
309
|
-
}
|
|
310
|
-
async function resolveCurrentCommandRoute(ctx, serverConfig, logger) {
|
|
311
|
-
const channel = normalizeChannel(ctx.channel);
|
|
312
|
-
const accountId = readNonEmptyString(ctx.accountId);
|
|
313
|
-
let replyChannel = channel;
|
|
314
|
-
let replyTo = normalizeReplyTarget(ctx.to, channel) ?? normalizeReplyTarget(ctx.from, channel, 'user');
|
|
315
|
-
let replyAccountId = accountId;
|
|
366
|
+
async function resolveCurrentCommandRoute(ctx, runtime, logger) {
|
|
367
|
+
let channel = normalizeChannel(ctx.channel);
|
|
368
|
+
let to = (0, reply_target_1.normalizeReplyTarget)(ctx.to, { channel }) ??
|
|
369
|
+
(0, reply_target_1.normalizeReplyTarget)(ctx.from, { channel, fallbackKind: 'user' });
|
|
370
|
+
let accountId = readNonEmptyString(ctx.accountId);
|
|
316
371
|
if (typeof ctx.getCurrentConversationBinding === 'function') {
|
|
317
372
|
try {
|
|
318
373
|
const binding = await ctx.getCurrentConversationBinding();
|
|
319
374
|
if (binding) {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
normalizeReplyTarget(binding.conversationId,
|
|
323
|
-
normalizeReplyTarget(binding.parentConversationId,
|
|
324
|
-
|
|
325
|
-
|
|
375
|
+
channel = normalizeChannel(binding.channel) ?? channel;
|
|
376
|
+
to =
|
|
377
|
+
(0, reply_target_1.normalizeReplyTarget)(binding.conversationId, { channel }) ??
|
|
378
|
+
(0, reply_target_1.normalizeReplyTarget)(binding.parentConversationId, { channel }) ??
|
|
379
|
+
to;
|
|
380
|
+
accountId = readNonEmptyString(binding.accountId) ?? accountId;
|
|
326
381
|
}
|
|
327
382
|
}
|
|
328
383
|
catch (error) {
|
|
329
384
|
logger.debug(`Failed to read current conversation binding: ${error instanceof Error ? error.message : String(error)}`);
|
|
330
385
|
}
|
|
331
386
|
}
|
|
332
|
-
if (!
|
|
387
|
+
if (!channel || !to) {
|
|
333
388
|
return undefined;
|
|
334
389
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
replyAccountId,
|
|
341
|
-
sessionStorePath: readServerSessionStorePath(serverConfig),
|
|
342
|
-
workdir: serverConfig.workdir,
|
|
343
|
-
routeOverrides: {
|
|
344
|
-
sessionKey: false,
|
|
345
|
-
agentId: false,
|
|
346
|
-
replyChannel: true,
|
|
347
|
-
replyTo: true,
|
|
348
|
-
replyAccountId: replyAccountId !== undefined,
|
|
349
|
-
},
|
|
390
|
+
return (0, notification_route_resolver_1.findSessionRouteForBinding)({
|
|
391
|
+
agentId: runtime.routing.agentId,
|
|
392
|
+
channel,
|
|
393
|
+
to,
|
|
394
|
+
accountId,
|
|
350
395
|
}, logger);
|
|
351
|
-
if (!route.replyChannel || !route.replyTo) {
|
|
352
|
-
return undefined;
|
|
353
|
-
}
|
|
354
|
-
if (isInternalAgentSessionKey(route.sessionKey)) {
|
|
355
|
-
const configuredSessionKey = readNonEmptyString(serverConfig.sessionKey);
|
|
356
|
-
if (configuredSessionKey && !isInternalAgentSessionKey(configuredSessionKey)) {
|
|
357
|
-
return {
|
|
358
|
-
sessionKey: configuredSessionKey,
|
|
359
|
-
agentId: readNonEmptyString(serverConfig.agentId) ?? route.agentId,
|
|
360
|
-
replyChannel: route.replyChannel,
|
|
361
|
-
replyTo: route.replyTo,
|
|
362
|
-
replyAccountId: route.replyAccountId,
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
return route;
|
|
367
396
|
}
|
|
368
|
-
async function buildHereText(ctx,
|
|
369
|
-
const route = await resolveCurrentCommandRoute(ctx,
|
|
397
|
+
async function buildHereText(ctx, runtime, eigenfluxBin, logger) {
|
|
398
|
+
const route = await resolveCurrentCommandRoute(ctx, runtime, logger);
|
|
370
399
|
if (!route || route.sessionKey === 'main' || route.sessionKey.endsWith(':main')) {
|
|
371
400
|
return [
|
|
372
|
-
`Unable to resolve the current external session for server=${
|
|
401
|
+
`Unable to resolve the current external session for server=${runtime.server.name}.`,
|
|
373
402
|
'Run `/eigenflux here` inside the target conversation after OpenClaw has already created a session for it.',
|
|
374
403
|
].join('\n');
|
|
375
404
|
}
|
|
376
|
-
const saved = (0, session_route_memory_1.writeStoredNotificationRoute)(
|
|
405
|
+
const saved = await (0, session_route_memory_1.writeStoredNotificationRoute)(eigenfluxBin, runtime.server.name, route, logger);
|
|
377
406
|
if (!saved) {
|
|
378
|
-
return `Failed to persist the current EigenFlux route for server=${
|
|
407
|
+
return `Failed to persist the current EigenFlux route for server=${runtime.server.name}; check plugin logs for details.`;
|
|
379
408
|
}
|
|
380
409
|
return [
|
|
381
|
-
`EigenFlux server ${
|
|
410
|
+
`EigenFlux server ${runtime.server.name} will deliver to this conversation by default:`,
|
|
382
411
|
`sessionKey: ${route.sessionKey}`,
|
|
383
412
|
`agentId: ${route.agentId}`,
|
|
384
413
|
`channel: ${route.replyChannel ?? 'unknown'}`,
|
|
@@ -388,42 +417,52 @@ async function buildHereText(ctx, serverConfig, logger) {
|
|
|
388
417
|
.filter(Boolean)
|
|
389
418
|
.join('\n');
|
|
390
419
|
}
|
|
391
|
-
async function rememberCurrentCommandRouteIfPossible(ctx,
|
|
392
|
-
const route = await resolveCurrentCommandRoute(ctx,
|
|
420
|
+
async function rememberCurrentCommandRouteIfPossible(ctx, runtime, eigenfluxBin, logger) {
|
|
421
|
+
const route = await resolveCurrentCommandRoute(ctx, runtime, logger);
|
|
393
422
|
if (!route || route.sessionKey === 'main' || route.sessionKey.endsWith(':main')) {
|
|
394
423
|
return;
|
|
395
424
|
}
|
|
396
|
-
if ((0, session_route_memory_1.writeStoredNotificationRoute)(
|
|
397
|
-
logger.debug(`Remembered current command route for server=${
|
|
425
|
+
if (await (0, session_route_memory_1.writeStoredNotificationRoute)(eigenfluxBin, runtime.server.name, route, logger)) {
|
|
426
|
+
logger.debug(`Remembered current command route for server=${runtime.server.name}: session_key=${route.sessionKey}, channel=${route.replyChannel ?? 'unknown'}, to=${route.replyTo ?? 'unknown'}`);
|
|
398
427
|
}
|
|
399
428
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
},
|
|
409
|
-
authState,
|
|
410
|
-
});
|
|
429
|
+
// ─── Command Handlers ───────────────────────────────────────────────────────
|
|
430
|
+
function buildAuthStatusText(runtime) {
|
|
431
|
+
const authState = runtime.credentialsLoader.loadAuthState();
|
|
432
|
+
const lines = [`EigenFlux auth status (server=${runtime.server.name}):`];
|
|
433
|
+
lines.push(`- credentials_path: ${authState.credentialsPath}`);
|
|
434
|
+
lines.push(`- status: ${authState.status}`);
|
|
435
|
+
if (authState.expiresAt) {
|
|
436
|
+
lines.push(`- expires_at: ${authState.expiresAt}`);
|
|
411
437
|
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
safeJsonStringify(payload),
|
|
418
|
-
'```',
|
|
419
|
-
].join('\n');
|
|
438
|
+
if (authState.status === 'available') {
|
|
439
|
+
lines.push(`- token: ${maskToken(authState.accessToken)}`);
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
lines.push('- token: unavailable');
|
|
420
443
|
}
|
|
421
|
-
|
|
422
|
-
|
|
444
|
+
return lines.join('\n');
|
|
445
|
+
}
|
|
446
|
+
async function buildProfileText(runtime, eigenfluxBin) {
|
|
447
|
+
const result = await (0, cli_executor_1.execEigenflux)(eigenfluxBin, ['profile', 'show', '-s', runtime.server.name, '-f', 'json']);
|
|
448
|
+
if (result.kind === 'auth_required') {
|
|
449
|
+
return (0, agent_prompt_templates_1.buildAuthRequiredPromptTemplate)({ context: runtime.getPromptContext() });
|
|
423
450
|
}
|
|
451
|
+
if (result.kind === 'not_installed') {
|
|
452
|
+
return `EigenFlux CLI not installed (bin=${result.bin}). Install with: ${INSTALL_COMMAND}`;
|
|
453
|
+
}
|
|
454
|
+
if (result.kind === 'error') {
|
|
455
|
+
return `Failed to fetch profile for server ${runtime.server.name}: ${result.error.message}`;
|
|
456
|
+
}
|
|
457
|
+
return [
|
|
458
|
+
`EigenFlux profile (server=${runtime.server.name}):`,
|
|
459
|
+
'```json',
|
|
460
|
+
safeJsonStringify(result.data),
|
|
461
|
+
'```',
|
|
462
|
+
].join('\n');
|
|
424
463
|
}
|
|
425
|
-
async function buildFeedText(runtime
|
|
426
|
-
const result = await runtime.
|
|
464
|
+
async function buildFeedText(runtime) {
|
|
465
|
+
const result = await runtime.feedPoller.pollOnce({
|
|
427
466
|
notifyFeed: false,
|
|
428
467
|
notifyAuthRequired: false,
|
|
429
468
|
});
|
|
@@ -436,89 +475,41 @@ async function buildFeedText(runtime, authState) {
|
|
|
436
475
|
'```',
|
|
437
476
|
].join('\n');
|
|
438
477
|
case 'auth_required':
|
|
439
|
-
return
|
|
440
|
-
authEvent: result.authEvent,
|
|
441
|
-
authState,
|
|
442
|
-
});
|
|
478
|
+
return (0, agent_prompt_templates_1.buildAuthRequiredPromptTemplate)({ context: runtime.getPromptContext() });
|
|
443
479
|
case 'error':
|
|
444
480
|
return `EigenFlux feed failed for server ${runtime.server.name}: ${result.error.message}`;
|
|
445
481
|
default:
|
|
446
482
|
return `EigenFlux feed finished with an unknown result for server ${runtime.server.name}.`;
|
|
447
483
|
}
|
|
448
484
|
}
|
|
449
|
-
async function
|
|
450
|
-
const result = await
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
});
|
|
454
|
-
switch (result.kind) {
|
|
455
|
-
case 'success':
|
|
456
|
-
return [
|
|
457
|
-
`EigenFlux PM poll result (server=${runtime.server.name}):`,
|
|
458
|
-
'```json',
|
|
459
|
-
safeJsonStringify(result.payload),
|
|
460
|
-
'```',
|
|
461
|
-
].join('\n');
|
|
462
|
-
case 'auth_required':
|
|
463
|
-
return buildAuthRequiredMessage(runtime.getPromptContext(), {
|
|
464
|
-
authEvent: result.authEvent,
|
|
465
|
-
authState,
|
|
466
|
-
});
|
|
467
|
-
case 'error':
|
|
468
|
-
return `EigenFlux PM poll failed for server ${runtime.server.name}: ${result.error.message}`;
|
|
469
|
-
default:
|
|
470
|
-
return `EigenFlux PM poll finished with an unknown result for server ${runtime.server.name}.`;
|
|
485
|
+
async function buildVersionText(eigenfluxBin) {
|
|
486
|
+
const result = await (0, cli_executor_1.execEigenflux)(eigenfluxBin, ['version']);
|
|
487
|
+
if (result.kind === 'not_installed') {
|
|
488
|
+
return `EigenFlux CLI not installed (bin=${result.bin}). Install with: ${INSTALL_COMMAND}`;
|
|
471
489
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
const response = await fetch(url, {
|
|
475
|
-
method: 'GET',
|
|
476
|
-
headers: (0, config_1.buildEigenFluxRequestHeaders)(accessToken),
|
|
477
|
-
});
|
|
478
|
-
if (response.status === 401) {
|
|
479
|
-
throw new Error('HTTP 401: unauthorized');
|
|
490
|
+
if (result.kind === 'auth_required') {
|
|
491
|
+
return `EigenFlux CLI reported auth_required while fetching version (stderr: ${result.stderr || 'n/a'}).`;
|
|
480
492
|
}
|
|
481
|
-
if (
|
|
482
|
-
|
|
493
|
+
if (result.kind === 'error') {
|
|
494
|
+
return `Failed to fetch eigenflux version: ${result.error.message}`;
|
|
483
495
|
}
|
|
484
|
-
const
|
|
485
|
-
|
|
486
|
-
throw new Error(`API error: ${payload.msg}`);
|
|
487
|
-
}
|
|
488
|
-
return payload;
|
|
496
|
+
const body = typeof result.data === 'string' ? result.data : safeJsonStringify(result.data);
|
|
497
|
+
return ['EigenFlux CLI version:', '```json', body, '```'].join('\n');
|
|
489
498
|
}
|
|
490
|
-
function
|
|
491
|
-
const
|
|
492
|
-
|
|
493
|
-
lines
|
|
494
|
-
lines.push(`-
|
|
495
|
-
if (
|
|
496
|
-
lines.push(`-
|
|
499
|
+
function buildPmStatusText(runtime) {
|
|
500
|
+
const running = runtime.streamClient.isRunning();
|
|
501
|
+
const cursor = runtime.streamClient.getLastCursor();
|
|
502
|
+
const lines = [`EigenFlux PM stream status (server=${runtime.server.name}):`];
|
|
503
|
+
lines.push(`- streaming: ${running ? 'active' : 'inactive'}`);
|
|
504
|
+
if (cursor) {
|
|
505
|
+
lines.push(`- last_cursor: ${cursor}`);
|
|
497
506
|
}
|
|
498
|
-
if (
|
|
499
|
-
lines.push(
|
|
500
|
-
}
|
|
501
|
-
if (authState.status === 'available') {
|
|
502
|
-
lines.push(`- token: ${maskToken(authState.accessToken)}`);
|
|
503
|
-
}
|
|
504
|
-
else {
|
|
505
|
-
lines.push('- token: unavailable');
|
|
507
|
+
if (!running) {
|
|
508
|
+
lines.push('PM stream is not running. Check auth status or restart the service.');
|
|
506
509
|
}
|
|
507
510
|
return lines.join('\n');
|
|
508
511
|
}
|
|
509
|
-
|
|
510
|
-
return (0, agent_prompt_templates_1.buildAuthRequiredPromptTemplate)({
|
|
511
|
-
...promptContext,
|
|
512
|
-
authEvent,
|
|
513
|
-
maskedToken: authState?.status === 'available' ? maskToken(authState.accessToken) : undefined,
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
function buildFeedPayloadMessage(promptContext, payload) {
|
|
517
|
-
return (0, agent_prompt_templates_1.buildFeedPayloadPromptTemplate)(payload, promptContext);
|
|
518
|
-
}
|
|
519
|
-
function buildPmPayloadMessage(promptContext, payload) {
|
|
520
|
-
return (0, agent_prompt_templates_1.buildPmPayloadPromptTemplate)(payload, promptContext);
|
|
521
|
-
}
|
|
512
|
+
// ─── Utilities ──────────────────────────────────────────────────────────────
|
|
522
513
|
function maskToken(token) {
|
|
523
514
|
const trimmed = token.trim();
|
|
524
515
|
if (trimmed.length <= 10) {
|
|
@@ -534,8 +525,4 @@ function safeJsonStringify(value) {
|
|
|
534
525
|
return String(value);
|
|
535
526
|
}
|
|
536
527
|
}
|
|
537
|
-
function toServiceIdSegment(name) {
|
|
538
|
-
const sanitized = name.trim().toLowerCase().replace(/[^a-z0-9._-]+/gu, '-');
|
|
539
|
-
return sanitized || 'default';
|
|
540
|
-
}
|
|
541
528
|
//# sourceMappingURL=index.js.map
|