@dcrays/dcgchat 0.4.29 → 0.5.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.
@@ -3,9 +3,25 @@
3
3
  "channels": [
4
4
  "dcgchat"
5
5
  ],
6
+ "description": "Gateway `event=cron` + `action=finished` 时:优先在 payload 中按 schemas/gateway-cron-finished.payload.json 提供 `attachments`;若缺省,插件在工作区规则下从 summary 回退提取路径并经 sendMedia 发送。",
6
7
  "configSchema": {
7
8
  "type": "object",
8
9
  "additionalProperties": false,
9
- "properties": {}
10
+ "properties": {
11
+ "allowedPaths": {
12
+ "type": "array",
13
+ "items": {
14
+ "type": "string"
15
+ },
16
+ "description": "允许发送文件的额外路径列表"
17
+ },
18
+ "allowedAttachmentExtensions": {
19
+ "type": "array",
20
+ "items": {
21
+ "type": "string"
22
+ },
23
+ "description": "在插件默认附件扩展名之外额外允许的后缀,如 [\".go\", \".rs\"]。默认已含常见办公/媒体及 .py/.ipynb 等;可省略本项。"
24
+ }
25
+ }
10
26
  }
11
27
  }
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@dcrays/dcgchat",
3
- "version": "0.4.29",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "description": "OpenClaw channel plugin for 书灵墨宝 (WebSocket)",
6
- "main": "index.ts",
6
+ "main": "index.js",
7
7
  "license": "MIT",
8
8
  "files": [
9
- "index.ts",
10
- "src",
11
- "openclaw.plugin.json"
9
+ "index.js",
10
+ "openclaw.plugin.json",
11
+ "schemas"
12
12
  ],
13
13
  "keywords": [
14
14
  "openclaw",
@@ -16,16 +16,17 @@
16
16
  "websocket",
17
17
  "ai"
18
18
  ],
