@2en/clawly-plugins 1.20.1 → 1.21.1
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/gateway/index.ts +0 -2
- package/index.ts +3 -0
- package/package.json +1 -1
- package/gateway/channels-configure.ts +0 -151
package/gateway/index.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type {PluginApi} from '../index'
|
|
2
2
|
import {registerAgentSend} from './agent'
|
|
3
|
-
import {registerChannelsConfigure} from './channels-configure'
|
|
4
3
|
import {registerClawhub2gateway} from './clawhub2gateway'
|
|
5
4
|
import {registerConfigRepair} from './config-repair'
|
|
6
5
|
import {registerPairing} from './pairing'
|
|
@@ -17,7 +16,6 @@ export function registerGateway(api: PluginApi) {
|
|
|
17
16
|
registerMemoryBrowser(api)
|
|
18
17
|
registerClawhub2gateway(api)
|
|
19
18
|
registerPlugins(api)
|
|
20
|
-
registerChannelsConfigure(api)
|
|
21
19
|
registerOfflinePush(api)
|
|
22
20
|
registerConfigRepair(api)
|
|
23
21
|
registerPairing(api)
|
package/index.ts
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* - /clawly_echo — echo text back without LLM
|
|
22
22
|
*
|
|
23
23
|
* Hooks:
|
|
24
|
+
* - before_message_write — restores original /skill command in user messages (undoes gateway rewrite)
|
|
24
25
|
* - tool_result_persist — copies TTS audio to persistent outbound directory
|
|
25
26
|
* - before_tool_call — enforces delivery fields on cron.create
|
|
26
27
|
* - agent_end — sends push notification when client is offline
|
|
@@ -36,6 +37,7 @@ import {registerGateway} from './gateway'
|
|
|
36
37
|
import {getGatewayConfig} from './gateway-fetch'
|
|
37
38
|
import {setupModelGateway} from './model-gateway-setup'
|
|
38
39
|
import {registerOutboundHook, registerOutboundHttpRoute, registerOutboundMethods} from './outbound'
|
|
40
|
+
import {registerSkillCommandRestore} from './skill-command-restore'
|
|
39
41
|
import {registerTools} from './tools'
|
|
40
42
|
|
|
41
43
|
type PluginRuntime = {
|
|
@@ -108,6 +110,7 @@ export default {
|
|
|
108
110
|
name: 'Clawly Plugins',
|
|
109
111
|
description: 'Clawly utility RPC methods (clawly.*).',
|
|
110
112
|
register(api: PluginApi) {
|
|
113
|
+
registerSkillCommandRestore(api)
|
|
111
114
|
registerOutboundHook(api)
|
|
112
115
|
registerOutboundMethods(api)
|
|
113
116
|
registerOutboundHttpRoute(api)
|
package/package.json
CHANGED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Channel configuration management via openclaw.json.
|
|
3
|
-
*
|
|
4
|
-
* Methods:
|
|
5
|
-
* - clawly.channels.configure — add/update a channel account config
|
|
6
|
-
* - clawly.channels.disconnect — remove a channel account config
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import fs from 'node:fs'
|
|
10
|
-
import path from 'node:path'
|
|
11
|
-
|
|
12
|
-
import type {PluginApi} from '../index'
|
|
13
|
-
|
|
14
|
-
const TOKEN_CHANNELS = new Set(['telegram', 'discord', 'slack', 'irc', 'googlechat'])
|
|
15
|
-
|
|
16
|
-
function resolveStateDir(api: PluginApi): string {
|
|
17
|
-
return api.runtime.state?.resolveStateDir?.(process.env) ?? process.env.OPENCLAW_STATE_DIR ?? ''
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function readOpenclawConfig(configPath: string): Record<string, unknown> {
|
|
21
|
-
try {
|
|
22
|
-
return JSON.parse(fs.readFileSync(configPath, 'utf-8'))
|
|
23
|
-
} catch {
|
|
24
|
-
return {}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function writeOpenclawConfig(configPath: string, config: Record<string, unknown>) {
|
|
29
|
-
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n')
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function registerChannelsConfigure(api: PluginApi) {
|
|
33
|
-
// ── clawly.channels.configure ──────────────────────────────────
|
|
34
|
-
|
|
35
|
-
api.registerGatewayMethod('clawly.channels.configure', async ({params, respond}) => {
|
|
36
|
-
const channel = typeof params.channel === 'string' ? params.channel.trim() : ''
|
|
37
|
-
const accountId = typeof params.accountId === 'string' ? params.accountId.trim() : 'default'
|
|
38
|
-
const config =
|
|
39
|
-
params.config && typeof params.config === 'object' && !Array.isArray(params.config)
|
|
40
|
-
? (params.config as Record<string, unknown>)
|
|
41
|
-
: null
|
|
42
|
-
|
|
43
|
-
if (!channel) {
|
|
44
|
-
respond(false, undefined, {code: 'invalid_params', message: 'channel is required'})
|
|
45
|
-
return
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (!TOKEN_CHANNELS.has(channel)) {
|
|
49
|
-
respond(false, undefined, {
|
|
50
|
-
code: 'invalid_params',
|
|
51
|
-
message: `unsupported channel: ${channel}. Supported: ${[...TOKEN_CHANNELS].join(', ')}`,
|
|
52
|
-
})
|
|
53
|
-
return
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (!config) {
|
|
57
|
-
respond(false, undefined, {code: 'invalid_params', message: 'config object is required'})
|
|
58
|
-
return
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const stateDir = resolveStateDir(api)
|
|
62
|
-
if (!stateDir) {
|
|
63
|
-
respond(false, undefined, {code: 'internal', message: 'cannot resolve openclaw state dir'})
|
|
64
|
-
return
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const configPath = path.join(stateDir, 'openclaw.json')
|
|
68
|
-
|
|
69
|
-
try {
|
|
70
|
-
const ocConfig = readOpenclawConfig(configPath)
|
|
71
|
-
|
|
72
|
-
// Ensure channels.<channel>.accounts.<accountId> path exists
|
|
73
|
-
if (!ocConfig.channels || typeof ocConfig.channels !== 'object') {
|
|
74
|
-
ocConfig.channels = {}
|
|
75
|
-
}
|
|
76
|
-
const channels = ocConfig.channels as Record<string, unknown>
|
|
77
|
-
|
|
78
|
-
if (!channels[channel] || typeof channels[channel] !== 'object') {
|
|
79
|
-
channels[channel] = {}
|
|
80
|
-
}
|
|
81
|
-
const channelConfig = channels[channel] as Record<string, unknown>
|
|
82
|
-
|
|
83
|
-
if (!channelConfig.accounts || typeof channelConfig.accounts !== 'object') {
|
|
84
|
-
channelConfig.accounts = {}
|
|
85
|
-
}
|
|
86
|
-
const accounts = channelConfig.accounts as Record<string, unknown>
|
|
87
|
-
|
|
88
|
-
// Merge config with enabled: true
|
|
89
|
-
accounts[accountId] = {
|
|
90
|
-
...((accounts[accountId] as Record<string, unknown>) ?? {}),
|
|
91
|
-
...config,
|
|
92
|
-
enabled: true,
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
writeOpenclawConfig(configPath, ocConfig)
|
|
96
|
-
api.logger.info(`channels.configure: wrote ${channel}/${accountId} to openclaw.json`)
|
|
97
|
-
|
|
98
|
-
respond(true, {ok: true, channel, accountId})
|
|
99
|
-
} catch (err) {
|
|
100
|
-
const msg = err instanceof Error ? err.message : String(err)
|
|
101
|
-
api.logger.error(`channels.configure: failed — ${msg}`)
|
|
102
|
-
respond(false, undefined, {code: 'internal', message: msg})
|
|
103
|
-
}
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
// ── clawly.channels.disconnect ─────────────────────────────────
|
|
107
|
-
|
|
108
|
-
api.registerGatewayMethod('clawly.channels.disconnect', async ({params, respond}) => {
|
|
109
|
-
const channel = typeof params.channel === 'string' ? params.channel.trim() : ''
|
|
110
|
-
const accountId = typeof params.accountId === 'string' ? params.accountId.trim() : 'default'
|
|
111
|
-
|
|
112
|
-
if (!channel) {
|
|
113
|
-
respond(false, undefined, {code: 'invalid_params', message: 'channel is required'})
|
|
114
|
-
return
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const stateDir = resolveStateDir(api)
|
|
118
|
-
if (!stateDir) {
|
|
119
|
-
respond(false, undefined, {code: 'internal', message: 'cannot resolve openclaw state dir'})
|
|
120
|
-
return
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const configPath = path.join(stateDir, 'openclaw.json')
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
const ocConfig = readOpenclawConfig(configPath)
|
|
127
|
-
const channels = ocConfig.channels as Record<string, unknown> | undefined
|
|
128
|
-
|
|
129
|
-
if (channels && typeof channels === 'object') {
|
|
130
|
-
const channelConfig = channels[channel] as Record<string, unknown> | undefined
|
|
131
|
-
if (channelConfig && typeof channelConfig === 'object') {
|
|
132
|
-
const accounts = channelConfig.accounts as Record<string, unknown> | undefined
|
|
133
|
-
if (accounts && typeof accounts === 'object' && accountId in accounts) {
|
|
134
|
-
delete accounts[accountId]
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
writeOpenclawConfig(configPath, ocConfig)
|
|
140
|
-
api.logger.info(`channels.disconnect: removed ${channel}/${accountId} from openclaw.json`)
|
|
141
|
-
|
|
142
|
-
respond(true, {ok: true, channel, accountId})
|
|
143
|
-
} catch (err) {
|
|
144
|
-
const msg = err instanceof Error ? err.message : String(err)
|
|
145
|
-
api.logger.error(`channels.disconnect: failed — ${msg}`)
|
|
146
|
-
respond(false, undefined, {code: 'internal', message: msg})
|
|
147
|
-
}
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
api.logger.info('channels: registered clawly.channels.configure + clawly.channels.disconnect')
|
|
151
|
-
}
|