@phronesis-io/openclaw-eigenflux 0.0.1 → 0.0.3

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 (44) hide show
  1. package/README.md +16 -3
  2. package/dist/config.d.ts +12 -5
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +47 -10
  5. package/dist/config.js.map +1 -1
  6. package/dist/index.d.ts +5 -3
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +3 -7
  9. package/dist/index.js.map +1 -1
  10. package/dist/notifier.d.ts +1 -17
  11. package/dist/notifier.d.ts.map +1 -1
  12. package/dist/notifier.js +1 -94
  13. package/dist/notifier.js.map +1 -1
  14. package/dist/pm-polling-client.d.ts +1 -0
  15. package/dist/pm-polling-client.d.ts.map +1 -1
  16. package/dist/pm-polling-client.js +64 -57
  17. package/dist/pm-polling-client.js.map +1 -1
  18. package/dist/polling-client.d.ts +1 -0
  19. package/dist/polling-client.d.ts.map +1 -1
  20. package/dist/polling-client.js +65 -58
  21. package/dist/polling-client.js.map +1 -1
  22. package/openclaw.plugin.json +8 -6
  23. package/package.json +2 -2
  24. package/src/agent-prompt-templates.ts +0 -91
  25. package/src/config.test.ts +0 -188
  26. package/src/config.ts +0 -410
  27. package/src/credentials-loader.test.ts +0 -78
  28. package/src/credentials-loader.ts +0 -121
  29. package/src/gateway-rpc-client.test.ts +0 -190
  30. package/src/gateway-rpc-client.ts +0 -373
  31. package/src/index.integration.test.ts +0 -437
  32. package/src/index.test.ts +0 -454
  33. package/src/index.ts +0 -758
  34. package/src/logger.ts +0 -27
  35. package/src/notification-route-resolver.test.ts +0 -136
  36. package/src/notification-route-resolver.ts +0 -430
  37. package/src/notifier.test.ts +0 -374
  38. package/src/notifier.ts +0 -558
  39. package/src/openclaw-plugin-sdk.d.ts +0 -121
  40. package/src/pm-polling-client.test.ts +0 -390
  41. package/src/pm-polling-client.ts +0 -257
  42. package/src/polling-client.test.ts +0 -279
  43. package/src/polling-client.ts +0 -283
  44. package/src/session-route-memory.ts +0 -106
