@wenbin_wb/dsh-bridge 2.2.7 → 2.2.8
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/lib/platform/conversation-bridge.js +14 -10
- package/lib/qq/node.js +26 -2
- package/package.json +1 -1
|
@@ -634,14 +634,14 @@ export class ConversationBridge {
|
|
|
634
634
|
const timeoutSec = this.config.approvalTimeoutSec
|
|
635
635
|
const timeoutMin = Math.max(1, Math.round(timeoutSec / 60))
|
|
636
636
|
const prompt = [
|
|
637
|
-
|
|
637
|
+
`## ⚠️ 操作权限确认 (#${number})`,
|
|
638
638
|
'',
|
|
639
639
|
`- **调用工具**:\`${req.toolName}\``,
|
|
640
640
|
...(req.reason ? [`- **申请原因**:${req.reason}`] : []),
|
|
641
641
|
`- **等待超时**:${timeoutMin} 分钟内未回复将自动拒绝`,
|
|
642
642
|
'',
|
|
643
|
-
`> 回复 \`/yes
|
|
644
|
-
`> 回复 \`/no
|
|
643
|
+
`> 回复 \`/yes\` (或 \`1\`) 批准执行`,
|
|
644
|
+
`> 回复 \`/no\` (或 \`2\`) 拒绝执行`,
|
|
645
645
|
].join('\n')
|
|
646
646
|
|
|
647
647
|
void this.sendText(prompt)
|
|
@@ -824,14 +824,14 @@ async function routeCommand(node, text) {
|
|
|
824
824
|
case 'workspaces': {
|
|
825
825
|
const workspaces = await listWorkspaces(node)
|
|
826
826
|
if (workspaces.length === 0) {
|
|
827
|
-
await node.sendText(
|
|
827
|
+
await node.sendText(`## 🗂️ 可用工作区\n\n> 当前没有已注册的工作区。可使用 \`/new <提示词> @<路径>\` 指定项目目录。`)
|
|
828
828
|
return true
|
|
829
829
|
}
|
|
830
830
|
const lines = workspaces.map((w, i) => {
|
|
831
831
|
const titleStr = w.title && w.title !== w.path ? `**${w.title}**` : `**${getWorkspaceBasename(w.path)}**`
|
|
832
832
|
return `- **[${i + 1}]** ${titleStr}\n \`${w.path}\``
|
|
833
833
|
})
|
|
834
|
-
await node.sendText(
|
|
834
|
+
await node.sendText(`## 🗂️ 可用工作区 (共 ${workspaces.length} 个)\n\n> 新建会话:发送 \`/new <提示词> @序号\`\n\n${lines.join('\n')}`)
|
|
835
835
|
return true
|
|
836
836
|
}
|
|
837
837
|
case 'new': {
|
|
@@ -888,7 +888,7 @@ async function routeCommand(node, text) {
|
|
|
888
888
|
const agent = node.activeAgent()
|
|
889
889
|
const session = node.activeSession()
|
|
890
890
|
if (!session) {
|
|
891
|
-
await node.sendText(
|
|
891
|
+
await node.sendText(`## 📊 Agent 状态看板\n\n> 当前没有活动会话。\n> 发送 \`/new <提示词>\` 开始新任务,或发送 \`/sessions\` 查看已有会话。`)
|
|
892
892
|
return true
|
|
893
893
|
}
|
|
894
894
|
const statusMap = {
|
|
@@ -904,7 +904,7 @@ async function routeCommand(node, text) {
|
|
|
904
904
|
const titleLine = title ? `\n- **会话标题**:${title}` : ''
|
|
905
905
|
const cwdLine = session.header?.cwd ? `\n- **工作区**:\`${session.header.cwd}\`` : ''
|
|
906
906
|
|
|
907
|
-
await node.sendText(
|
|
907
|
+
await node.sendText(`## 📊 Agent 状态看板\n\n- **会话 ID**:\`${session.id}\`${titleLine}${cwdLine}\n- **Agent 状态**:${status}\n- **累计事件**:${session.seq ?? 0} 条\n- **最近执行**:${reason}`)
|
|
908
908
|
return true
|
|
909
909
|
}
|
|
910
910
|
case 'start': // 别名:首次扫码自动开始一个会话
|
|
@@ -931,7 +931,7 @@ function describeTurnEnd(reason) {
|
|
|
931
931
|
async function renderSessions(node) {
|
|
932
932
|
const all = await listSessions(node)
|
|
933
933
|
if (all.length === 0) {
|
|
934
|
-
return
|
|
934
|
+
return `## 📋 会话列表\n\n> 暂无历史会话。发送 \`/new <提示词>\` 开始新会话。`
|
|
935
935
|
}
|
|
936
936
|
// 按工作区(真实 cwd)分组;无 cwd 的归入 '(未指定)'
|
|
937
937
|
const groups = new Map()
|
|
@@ -942,7 +942,7 @@ async function renderSessions(node) {
|
|
|
942
942
|
}
|
|
943
943
|
const sortedGroups = [...groups.entries()].sort((a, b) => String(a[0]).localeCompare(String(b[0])))
|
|
944
944
|
const parts = [
|
|
945
|
-
|
|
945
|
+
`## 📋 会话列表 (共 ${all.length} 个)`,
|
|
946
946
|
`> 切换会话:发送 \`/use 编号\` 或 \`/resume 编号\``,
|
|
947
947
|
'',
|
|
948
948
|
]
|
|
@@ -951,6 +951,7 @@ async function renderSessions(node) {
|
|
|
951
951
|
const groupName = cwd === '(未指定)' ? '📁 未指定工作区' : `📁 **${getWorkspaceBasename(cwd)}**`
|
|
952
952
|
const pathDetail = cwd === '(未指定)' ? '' : ` \`${cwd}\``
|
|
953
953
|
parts.push(`${groupName}${pathDetail}`)
|
|
954
|
+
parts.push('') // 空行:QQ 规定列表前必须空行
|
|
954
955
|
for (const session of sessions.slice(0, 20)) {
|
|
955
956
|
idx += 1
|
|
956
957
|
const isActive = session.id === node.activeSessionId
|
|
@@ -1006,9 +1007,10 @@ function fmtSessionId(id) {
|
|
|
1006
1007
|
|
|
1007
1008
|
function helpText() {
|
|
1008
1009
|
return [
|
|
1009
|
-
'
|
|
1010
|
+
'## 🤖 常用指令帮助',
|
|
1010
1011
|
'',
|
|
1011
1012
|
'**💬 会话控制**',
|
|
1013
|
+
'',
|
|
1012
1014
|
'- `/sessions` (或 `/list`) — 查看所有会话列表',
|
|
1013
1015
|
'- `/use <编号>` (或 `/resume <编号>`) — 切换到指定编号会话',
|
|
1014
1016
|
'- `/new <提示词>` — 在当前工作区创建新会话并开始',
|
|
@@ -1018,11 +1020,13 @@ function helpText() {
|
|
|
1018
1020
|
'- `/stop` — 中断停止当前正在执行的任务',
|
|
1019
1021
|
'',
|
|
1020
1022
|
'**📁 环境与状态**',
|
|
1023
|
+
'',
|
|
1021
1024
|
'- `/workspaces` — 查看已注册的工作区列表',
|
|
1022
1025
|
'- `/status` — 查看 Agent 运行状态与事件摘要',
|
|
1023
1026
|
'- `/help` — 查看此帮助菜单',
|
|
1024
1027
|
'',
|
|
1025
1028
|
'**🔐 权限确认**',
|
|
1029
|
+
'',
|
|
1026
1030
|
'- `/yes` (或 `1`) — 批准当前工具执行请求',
|
|
1027
1031
|
'- `/no` (或 `2`) — 拒绝当前工具执行请求',
|
|
1028
1032
|
].join('\n')
|
package/lib/qq/node.js
CHANGED
|
@@ -17,6 +17,8 @@ const STREAM_CHUNK_SIZE = 400
|
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* 将文本转成 QQ 安全 Markdown:
|
|
20
|
+
* - 标题降级:QQ 仅标准支持 # 与 ##,超出(###、####)降级为 ## 或加粗
|
|
21
|
+
* - 列表前空行:QQ 规定列表前若为普通文本必须有空行隔开,自动补齐空行
|
|
20
22
|
* - 表格(| a | b | / |---|)降级为纯文本(QQ Markdown 不支持表格,会截断/报错)
|
|
21
23
|
* - markdown 图片语法  转为链接 [alt](url)(避免图片转存失败导致整条失败)
|
|
22
24
|
* - 代码块内容原样保留
|
|
@@ -29,14 +31,19 @@ function sanitizeQQMarkdown(text) {
|
|
|
29
31
|
let inTable = false
|
|
30
32
|
const isSep = (l) => /^\s*\|?\s*:?-{2,}:?\s*(\|\s*:?-{2,}:?\s*)*\|?\s*$/.test(l) && l.includes('-')
|
|
31
33
|
const isTableRow = (l) => /^\s*\|.*\|\s*$/.test(l)
|
|
34
|
+
const isListLine = (l) => /^\s*(-|\*|\d+\.)\s+/.test(l)
|
|
35
|
+
const isHeading = (l) => /^\s*#{1,6}\s+/.test(l)
|
|
36
|
+
|
|
32
37
|
for (let i = 0; i < lines.length; i++) {
|
|
33
|
-
|
|
38
|
+
let line = lines[i]
|
|
34
39
|
if (/^\s*```/.test(line)) {
|
|
35
40
|
inFence = !inFence
|
|
36
41
|
out.push(line)
|
|
37
42
|
continue
|
|
38
43
|
}
|
|
39
44
|
if (inFence) { out.push(line); continue }
|
|
45
|
+
|
|
46
|
+
// 表格处理
|
|
40
47
|
const nextIsSep = i + 1 < lines.length && isSep(lines[i + 1])
|
|
41
48
|
if (isTableRow(line) && (inTable || nextIsSep)) {
|
|
42
49
|
inTable = true
|
|
@@ -47,7 +54,24 @@ function sanitizeQQMarkdown(text) {
|
|
|
47
54
|
continue
|
|
48
55
|
}
|
|
49
56
|
inTable = false
|
|
50
|
-
|
|
57
|
+
|
|
58
|
+
// 标题级别规范化:QQ 标准支持 # 和 ##,超出(###+)统一转为 ##
|
|
59
|
+
if (isHeading(line)) {
|
|
60
|
+
line = line.replace(/^\s*#{3,}\s+/, '## ')
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 图片语法转为链接
|
|
64
|
+
line = line.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '[$1]($2)')
|
|
65
|
+
|
|
66
|
+
// 列表前空行保障:若前一行是非空普通文本且不是标题/列表/引用,则插入空行保证 QQ 正确解析列表
|
|
67
|
+
if (isListLine(line) && out.length > 0) {
|
|
68
|
+
const prev = out[out.length - 1]
|
|
69
|
+
if (prev && prev.trim() && !isListLine(prev) && !isHeading(prev) && !prev.startsWith('>')) {
|
|
70
|
+
out.push('')
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
out.push(line)
|
|
51
75
|
}
|
|
52
76
|
return out.join('\n')
|
|
53
77
|
}
|
package/package.json
CHANGED