19
- "dependencies": {
20
- "ali-oss": "file:src/libs/ali-oss-6.23.0.tgz",
21
- "axios": "file:src/libs/axios-1.13.6.tgz",
22
- "md5": "file:src/libs/md5-2.3.0.tgz",
23
- "unzipper": "file:src/libs/unzipper-0.12.3.tgz",
24
- "ws": "file:src/libs/ws-8.19.0.tgz"
19
+ "peerDependencies": {
20
+ "openclaw": ">=2026.4.15"
21
+ },
22
+ "peerDependenciesMeta": {
23
+ "openclaw": {
24
+ "optional": true
25
+ }
25
26
  },
26
27
  "openclaw": {
27
28
  "extensions": [
28
- "./index.ts"
29
+ "./index.js"
29
30
  ],
30
31
  "channel": {
31
32
  "id": "dcgchat",
@@ -39,7 +40,11 @@
39
40
  "install": {
40
41
  "npmSpec": "@dcrays/dcgchat",
41
42
  "localPath": "extensions/dcgchat",
42
- "defaultChoice": "npm"
43
+ "defaultChoice": "npm",
44
+ "minHostVersion": ">=2026.4.12"
45
+ },
46
+ "compat": {
47
+ "pluginApi": ">=2026.4.12"
43
48
  }
44
49
  }
45
50
  }
@@ -0,0 +1,39 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://dcgchat.local/schemas/gateway-cron-finished.payload.json",
4
+ "title": "Gateway WS event: cron finished (dcgchat contract)",
5
+ "description": "网关下行 `event: \"cron\"` 且 `payload.action === \"finished\"` 时,书灵通道插件读取的约定字段。`attachments` 为首选:须为 Gateway 进程可读的绝对路径,经通道 sendMedia 发送。若宿主未提供 `attachments`,插件会回退为仅在工作区/挂载规则下从 `summary` 提取路径(与 dcgchat_message 一致),直至宿主实现本字段。",
6
+ "type": "object",
7
+ "properties": {
8
+ "jobId": { "type": "string" },
9
+ "action": { "const": "finished" },
10
+ "status": { "type": "string" },
11
+ "summary": { "type": "string" },
12
+ "delivered": { "type": "boolean" },
13
+ "deliveryStatus": { "type": "string" },
14
+ "sessionId": { "type": "string" },
15
+ "sessionKey": { "type": "string" },
16
+ "attachments": {
17
+ "type": "array",
18
+ "description": "本轮定时任务产出的本地文件路径,按顺序经通道发送为附件",
19
+ "items": {
20
+ "oneOf": [
21
+ {
22
+ "type": "string",
23
+ "minLength": 1,
24
+ "description": "绝对路径"
25
+ },
26
+ {
27
+ "type": "object",
28
+ "additionalProperties": false,
29
+ "properties": {
30
+ "path": { "type": "string", "minLength": 1 },
31
+ "file": { "type": "string", "minLength": 1 }
32
+ },
33
+ "description": "对象形式:优先读取 `path`,否则 `file`"
34
+ }
35
+ ]
36
+ }
37
+ }
38
+ }
39
+ }
package/index.ts DELETED
@@ -1,26 +0,0 @@
1
- import type { OpenClawPluginApi } from 'openclaw/plugin-sdk'
2
- import { emptyPluginConfigSchema } from 'openclaw/plugin-sdk'
3
- import { dcgchatPlugin } from './src/channel.js'
4
- import { setDcgchatRuntime, setWorkspaceDir } from './src/utils/global.js'
5
- import { monitoringToolMessage } from './src/tool.js'
6
- import { setOpenClawConfig } from './src/utils/global.js'
7
- import { createDcgchatMessageTool } from './src/tools/messageTool.js'
8
-
9
- const plugin = {
10
- id: "dcgchat",
11
- name: '书灵墨宝',
12
- description: '连接 OpenClaw 与 书灵墨宝 产品(WebSocket)',
13
- configSchema: emptyPluginConfigSchema(),
14
- register(api: OpenClawPluginApi) {
15
- setDcgchatRuntime(api.runtime)
16
- monitoringToolMessage(api)
17
- setOpenClawConfig(api.config)
18
- api.registerChannel({ plugin: dcgchatPlugin })
19
- setWorkspaceDir(api.config?.agents?.defaults?.workspace)
20
- api.registerTool((ctx) => {
21
- return createDcgchatMessageTool(ctx)
22
- })
23
- }
24
- }
25
-
26
- export default plugin
package/src/agent.ts DELETED
@@ -1,128 +0,0 @@
1
- import axios from 'axios'
2
- import fs from 'fs'
3
- import path from 'path'
4
- import { getWorkspaceDir } from './utils/global.js'
5
- import { getWsConnection } from './utils/global.js'
6
- import { dcgLogger } from './utils/log.js'
7
- import { isWsOpen } from './transport.js'
8
- import { sendMessageToGateway } from './gateway/socket.js'
9
- import { extractZipBufferToDirectory } from './utils/zipExtract.js'
10
-
11
- type IAgentParams = {
12
- url: string
13
- agent_code: string
14
- agent_name: string
15
- agent_description: string
16
- }
17
-
18
- function sendEvent(msgContent: Record<string, any>) {
19
- const ws = getWsConnection()
20
- if (isWsOpen()) {
21
- ws?.send(
22
- JSON.stringify({
23
- messageType: 'openclaw_bot_event',
24
- source: 'client',
25
- content: msgContent
26
- })
27
- )
28
- dcgLogger(`agent安装: ${JSON.stringify(msgContent)}`)
29
- }
30
- }
31
-
32
- /** 若 workspace-${clone_code}/agent 存在,则复制到 agents/${clone_code}/agent */
33
- function copyAgentsFiles(clone_code: string) {
34
- const workspacePath = getWorkspaceDir()
35
- if (!workspacePath) return
36
- const workspaceDir = path.join(workspacePath, '../', `workspace-${clone_code}`)
37
- const agentDir = path.join(workspacePath, '../', `agents/${clone_code}`)
38
- const sourceAgent = path.join(workspaceDir, 'agent')
39
- try {
40
- if (!fs.existsSync(sourceAgent)) return
41
- if (!fs.statSync(sourceAgent).isDirectory()) return
42
- fs.mkdirSync(agentDir, { recursive: true })
43
- const dest = path.join(agentDir, 'agent')
44
- if (fs.existsSync(dest)) {
45
- fs.rmSync(dest, { recursive: true, force: true })
46
- }
47
- fs.cpSync(sourceAgent, dest, { recursive: true })
48
- } catch (err: unknown) {
49
- dcgLogger(`copyAgentsFiles failed: ${String(err)}`, 'error')
50
- }
51
- }
52
-
53
- export async function onCreateAgent(params: Record<string, any>) {
54
- const { clone_code, name, description } = params
55
- try {
56
- const workspacePath = getWorkspaceDir()
57
- if (!workspacePath) return
58
- const workspaceDir = path.join(workspacePath, '../', `workspace-${clone_code}`)
59
- await sendMessageToGateway(JSON.stringify({ method: 'agents.create', params: { name: clone_code, workspace: workspaceDir } }))
60
- } catch (err: unknown) {
61
- dcgLogger(`agents.create failed: ${String(err)}`, 'error')
62
- }
63
- // Update config.name to the user-supplied display name (may contain CJK, spaces, etc.)
64
- try {
65
- await sendMessageToGateway(JSON.stringify({ method: 'agents.update', params: { name: name, agentId: clone_code } }))
66
- } catch (err: unknown) {
67
- dcgLogger(`agents.update failed: ${String(err)}`, 'error')
68
- }
69
- // if (description?.trim()) {
70
- // try {
71
- // await sendMessageToGateway(
72
- // JSON.stringify({
73
- // method: 'agents.files.set',
74
- // params: { agentId: clone_code, name: 'IDENTITY.md', content: description.trim() }
75
- // })
76
- // )
77
- // } catch {
78
- // // Non-fatal
79
- // }
80
- // }
81
- // if (name?.trim()) {
82
- // try {
83
- // await sendMessageToGateway(
84
- // JSON.stringify({
85
- // method: 'agents.files.set',
86
- // params: { agentId: clone_code, name: 'USER.md', content: name.trim() }
87
- // })
88
- // )
89
- // } catch {
90
- // // Non-fatal
91
- // }
92
- // }
93
- copyAgentsFiles(clone_code)
94
- sendEvent({ ...params, status: 'ok' })
95
- }
96
-
97
- export async function createAgent(msgContent: Record<string, any>) {
98
- const { url, clone_code } = msgContent
99
- if (!url || !clone_code) {
100
- dcgLogger(`createAgent failed empty url&clone_code: ${JSON.stringify(msgContent)}`, 'error')
101
- sendEvent({ ...msgContent, status: 'fail' })
102
- return
103
- }
104
- const workspacePath = getWorkspaceDir()
105
- const workspaceDir = path.join(workspacePath, '../', `workspace-${clone_code}`)
106
-
107
- // 如果目标目录已存在,先删除
108
- if (fs.existsSync(workspaceDir)) {
109
- fs.rmSync(workspaceDir, { recursive: true, force: true })
110
- }
111
-
112
- try {
113
- const response = await axios({
114
- method: 'get',
115
- url,
116
- responseType: 'arraybuffer'
117
- })
118
- fs.mkdirSync(workspaceDir, { recursive: true })
119
- await extractZipBufferToDirectory(Buffer.from(response.data), workspaceDir)
120
- await onCreateAgent(msgContent)
121
- } catch (error) {
122
- // 如果安装失败,清理目录
123
- if (fs.existsSync(workspaceDir)) {
124
- fs.rmSync(workspaceDir, { recursive: true, force: true })
125
- }
126
- sendEvent({ ...msgContent, status: 'fail' })
127
- }
128
- }