@@ -1,78 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as os from 'os';
3
- import * as path from 'path';
4
-
5
- import { CredentialsLoader } from './credentials-loader';
6
- import { Logger } from './logger';
7
-
8
- function createLogger(): Logger {
9
- return new Logger({
10
- info: jest.fn(),
11
- warn: jest.fn(),
12
- error: jest.fn(),
13
- debug: jest.fn(),
14
- });
15
- }
16
-
17
- describe('CredentialsLoader', () => {
18
- let workdir: string;
19
-
20
- beforeEach(() => {
21
- workdir = fs.mkdtempSync(path.join(os.tmpdir(), 'eigenflux-workdir-'));
22
- });
23
-
24
- afterEach(() => {
25
- fs.rmSync(workdir, { recursive: true, force: true });
26
- });
27
-
28
- test('loads access token from credentials.json', () => {
29
- fs.writeFileSync(
30
- path.join(workdir, 'credentials.json'),
31
- JSON.stringify({ access_token: 'at_file_token' }),
32
- 'utf-8'
33
- );
34
-
35
- const loader = new CredentialsLoader(createLogger(), workdir);
36
- expect(loader.loadAccessToken()).toBe('at_file_token');
37
- });
38
-
39
- test('returns null when credentials file is missing', () => {
40
- const loader = new CredentialsLoader(createLogger(), workdir);
41
- expect(loader.loadAccessToken()).toBeNull();
42
- });
43
-
44
- test('returns expired auth state when credentials file token is stale', () => {
45
- fs.writeFileSync(
46
- path.join(workdir, 'credentials.json'),
47
- JSON.stringify({
48
- access_token: 'at_expired_token',
49
- expires_at: Date.now() - 1_000,
50
- }),
51
- 'utf-8'
52
- );
53
-
54
- const loader = new CredentialsLoader(createLogger(), workdir);
55
- expect(loader.loadAuthState()).toEqual(
56
- expect.objectContaining({
57
- status: 'expired',
58
- source: 'file',
59
- })
60
- );
61
- expect(loader.loadAccessToken()).toBeNull();
62
- });
63
-
64
- test('saveAccessToken creates the workdir and writes credentials.json', () => {
65
- const nestedWorkdir = path.join(workdir, 'nested/eigenflux');
66
- const loader = new CredentialsLoader(createLogger(), nestedWorkdir);
67
-
68
- loader.saveAccessToken('at_saved_token', 'bot@example.com', 1_760_000_000_000);
69
-
70
- const credentialsPath = path.join(nestedWorkdir, 'credentials.json');
71
- expect(fs.existsSync(credentialsPath)).toBe(true);
72
- expect(JSON.parse(fs.readFileSync(credentialsPath, 'utf-8'))).toEqual({
73
- access_token: 'at_saved_token',
74
- email: 'bot@example.com',
75
- expires_at: 1_760_000_000_000,
76
- });
77
- });
78
- });
@@ -1,121 +0,0 @@
1
- /**
2
- * Credentials loader for the EigenFlux auth token.
3
- */
4
-
5
- import * as fs from 'fs';
6
- import * as path from 'path';
7
- import { Logger } from './logger';
8
- import { PLUGIN_CONFIG } from './config';
9
-
10
- interface EigenFluxCredentials {
11
- access_token: string;
12
- email?: string;
13
- expires_at?: number;
14
- }
15
-
16
- export type AuthState =
17
- | {
18
- status: 'available';
19
- accessToken: string;
20
- source: 'file';
21
- credentialsPath: string;
22
- expiresAt?: number;
23
- email?: string;
24
- }
25
- | {
26
- status: 'missing' | 'expired';
27
- source?: 'file';
28
- credentialsPath: string;
29
- expiresAt?: number;
30
- email?: string;
31
- };
32
-
33
- export class CredentialsLoader {
34
- private readonly logger: Logger;
35
- private readonly workdir: string;
36
-
37
- constructor(logger: Logger, workdir: string) {
38
- this.logger = logger;
39
- this.workdir = workdir;
40
- }
41
-
42
- loadAccessToken(): string | null {
43
- const authState = this.loadAuthState();
44
- if (authState.status !== 'available') {
45
- if (authState.status === 'missing') {
46
- this.logger.error(`No access token found in ${authState.credentialsPath}`);
47
- }
48
- return null;
49
- }
50
- return authState.accessToken;
51
- }
52
-
53
- loadAuthState(): AuthState {
54
- const credentialsPath = this.resolveCredentialsPath();
55
-
56
- if (fs.existsSync(credentialsPath)) {
57
- try {
58
- const content = fs.readFileSync(credentialsPath, 'utf-8');
59
- const credentials: EigenFluxCredentials = JSON.parse(content);
60
-
61
- if (credentials.access_token) {
62
- if (credentials.expires_at) {
63
- const now = Date.now();
64
- if (now >= credentials.expires_at) {
65
- this.logger.warn('Access token has expired');
66
- return {
67
- status: 'expired',
68
- source: 'file',
69
- credentialsPath,
70
- expiresAt: credentials.expires_at,
71
- email: credentials.email,
72
- };
73
- }
74
- }
75
-
76
- this.logger.info(`Loaded access token from ${credentialsPath}`);
77
- return {
78
- status: 'available',
79
- accessToken: credentials.access_token,
80
- source: 'file',
81
- credentialsPath,
82
- expiresAt: credentials.expires_at,
83
- email: credentials.email,
84
- };
85
- }
86
- } catch (error) {
87
- this.logger.error(`Failed to read credentials file: ${credentialsPath}`, error);
88
- }
89
- }
90
-
91
- return {
92
- status: 'missing',
93
- credentialsPath,
94
- };
95
- }
96
-
97
- saveAccessToken(token: string, email?: string, expiresAt?: number): void {
98
- const credentialsPath = this.resolveCredentialsPath();
99
-
100
- if (!fs.existsSync(this.workdir)) {
101
- fs.mkdirSync(this.workdir, { recursive: true });
102
- }
103
-
104
- const credentials: EigenFluxCredentials = {
105
- access_token: token,
106
- email,
107
- expires_at: expiresAt,
108
- };
109
-
110
- try {
111
- fs.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), 'utf-8');
112
- this.logger.info(`Saved access token to ${credentialsPath}`);
113
- } catch (error) {
114
- this.logger.error('Failed to save credentials file', error);
115
- }
116
- }
117
-
118
- private resolveCredentialsPath(): string {
119
- return path.join(this.workdir, PLUGIN_CONFIG.CREDENTIALS_FILE);
120
- }
121
- }
@@ -1,190 +0,0 @@
1
- import http from 'http';
2
- import { WebSocketServer } from 'ws';
3
- import { OpenClawGatewayRpcClient } from './gateway-rpc-client';
4
- import { Logger } from './logger';
5
-
6
- describe('OpenClawGatewayRpcClient', () => {
7
- let server: http.Server;
8
- let wss: WebSocketServer;
9
- let port: number;
10
-
11
- beforeEach(async () => {
12
- server = http.createServer();
13
- wss = new WebSocketServer({ server });
14
- await new Promise<void>((resolve) => {
15
- server.listen(0, '127.0.0.1', () => {
16
- port = (server.address() as any).port;
17
- resolve();
18
- });
19
- });
20
- });
21
-
22
- afterEach(async () => {
23
- await new Promise<void>((resolve) => wss.close(() => resolve()));
24
- await new Promise<void>((resolve) => server.close(() => resolve()));
25
- });
26
-
27
- test('uses configured session key and sends agent directly', async () => {
28
- const methods: string[] = [];
29
- let agentParams: any = null;
30
-
31
- wss.on('connection', (socket) => {
32
- socket.send(
33
- JSON.stringify({
34
- type: 'event',
35
- event: 'connect.challenge',
36
- payload: { nonce: 'nonce-test-1' },
37
- })
38
- );
39
-
40
- socket.on('message', (raw) => {
41
- const frame = JSON.parse(raw.toString());
42
- methods.push(String(frame.method || ''));
43
-
44
- if (frame.method === 'connect') {
45
- socket.send(
46
- JSON.stringify({
47
- type: 'res',
48
- id: frame.id,
49
- ok: true,
50
- payload: {
51
- protocol: 3,
52
- server: { version: 'test', connId: 'conn-1' },
53
- features: { methods: ['agent'], events: [] },
54
- snapshot: { ts: Date.now() },
55
- policy: { maxPayload: 1000000, maxBufferedBytes: 1000000, tickIntervalMs: 30000 },
56
- },
57
- })
58
- );
59
- return;
60
- }
61
-
62
- if (frame.method === 'agent') {
63
- agentParams = frame.params;
64
- socket.send(
65
- JSON.stringify({
66
- type: 'res',
67
- id: frame.id,
68
- ok: true,
69
- payload: { status: 'started', runId: 'run-1' },
70
- })
71
- );
72
- }
73
- });
74
- });
75
-
76
- const client = new OpenClawGatewayRpcClient({
77
- gatewayUrl: `ws://127.0.0.1:${port}`,
78
- gatewayToken: 'gw_token_1',
79
- sessionKey: 'agent:test:feishu:direct:ou_123',
80
- agentId: 'test',
81
- replyChannel: 'feishu',
82
- replyTo: 'ou_123',
83
- logger: new Logger({ info: jest.fn(), warn: jest.fn(), error: jest.fn(), debug: jest.fn() }),
84
- });
85
-
86
- const result = await client.sendAgentMessage('[EIGENFLUX_TEST] first payload');
87
-
88
- expect(result).toEqual({
89
- sessionKey: 'agent:test:feishu:direct:ou_123',
90
- runId: 'run-1',
91
- });
92
- expect(methods).toEqual(['connect', 'agent']);
93
- expect(agentParams).toEqual(
94
- expect.objectContaining({
95
- sessionKey: 'agent:test:feishu:direct:ou_123',
96
- agentId: 'test',
97
- message: '[EIGENFLUX_TEST] first payload',
98
- deliver: true,
99
- replyChannel: 'feishu',
100
- replyTo: 'ou_123',
101
- })
102
- );
103
- });
104
-
105
- test('resolves session key from sessions.list when not configured', async () => {
106
- const methods: string[] = [];
107
- let agentParams: any = null;
108
-
109
- wss.on('connection', (socket) => {
110
- socket.send(
111
- JSON.stringify({
112
- type: 'event',
113
- event: 'connect.challenge',
114
- payload: { nonce: 'nonce-test-2' },
115
- })
116
- );
117
-
118
- socket.on('message', (raw) => {
119
- const frame = JSON.parse(raw.toString());
120
- methods.push(String(frame.method || ''));
121
-
122
- if (frame.method === 'connect') {
123
- socket.send(
124
- JSON.stringify({
125
- type: 'res',
126
- id: frame.id,
127
- ok: true,
128
- payload: {
129
- protocol: 3,
130
- server: { version: 'test', connId: 'conn-2' },
131
- features: { methods: ['sessions.list', 'agent'], events: [] },
132
- snapshot: { ts: Date.now() },
133
- policy: { maxPayload: 1000000, maxBufferedBytes: 1000000, tickIntervalMs: 30000 },
134
- },
135
- })
136
- );
137
- return;
138
- }
139
-
140
- if (frame.method === 'sessions.list') {
141
- socket.send(
142
- JSON.stringify({
143
- type: 'res',
144
- id: frame.id,
145
- ok: true,
146
- payload: {
147
- sessions: [{ key: 'agent:foo:main' }, { key: 'agent:foo:feishu:direct:ou_999', active: true }],
148
- },
149
- })
150
- );
151
- return;
152
- }
153
-
154
- if (frame.method === 'agent') {
155
- agentParams = frame.params;
156
- socket.send(
157
- JSON.stringify({
158
- type: 'res',
159
- id: frame.id,
160
- ok: true,
161
- payload: { status: 'started', runId: 'run-2' },
162
- })
163
- );
164
- }
165
- });
166
- });
167
-
168
- const client = new OpenClawGatewayRpcClient({
169
- gatewayUrl: `ws://127.0.0.1:${port}`,
170
- gatewayToken: 'gw_token_2',
171
- logger: new Logger({ info: jest.fn(), warn: jest.fn(), error: jest.fn(), debug: jest.fn() }),
172
- });
173
-
174
- const result = await client.sendAgentMessage('[EIGENFLUX_TEST] second payload');
175
-
176
- expect(result).toEqual({
177
- sessionKey: 'agent:foo:feishu:direct:ou_999',
178
- runId: 'run-2',
179
- });
180
- expect(methods).toEqual(['connect', 'sessions.list', 'agent']);
181
- expect(agentParams).toEqual(
182
- expect.objectContaining({
183
- sessionKey: 'agent:foo:feishu:direct:ou_999',
184
- agentId: 'foo',
185
- message: '[EIGENFLUX_TEST] second payload',
186
- deliver: true,
187
- })
188
- );
189
- });
190
- });