@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 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,6 +1,6 @@
1
1
  {
2
2
  "name": "@2en/clawly-plugins",
3
- "version": "1.20.1",
3
+ "version": "1.21.1",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "repository": {
@@ -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
- }