@eyeclaw/eyeclaw 1.0.4 → 2.0.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/index.ts CHANGED
@@ -1,9 +1,6 @@
1
1
  import type { OpenClawPluginApi } from 'openclaw/plugin-sdk'
2
2
  import { emptyPluginConfigSchema } from 'openclaw/plugin-sdk'
3
- import { EyeClawClient } from './src/client.js'
4
- import type { PluginConfig } from './src/types.js'
5
-
6
- let client: EyeClawClient | null = null
3
+ import { eyeclawPlugin } from './src/channel.js'
7
4
 
8
5
  /**
9
6
  * EyeClaw SDK - OpenClaw Channel Plugin
@@ -17,82 +14,8 @@ const plugin = {
17
14
  configSchema: emptyPluginConfigSchema(),
18
15
 
19
16
  register(api: OpenClawPluginApi) {
20
- const runtime = api.runtime
21
- const logger = runtime.logging.getChildLogger({ plugin: 'eyeclaw' })
22
- const config = runtime.config as any
23
-
24
- // Debug: log entire config structure
25
- logger.info('🔍 Full config:', JSON.stringify(config, null, 2))
26
- logger.info('🔍 Channels config:', JSON.stringify(config?.channels, null, 2))
27
-
28
- // Get EyeClaw config from channels.eyeclaw
29
- const eyeclawConfig: PluginConfig = config?.channels?.eyeclaw || {}
30
-
31
- // Debug: log eyeclaw config
32
- logger.info('🔍 EyeClaw config:', JSON.stringify(eyeclawConfig, null, 2))
33
- logger.info('🔍 botId type:', typeof eyeclawConfig.botId)
34
- logger.info('🔍 botId value:', eyeclawConfig.botId)
35
- logger.info('🔍 sdkToken type:', typeof eyeclawConfig.sdkToken)
36
- logger.info('🔍 sdkToken exists:', !!eyeclawConfig.sdkToken)
37
-
38
- // Check if enabled
39
- if (eyeclawConfig.enabled === false) {
40
- logger.info('Plugin disabled in config')
41
- return
42
- }
43
-
44
- // Validate required fields with detailed logging
45
- if (!eyeclawConfig.botId) {
46
- logger.warn('❌ botId is missing or falsy:', eyeclawConfig.botId)
47
- logger.warn('Configure with: openclaw config set channels.eyeclaw.botId "YOUR_BOT_ID"')
48
- return
49
- }
50
-
51
- if (!eyeclawConfig.sdkToken) {
52
- logger.warn('❌ sdkToken is missing or falsy')
53
- logger.warn('Configure with: openclaw config set channels.eyeclaw.sdkToken "YOUR_SDK_TOKEN"')
54
- return
55
- }
56
-
57
- logger.info('✅ Config validation passed')
58
-
59
- // Convert botId to string (OpenClaw may auto-convert "1" to number 1)
60
- eyeclawConfig.botId = String(eyeclawConfig.botId)
61
-
62
- // Set defaults
63
- eyeclawConfig.serverUrl = eyeclawConfig.serverUrl || 'http://localhost:3000'
64
- eyeclawConfig.reconnectInterval = eyeclawConfig.reconnectInterval || 5000
65
- eyeclawConfig.heartbeatInterval = eyeclawConfig.heartbeatInterval || 30000
66
-
67
- logger.info('🦞 Starting EyeClaw SDK...', { botId: eyeclawConfig.botId, serverUrl: eyeclawConfig.serverUrl })
68
-
69
- // Create logger adapter for client (simple console logger)
70
- const clientLogger = {
71
- debug: (msg: string) => logger.debug(msg),
72
- info: (msg: string) => logger.info(msg),
73
- warn: (msg: string) => logger.warn(msg),
74
- error: (msg: string) => logger.error(msg),
75
- }
76
-
77
- // Create and connect WebSocket client
78
- client = new EyeClawClient(eyeclawConfig, clientLogger)
79
-
80
- client.connect().then(() => {
81
- logger.info('✅ Successfully connected to EyeClaw platform')
82
- }).catch((error: Error) => {
83
- logger.error('Failed to connect to EyeClaw', { error: error.message })
84
- })
85
-
86
- // Handle shutdown
87
- const shutdown = () => {
88
- if (client) {
89
- logger.info('🛑 Shutting down EyeClaw SDK...')
90
- client.disconnect()
91
- }
92
- }
93
-
94
- process.on('SIGINT', shutdown)
95
- process.on('SIGTERM', shutdown)
17
+ // Register EyeClaw as a channel plugin
18
+ api.registerChannel({ plugin: eyeclawPlugin })
96
19
  },
97
20
  }
98
21
 
@@ -101,3 +24,4 @@ export default plugin
101
24
  // Re-export for direct usage
102
25
  export { EyeClawClient } from './src/client.js'
103
26
  export * from './src/types.js'
27
+ export { eyeclawPlugin } from './src/channel.js'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eyeclaw/eyeclaw",
3
- "version": "1.0.4",
3
+ "version": "2.0.0",
4
4
  "description": "EyeClaw channel plugin for OpenClaw - Connect your local OpenClaw instance to EyeClaw platform",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
package/src/channel.ts ADDED
@@ -0,0 +1,209 @@
1
+ import type { ChannelPlugin } from 'openclaw/plugin-sdk'
2
+ import { DEFAULT_ACCOUNT_ID } from 'openclaw/plugin-sdk'
3
+ import type { EyeClawConfig, ResolvedEyeClawAccount } from './types.js'
4
+ import { EyeClawClient } from './client.js'
5
+
6
+ // Active clients map (accountId -> client)
7
+ const clients = new Map<string, EyeClawClient>()
8
+
9
+ /**
10
+ * Resolve EyeClaw account configuration
11
+ */
12
+ function resolveEyeClawAccount(cfg: any, accountId: string): ResolvedEyeClawAccount {
13
+ const eyeclawConfig: EyeClawConfig = cfg?.channels?.eyeclaw || {}
14
+
15
+ // Default account uses top-level config
16
+ if (accountId === DEFAULT_ACCOUNT_ID) {
17
+ return {
18
+ accountId: DEFAULT_ACCOUNT_ID,
19
+ enabled: eyeclawConfig.enabled !== false,
20
+ configured: !!(eyeclawConfig.botId && eyeclawConfig.sdkToken),
21
+ name: 'Default',
22
+ config: eyeclawConfig,
23
+ }
24
+ }
25
+
26
+ // Named accounts not supported yet
27
+ throw new Error(`Named accounts not yet supported for EyeClaw`)
28
+ }
29
+
30
+ /**
31
+ * List all EyeClaw account IDs
32
+ */
33
+ function listEyeClawAccountIds(cfg: any): string[] {
34
+ return [DEFAULT_ACCOUNT_ID]
35
+ }
36
+
37
+ /**
38
+ * EyeClaw Channel Plugin
39
+ */
40
+ export const eyeclawPlugin: ChannelPlugin<ResolvedEyeClawAccount> = {
41
+ id: 'eyeclaw',
42
+
43
+ meta: {
44
+ id: 'eyeclaw',
45
+ label: 'EyeClaw',
46
+ selectionLabel: 'EyeClaw Platform',
47
+ docsPath: '/channels/eyeclaw',
48
+ docsLabel: 'eyeclaw',
49
+ blurb: 'EyeClaw platform integration via WebSocket.',
50
+ order: 100,
51
+ },
52
+
53
+ capabilities: {
54
+ chatTypes: ['direct', 'channel'],
55
+ polls: false,
56
+ threads: false,
57
+ media: false,
58
+ reactions: false,
59
+ edit: false,
60
+ reply: false,
61
+ },
62
+
63
+ reload: { configPrefixes: ['channels.eyeclaw'] },
64
+
65
+ configSchema: {
66
+ schema: {
67
+ type: 'object',
68
+ additionalProperties: true,
69
+ properties: {
70
+ enabled: {
71
+ type: 'boolean',
72
+ description: 'Enable/disable the plugin',
73
+ },
74
+ botId: {
75
+ type: ['string', 'number'],
76
+ description: 'Bot ID from EyeClaw platform',
77
+ },
78
+ sdkToken: {
79
+ type: 'string',
80
+ description: 'SDK token for authentication',
81
+ },
82
+ serverUrl: {
83
+ type: 'string',
84
+ description: 'EyeClaw server URL',
85
+ },
86
+ reconnectInterval: {
87
+ type: 'number',
88
+ description: 'Reconnect interval in milliseconds',
89
+ },
90
+ heartbeatInterval: {
91
+ type: 'number',
92
+ description: 'Heartbeat interval in milliseconds',
93
+ },
94
+ },
95
+ },
96
+ },
97
+
98
+ config: {
99
+ listAccountIds: (cfg) => listEyeClawAccountIds(cfg),
100
+ resolveAccount: (cfg, accountId) => resolveEyeClawAccount(cfg, accountId || DEFAULT_ACCOUNT_ID),
101
+ defaultAccountId: () => DEFAULT_ACCOUNT_ID,
102
+ },
103
+
104
+ status: {
105
+ defaultRuntime: {
106
+ accountId: DEFAULT_ACCOUNT_ID,
107
+ running: false,
108
+ lastStartAt: null,
109
+ lastStopAt: null,
110
+ lastError: null,
111
+ },
112
+
113
+ buildChannelSummary: ({ snapshot }) => ({
114
+ configured: snapshot.configured ?? false,
115
+ running: snapshot.running ?? false,
116
+ lastStartAt: snapshot.lastStartAt ?? null,
117
+ lastStopAt: snapshot.lastStopAt ?? null,
118
+ lastError: snapshot.lastError ?? null,
119
+ }),
120
+
121
+ probeAccount: async ({ account }) => {
122
+ // Simple probe - check if configured
123
+ return {
124
+ ok: account.configured,
125
+ message: account.configured ? 'Configured' : 'Not configured',
126
+ }
127
+ },
128
+
129
+ buildAccountSnapshot: ({ account, runtime, probe }) => ({
130
+ accountId: account.accountId,
131
+ enabled: account.enabled,
132
+ configured: account.configured,
133
+ name: account.name,
134
+ running: runtime?.running ?? false,
135
+ lastStartAt: runtime?.lastStartAt ?? null,
136
+ lastStopAt: runtime?.lastStopAt ?? null,
137
+ lastError: runtime?.lastError ?? null,
138
+ probe,
139
+ }),
140
+ },
141
+
142
+ gateway: {
143
+ startAccount: async (ctx) => {
144
+ const account = resolveEyeClawAccount(ctx.cfg, ctx.accountId)
145
+
146
+ if (!account.configured || !account.config) {
147
+ throw new Error('EyeClaw not configured. Please set botId and sdkToken.')
148
+ }
149
+
150
+ const config = account.config
151
+
152
+ // Validate required fields
153
+ if (!config.botId || !config.sdkToken) {
154
+ throw new Error('botId and sdkToken are required')
155
+ }
156
+
157
+ // Set defaults
158
+ const clientConfig = {
159
+ botId: String(config.botId),
160
+ sdkToken: config.sdkToken,
161
+ serverUrl: config.serverUrl || 'http://localhost:3000',
162
+ reconnectInterval: config.reconnectInterval || 5000,
163
+ heartbeatInterval: config.heartbeatInterval || 30000,
164
+ enabled: true,
165
+ }
166
+
167
+ ctx.log?.info(`🦞 Starting EyeClaw SDK... botId=${clientConfig.botId}, serverUrl=${clientConfig.serverUrl}`)
168
+
169
+ // Create logger adapter
170
+ const logger = {
171
+ debug: (msg: string) => ctx.log?.debug?.(msg),
172
+ info: (msg: string) => ctx.log?.info(msg),
173
+ warn: (msg: string) => ctx.log?.warn(msg),
174
+ error: (msg: string) => ctx.log?.error(msg),
175
+ }
176
+
177
+ // Create and connect client
178
+ const client = new EyeClawClient(clientConfig, logger)
179
+ clients.set(ctx.accountId, client)
180
+
181
+ try {
182
+ await client.connect()
183
+ ctx.log?.info('✅ Successfully connected to EyeClaw platform')
184
+ ctx.setStatus({ accountId: ctx.accountId, running: true, lastStartAt: Date.now() })
185
+
186
+ // Wait for abort signal
187
+ await new Promise<void>((resolve) => {
188
+ ctx.abortSignal.addEventListener('abort', () => {
189
+ ctx.log?.info('🛑 Shutting down EyeClaw SDK...')
190
+ client.disconnect()
191
+ clients.delete(ctx.accountId)
192
+ ctx.setStatus({ accountId: ctx.accountId, running: false, lastStopAt: Date.now() })
193
+ resolve()
194
+ })
195
+ })
196
+ } catch (error) {
197
+ const errorMsg = error instanceof Error ? error.message : String(error)
198
+ ctx.log?.error(`Failed to connect to EyeClaw: ${errorMsg}`)
199
+ ctx.setStatus({
200
+ accountId: ctx.accountId,
201
+ running: false,
202
+ lastError: errorMsg,
203
+ lastStopAt: Date.now(),
204
+ })
205
+ throw error
206
+ }
207
+ },
208
+ },
209
+ }
package/src/cli.ts CHANGED
@@ -51,7 +51,7 @@ function main() {
51
51
  // Default: show usage
52
52
  console.log(USAGE)
53
53
  console.log(chalk.yellow('ℹ This is an OpenClaw plugin. Please install it using:'))
54
- console.log(chalk.cyan(' openclaw plugins install @eyeclaw/sdk\n'))
54
+ console.log(chalk.cyan(' openclaw plugins install @eyeclaw/eyeclaw\n'))
55
55
  }
56
56
 
57
57
  main()
package/src/types.ts CHANGED
@@ -1,5 +1,21 @@
1
- // Type definitions for OpenClaw plugin system
2
- // Reference: clawdbot-feishu architecture
1
+ // Type definitions for EyeClaw Channel Plugin
2
+
3
+ export interface EyeClawConfig {
4
+ enabled?: boolean
5
+ botId: string | number
6
+ sdkToken: string
7
+ serverUrl?: string
8
+ reconnectInterval?: number
9
+ heartbeatInterval?: number
10
+ }
11
+
12
+ export interface ResolvedEyeClawAccount {
13
+ accountId: string
14
+ enabled: boolean
15
+ configured: boolean
16
+ name: string
17
+ config?: EyeClawConfig
18
+ }
3
19
 
4
20
  export interface PluginConfig {
5
21
  enabled: boolean