@mhfire/dsh-im-bridge 0.1.3 → 0.2.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.
- package/README.en.md +114 -82
- package/README.md +114 -82
- package/cordis.patch.yml +83 -47
- package/lib/client.js +789 -153
- package/lib/client.js.map +1 -0
- package/lib/index.js +570 -0
- package/package.json +76 -43
- package/persona.default.en.md +22 -0
- package/persona.default.md +22 -0
- package/src/client/PluginCard.module.css +153 -0
- package/src/client/PluginCard.tsx +83 -0
- package/src/client/WecomCard.tsx +135 -0
- package/src/client/card-controller.ts +146 -0
- package/src/client/card-form.ts +293 -0
- package/src/client/css-modules.d.ts +4 -0
- package/src/client/fields.module.css +124 -0
- package/src/client/fields.tsx +112 -0
- package/src/client/index.ts +37 -0
- package/src/client/locales.ts +112 -0
- package/src/index.ts +542 -0
- package/src/wecom.ts +234 -0
- package/tsconfig.json +14 -0
- package/tsdown.client.ts +109 -0
- package/tsdown.host.ts +36 -0
- package/src/index.js +0 -272
- package/src/wecom.js +0 -111
package/src/wecom.js
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* wecom.js — 企业微信交互封装: 流式动画(v3) + 最终简报 + 发送助手。
|
|
3
|
-
* 逻辑移植自旧版 im-bridge/bridge.js, 改为纯 ESM 供插件使用。
|
|
4
|
-
*/
|
|
5
|
-
import { generateReqId } from '@wecom/aibot-node-sdk'
|
|
6
|
-
|
|
7
|
-
/** 流式思考动画的默认素材(可被 Config.thinking / cordis patch 覆盖) */
|
|
8
|
-
export const DEFAULT_THINKING = {
|
|
9
|
-
phases: [
|
|
10
|
-
{ atSec: 0, text: '🤔 正在理解你的需求…' },
|
|
11
|
-
{ atSec: 8, text: '📋 正在整理任务清单' },
|
|
12
|
-
{ atSec: 25, text: '🔍 正在查找相关资料' },
|
|
13
|
-
{ atSec: 55, text: '✍️ 正在处理文档/数据' },
|
|
14
|
-
{ atSec: 120, text: '🧠 正在思考最佳方案…' },
|
|
15
|
-
{ atSec: 240, text: '⏳ 任务较繁琐,请稍候…' },
|
|
16
|
-
{ atSec: 420, text: '☕ 快好了,正在收尾…' },
|
|
17
|
-
],
|
|
18
|
-
spin: ['🧠', '💭', '✨', '🔎', '⚡'],
|
|
19
|
-
eggs: [
|
|
20
|
-
'📎 顺手把要点整理好了,稍后一起给你',
|
|
21
|
-
'📶 网络有点忙,让它慢慢跑',
|
|
22
|
-
'🎯 结果快出来了,坚持一下',
|
|
23
|
-
'🗂️ 资料较多,正在汇总中',
|
|
24
|
-
'🌙 别盯着了,完成会自动通知你',
|
|
25
|
-
],
|
|
26
|
-
eggAfterSec: 240,
|
|
27
|
-
intervalMs: 1500,
|
|
28
|
-
activityPrefix: '🛠️ 正在执行 ',
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** 毫秒 → 人类可读时长(如 "9 分 47 秒") */
|
|
32
|
-
export function fmtDuration(ms) {
|
|
33
|
-
const s = Math.floor(ms / 1000)
|
|
34
|
-
if (s < 60) return `${s} 秒`
|
|
35
|
-
const m = Math.floor(s / 60)
|
|
36
|
-
const r = s % 60
|
|
37
|
-
return r > 0 ? `${m} 分 ${r} 秒` : `${m} 分钟`
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** 按耗时给个速度评价 */
|
|
41
|
-
export function speedOf(ms) {
|
|
42
|
-
if (ms < 60000) return '⚡ 神速'
|
|
43
|
-
if (ms < 180000) return '🚀 正常速度'
|
|
44
|
-
return '🐢 耗时较长'
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** 执行完成的尾部简报 */
|
|
48
|
-
export function footerOf(ms) {
|
|
49
|
-
if (ms >= 180000) {
|
|
50
|
-
return `\n\n---\n✅ 执行完成 · 🐢 耗时较长(${fmtDuration(ms)})\n💡 如需提速,可让我把诊断步骤合并成更少的 SSH 批次`
|
|
51
|
-
}
|
|
52
|
-
return `\n\n---\n✅ 执行完成 · ${speedOf(ms)}(${fmtDuration(ms)})`
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/** 截断(按字节) */
|
|
56
|
-
export function truncate(text, max) {
|
|
57
|
-
if (Buffer.byteLength(text, 'utf8') <= max) return text
|
|
58
|
-
let t = text
|
|
59
|
-
while (Buffer.byteLength(t, 'utf8') > max) t = t.slice(0, -100)
|
|
60
|
-
return t + '\n\n...(内容过长已截断)'
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* 流式动画 v3: 阶段化台词 + 旋转表情 + 进度条 + 已用时/剩余估算 + 长任务彩蛋。
|
|
65
|
-
* 每 intervalMs 更新一次同一条流式消息(共用 streamId), 直到 agent 完成。返回停止函数。
|
|
66
|
-
* @param {() => string} [activity] - 可选: 返回当前真实活动描述, 覆盖阶段台词。
|
|
67
|
-
* @param {typeof DEFAULT_THINKING} [thinking] - 动画素材; 缺省用 {@link DEFAULT_THINKING}。
|
|
68
|
-
*/
|
|
69
|
-
export function startThinking(ws, frame, streamId, startedAt, timeoutSec, activity, thinking) {
|
|
70
|
-
const t = { ...DEFAULT_THINKING, ...(thinking || {}) }
|
|
71
|
-
const phases = Array.isArray(t.phases) && t.phases.length > 0 ? t.phases : DEFAULT_THINKING.phases
|
|
72
|
-
const spin = Array.isArray(t.spin) && t.spin.length > 0 ? t.spin : DEFAULT_THINKING.spin
|
|
73
|
-
const eggs = Array.isArray(t.eggs) && t.eggs.length > 0 ? t.eggs : DEFAULT_THINKING.eggs
|
|
74
|
-
const eggAfterSec = Number.isFinite(t.eggAfterSec) ? t.eggAfterSec : DEFAULT_THINKING.eggAfterSec
|
|
75
|
-
const intervalMs = Number.isFinite(t.intervalMs) && t.intervalMs > 0 ? t.intervalMs : DEFAULT_THINKING.intervalMs
|
|
76
|
-
const total = Number.isFinite(timeoutSec) && timeoutSec > 0 ? timeoutSec : 600
|
|
77
|
-
let i = 0
|
|
78
|
-
const timer = setInterval(() => {
|
|
79
|
-
const secs = Math.floor((Date.now() - startedAt) / 1000)
|
|
80
|
-
const live = activity ? activity() : ''
|
|
81
|
-
let stage = phases[0].text
|
|
82
|
-
if (!live) {
|
|
83
|
-
for (const p of phases) {
|
|
84
|
-
if (secs >= p.atSec) stage = p.text
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
const pct = Math.min(Math.floor((secs / total) * 100), 99)
|
|
88
|
-
const filled = '█'.repeat(Math.floor(pct / 10))
|
|
89
|
-
const bar = secs < 3 ? '' : `\n${filled}${'░'.repeat(10 - filled.length)} ${String(pct).padStart(2)}%`
|
|
90
|
-
const remain = Math.max(total - secs, 0)
|
|
91
|
-
const remainTxt = secs < 3 ? '' : ` · 预计还剩 ${Math.floor(remain / 60)}分${remain % 60}秒`
|
|
92
|
-
const egg = secs >= eggAfterSec && eggs.length > 0
|
|
93
|
-
? `\n${eggs[Math.floor(secs / 60) % eggs.length]}`
|
|
94
|
-
: ''
|
|
95
|
-
const emoji = spin[i % spin.length]
|
|
96
|
-
i++
|
|
97
|
-
const status = live || stage
|
|
98
|
-
ws.replyStream(frame, streamId, `${emoji} ${status} ⏱ ${secs} 秒${remainTxt}${bar}${egg}`, false).catch(() => {})
|
|
99
|
-
}, intervalMs)
|
|
100
|
-
return () => clearInterval(timer)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/** 最终回复: 原流失败(如 WeCom 10 分钟过期)时用新流重试一次 */
|
|
104
|
-
export async function sendFinal(ws, frame, streamId, content) {
|
|
105
|
-
try {
|
|
106
|
-
await ws.replyStream(frame, streamId, content, true)
|
|
107
|
-
} catch (e) {
|
|
108
|
-
console.error(`[im-bridge] 原流最终回复失败(${e.message}), 尝试新流...`)
|
|
109
|
-
await ws.replyStream(frame, generateReqId('stream'), content, true)
|
|
110
|
-
}
|
|
111
|
-
}
|