@dcrays/dcgchat-test 0.4.22 → 0.4.23

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dcrays/dcgchat-test",
3
- "version": "0.4.22",
3
+ "version": "0.4.23",
4
4
  "type": "module",
5
5
  "description": "OpenClaw channel plugin for 书灵墨宝 (WebSocket)",
6
6
  "main": "index.ts",
package/src/channel.ts CHANGED
@@ -113,11 +113,7 @@ export async function sendDcgchatMedia(opts: DcgchatMediaSendOptions): Promise<v
113
113
  sessionKey = resolveIsolatedCronSessionToJobSessionKey(sessionKey)
114
114
 
115
115
  /** 定时自动执行未走 onRunCronJob,须与 finishedDcgchatCron 共用同一 messageId,否则附件与气泡错位 */
116
- if (
117
- !opts.messageId?.trim() &&
118
- (fromIsolatedCron || fromDcgCronWrapper) &&
119
- !getCronMessageId(sessionKey)
120
- ) {
116
+ if (!opts.messageId?.trim() && (fromIsolatedCron || fromDcgCronWrapper) && !getCronMessageId(sessionKey)) {
121
117
  setCronMessageId(sessionKey, `${Date.now()}`)
122
118
  }
123
119
 
@@ -152,7 +148,7 @@ export async function sendDcgchatMedia(opts: DcgchatMediaSendOptions): Promise<v
152
148
  return
153
149
  }
154
150
  const fileName = mediaUrl?.split(/[\\/]/).pop() || ''
155
- const notMessageId = `${msgCtx?.messageId}`?.length !== 13 || !msgCtx?.messageId
151
+ const notMessageId = `${msgCtx?.messageId}`?.length === 13 || !msgCtx?.messageId
156
152
  try {
157
153
  const botToken = msgCtx.botToken ?? getOpenClawConfig()?.channels?.["dcgchat-test"]?.botToken ?? ''
158
154
  const url = opts.mediaUrl ? await ossUpload(opts.mediaUrl, botToken, 1) : ''
@@ -7,6 +7,9 @@ import { channelInfo, ENV } from './utils/constant.js'
7
7
  * 自动注入 bestEffort: true,使投递失败时静默降级,
8
8
  * 不影响 cron 执行结果的保存。
9
9
  *
10
+ * 另:拦截高危 exec,避免对话内 `openclaw gateway start` 向已运行网关发 SIGTERM、
11
+ * 以及反复 `openclaw cron add` 阻塞与握手超时——应改用内置 `cron` 工具或 Gateway RPC。
12
+ *
10
13
  * 背景:
11
14
  * - 定时任务的 delivery 设为 announce 模式,如果没有指定 channel,
12
15
  * 投递可能因找不到有效渠道而失败
@@ -79,6 +82,23 @@ function isCronTool(toolName: string): boolean {
79
82
  return toolName === 'cron'
80
83
  }
81
84
 
85
+ /** 非 running 会话(如定时触发)也需跑本钩子的 exec 子串 */
86
+ export function execCommandNeedsCronToolHook(command: string): boolean {
87
+ const c = command.trim()
88
+ if (!c) return false
89
+ if (c.includes('cron create') || c.includes('cron add')) return true
90
+ return /\bopenclaw\s+gateway\s+start\b/i.test(c)
91
+ }
92
+
93
+ const BLOCK_GATEWAY_START =
94
+ '禁止在对话内 exec `openclaw gateway start`:当前会话可能正跑在本网关上,重复启动会先 SIGTERM 旧进程导致断连。' +
95
+ '若仅需确认存活,请改用只读命令,例如 `openclaw gateway health --json` 或 `openclaw gateway probe`(以本机 CLI 为准)。' +
96
+ '若确认网关未运行,请在宿主机/服务管理(systemd 等)中启动,勿由 Agent 代 exec。'
97
+
98
+ const BLOCK_CRON_CLI =
99
+ '请勿用 exec 跑 `openclaw cron add` / `openclaw cron create`:请改用内置 **`cron` 工具**(框架走 Gateway `cron.*`,由本插件自动补全 delivery / sessionKey)。' +
100
+ '高频 exec CLI 易长时间占满子进程并加剧网关 WebSocket 握手压力。'
101
+
82
102
  /**
83
103
  * 从 cron 参数中提取 delivery 配置
84
104
  * cron 工具的参数结构可能是:
@@ -188,14 +208,22 @@ export function cronToolCall(event: { toolName: any; params: any; toolCallId: an
188
208
 
189
209
  return { params: newParams }
190
210
  } else if (toolName === 'exec') {
191
- if (params.command.indexOf('cron create') > -1 || params.command.indexOf('cron add') > -1) {
211
+ const cmd = typeof params.command === 'string' ? params.command : ''
212
+ if (/\bopenclaw\s+gateway\s+start\b/i.test(cmd)) {
213
+ dcgLogger(`[${LOG_TAG}] blocked exec gateway start (${toolCallId})`)
214
+ return { block: true, blockReason: BLOCK_GATEWAY_START }
215
+ }
216
+ if (/\bopenclaw\s+cron\s+(add|create)\b/i.test(cmd)) {
217
+ dcgLogger(`[${LOG_TAG}] blocked exec openclaw cron add/create (${toolCallId})`)
218
+ return { block: true, blockReason: BLOCK_CRON_CLI }
219
+ }
220
+ if (cmd.includes('cron create') || cmd.includes('cron add')) {
192
221
  const newParams = JSON.parse(JSON.stringify(params)) as Record<string, unknown>
193
222
  newParams.command =
194
- params.command.replace('--json', '') + ` --session-key ${sk} --channel ${"dcgchat-test"} --to dcg-cron:${sk} --json`
223
+ cmd.replace(/--json/g, '').trimEnd() + ` --session-key ${sk} --channel ${"dcgchat-test"} --to dcg-cron:${sk} --json`
195
224
  return { params: newParams }
196
- } else {
197
- return undefined
198
225
  }
226
+ return undefined
199
227
  }
200
228
 
201
229
  return undefined
package/src/tool.ts CHANGED
@@ -3,7 +3,7 @@ import { getMsgStatus } from './utils/global.js'
3
3
  import { dcgLogger } from './utils/log.js'
4
4
  import { sendFinal, sendText, wsSendRaw } from './transport.js'
5
5
  import { getEffectiveMsgParams, deleteSessionKeyBySubAgentRunId, setSessionKeyBySubAgentRunId } from './utils/params.js'
6
- import { cronToolCall } from './cronToolCall.js'
6
+ import { cronToolCall, execCommandNeedsCronToolHook } from './cronToolCall.js'
7
7
 
8
8
  type PluginHookName =
9
9
  | 'before_model_resolve'
@@ -330,7 +330,7 @@ function shouldRunBeforeToolCallWithoutRunningSession(event: { toolName?: string
330
330
  if (event?.toolName === 'cron') return true
331
331
  const cmd = event?.params?.command
332
332
  if (event?.toolName === 'exec' && typeof cmd === 'string') {
333
- return cmd.includes('cron create') || cmd.includes('cron add')
333
+ return execCommandNeedsCronToolHook(cmd)
334
334
  }
335
335
  return false
336
336
  }