@zaofan/dsh-qqbot 1.1.4 → 1.1.5
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.md +17 -8
- package/README_EN.md +13 -7
- package/dist/commands/session.d.ts +3 -1
- package/dist/commands/session.d.ts.map +1 -1
- package/dist/commands/session.js +24 -8
- package/dist/commands/session.js.map +1 -1
- package/dist/config.js +1 -1
- package/dist/features/botplay.d.ts +1 -1
- package/dist/features/botplay.d.ts.map +1 -1
- package/dist/features/group-hub.js +1 -1
- package/dist/features/group-hub.js.map +1 -1
- package/dist/features/outbound-mode-switch.js +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/model/settings-reader.d.ts +6 -0
- package/dist/model/settings-reader.d.ts.map +1 -1
- package/dist/model/settings-reader.js +15 -2
- package/dist/model/settings-reader.js.map +1 -1
- package/dist/session/session-manager.d.ts +32 -7
- package/dist/session/session-manager.d.ts.map +1 -1
- package/dist/session/session-manager.js +150 -55
- package/dist/session/session-manager.js.map +1 -1
- package/dist/session/workspace-attach.d.ts +17 -18
- package/dist/session/workspace-attach.d.ts.map +1 -1
- package/dist/session/workspace-attach.js +162 -13
- package/dist/session/workspace-attach.js.map +1 -1
- package/dist/setup.d.ts +1 -1
- package/dist/setup.js +1 -1
- package/package.json +1 -1
- package/settings-host.js +7 -1
|
@@ -1,21 +1,170 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* workspace-attach.ts — 把 QQ 会话挂到其 cwd 对应的工作区分组 + 「会话被触发时」把它从归档里拉回可见
|
|
3
|
+
*
|
|
4
|
+
* ── 第一件事: 工作区归属(移植自上游 PR tencent-connect/dsh-qqbot#21) ──
|
|
5
|
+
* 问题: Web 侧边栏按工作区成员列表展示会话, 宿主只在客户端 session.create
|
|
6
|
+
* RPC 路径调用 workspace.attachSession(dsh-host-apiproxy), dsh-workspace 的
|
|
7
|
+
* "认领遗漏会话"(bootstrap) 仅在首次初始化执行——插件创建的 QQ 会话两条路径
|
|
8
|
+
* 都不经过 → 不在任何工作区成员列表, 刷新后只能落 Ungrouped(且闲置回收后
|
|
9
|
+
* 从侧边栏消失的另一主因是宿主帧语义, 见 deepseek-harness#4045, 本文件不处理)。
|
|
10
|
+
* 做法: 在 SessionManager.getOrCreate 创建/恢复会话后调用, 把会话挂到其 cwd
|
|
11
|
+
* 对应的 workspace(registry.create(cwd) 幂等取回 → workspace.attachSession 幂等)。
|
|
12
|
+
*
|
|
13
|
+
* ── 第二件事: 触发式反归档(2026-09-11 主人定稿) ──
|
|
14
|
+
* 侧边栏可见性是**两层**独立机制:
|
|
15
|
+
* ① 工作区归属(sessionIds) — attachSession 管;
|
|
16
|
+
* ② 全局归档集合(registry.archivedSessionIds) — 宿主 UI 的「归档会话」写它,
|
|
17
|
+
* 侧边栏的分组/扁平/搜索三处推导全都 `!archived.has(id)` 过滤。
|
|
18
|
+
* 两层互不影响: 归档的会话哪怕已经挂进工作区也**照样不显示**; 而宿主
|
|
19
|
+
* (dsh-api-workspace-controller)只暴露了 `archiveSession`, **没有任何
|
|
20
|
+
* unarchive / restore 接口**(registry 类里同样只有 archiveSession), 于是
|
|
21
|
+
* "点了归档就再也拉不回来"。本文件自己补上这一环。
|
|
22
|
+
*
|
|
23
|
+
* 语义(主人 2026-09-11 明确纠正):
|
|
24
|
+
* **不是"归档动作秒级弹回", 而是"会话被触发时弹回"。**
|
|
25
|
+
* · 主人主动归档 → 保持归档状态。**不拦截归档动作、也不跑定时巡检**——
|
|
26
|
+
* 那两样(半成品初版曾实现)会让「归档」功能形同虚设, 已按主人要求移除;
|
|
27
|
+
* · 该 QQ 会话下次被消息**触发**时, 顺带把它的 id 从归档集合里摘掉 →
|
|
28
|
+
* 侧边栏恢复可见(走宿主同一条持久化链, 热刷新, 无需重启宿主)。
|
|
29
|
+
* 落点两处(SessionManager 侧):
|
|
30
|
+
* ① getOrCreate 命中**已有活跃记录** → unarchiveSession();
|
|
31
|
+
* ② 新建/恢复会话 → attachSessionToWorkspace()(内部顺带 unarchive)。
|
|
32
|
+
*
|
|
33
|
+
* ⚠️ 风险与边界(宿主升级时重点回归):
|
|
34
|
+
* - setState / enqueueOperation / state / global 是 workspaceRegistry 的**内部成员**,
|
|
35
|
+
* 宿主没有对外公开 unarchive 能力, 便桥只能这么搭。这里全部 duck-typing +
|
|
36
|
+
* fail-soft: 缺哪个就用能用的那条(全取不到就只记日志, 绝不抛)。
|
|
37
|
+
* - 只对**被 QQ 消息触发**的会话生效, 主人手动归档的其它会话不受影响。
|
|
38
|
+
* - 全 fail-soft: workspaceRegistry 未挂载(如 headless)或任何一步失败 →
|
|
39
|
+
* 静默降级(仅日志), 绝不影响消息处理主链。
|
|
40
|
+
*
|
|
41
|
+
* ⚠️ 本地手改功能(fork 新增): 维护清单见工作区根《dsh-qqbot-开发维护手册.md》。
|
|
42
|
+
*/
|
|
43
|
+
import { appendFileSync } from 'node:fs';
|
|
44
|
+
import { homedir } from 'node:os';
|
|
45
|
+
import { join } from 'node:path';
|
|
46
|
+
const REGISTRY_SERVICE = 'workspaceRegistry';
|
|
47
|
+
/** 反归档诊断(离线可查: 写 ~/.dsh/qqbot-archive.log) */
|
|
48
|
+
const DIAG_FILE = join(homedir(), '.dsh', 'qqbot-archive.log');
|
|
49
|
+
function diag(line) {
|
|
4
50
|
try {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
51
|
+
appendFileSync(DIAG_FILE, `${new Date().toISOString()} ${line}\n`, 'utf8');
|
|
52
|
+
}
|
|
53
|
+
catch { /* 诊断写失败忽略 */ }
|
|
54
|
+
}
|
|
55
|
+
/** 反归档统计(供 /api/qqbot-settings/_debug 与排障查看) */
|
|
56
|
+
const stats = { unarchived: 0, lastUnarchivedId: '', lastUnarchivedAt: 0, lastError: '' };
|
|
57
|
+
/** 取 workspaceRegistry(未挂载时 undefined; 全程 fail-soft) */
|
|
58
|
+
function getRegistry(ctx) {
|
|
59
|
+
try {
|
|
60
|
+
return ctx.get?.(REGISTRY_SERVICE);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
67
|
+
// 反归档
|
|
68
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
69
|
+
/** 读当前归档集合(getter 优先, 回落 state 字段) */
|
|
70
|
+
function readArchived(registry) {
|
|
71
|
+
const direct = registry.archivedSessionIds;
|
|
72
|
+
if (Array.isArray(direct))
|
|
73
|
+
return direct.map(String);
|
|
74
|
+
const raw = registry.state?.archivedSessionIds;
|
|
75
|
+
return Array.isArray(raw) ? raw.map(String) : [];
|
|
76
|
+
}
|
|
77
|
+
/** 真正把 id 从归档集合里摘掉(串行 + 持久化) */
|
|
78
|
+
async function removeFromArchived(registry, sessionId) {
|
|
79
|
+
const write = async () => {
|
|
80
|
+
const archived = readArchived(registry);
|
|
81
|
+
if (!archived.includes(sessionId))
|
|
82
|
+
return false;
|
|
83
|
+
const state = registry.state;
|
|
84
|
+
if (state === undefined)
|
|
85
|
+
return false;
|
|
86
|
+
const next = { ...state, archivedSessionIds: archived.filter(id => id !== sessionId) };
|
|
87
|
+
if (typeof registry.setState === 'function') {
|
|
88
|
+
// 正常路径: 宿主 setState = 落盘 + 更新内存(会触发 controller 推 follow 'archived' 帧)
|
|
89
|
+
await registry.setState(next);
|
|
90
|
+
return true;
|
|
9
91
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
92
|
+
// 兜底: 直接写 domain global, 并同步内存 state(否则下一次 requireState 会把旧集合写回去)
|
|
93
|
+
const global = registry.global;
|
|
94
|
+
if (typeof global?.set !== 'function')
|
|
95
|
+
return false;
|
|
96
|
+
await global.set(next);
|
|
97
|
+
registry.state = next;
|
|
98
|
+
return true;
|
|
99
|
+
};
|
|
100
|
+
return typeof registry.enqueueOperation === 'function'
|
|
101
|
+
? await registry.enqueueOperation(write)
|
|
102
|
+
: await write();
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 把一个会话从「归档」里拉回可见(幂等; 不在归档集合里就是 no-op)。
|
|
106
|
+
* 走宿主同一条持久化链 → 侧边栏热刷新, 不需要重启宿主。
|
|
107
|
+
* @returns true = 本次真的摘掉了(之前处于归档)
|
|
108
|
+
*/
|
|
109
|
+
export async function unarchiveSession(ctx, sessionId, logger) {
|
|
110
|
+
try {
|
|
111
|
+
const registry = getRegistry(ctx);
|
|
112
|
+
if (!registry) {
|
|
113
|
+
stats.lastError = 'no-workspaceRegistry';
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
const id = String(sessionId);
|
|
117
|
+
const removed = await removeFromArchived(registry, id);
|
|
118
|
+
if (removed) {
|
|
119
|
+
stats.unarchived += 1;
|
|
120
|
+
stats.lastUnarchivedId = id;
|
|
121
|
+
stats.lastUnarchivedAt = Date.now();
|
|
122
|
+
stats.lastError = '';
|
|
123
|
+
logger.info(`[workspace-attach] session ${id} 已从「归档」拉回可见(触发式反归档)`);
|
|
124
|
+
diag(`unarchived ${id}`);
|
|
14
125
|
}
|
|
126
|
+
return removed;
|
|
15
127
|
}
|
|
16
128
|
catch (err) {
|
|
17
|
-
// fail-soft:
|
|
18
|
-
|
|
129
|
+
// fail-soft: 反归档失败绝不影响会话使用
|
|
130
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
131
|
+
stats.lastError = msg;
|
|
132
|
+
logger.warn?.(`[workspace-attach] unarchive skipped: ${msg}`);
|
|
133
|
+
diag(`unarchive-failed ${sessionId}: ${msg}`);
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** 供诊断: 反归档统计(有多少次真的把会话从归档里拉回可见) */
|
|
138
|
+
export function workspaceAttachState() {
|
|
139
|
+
return { ...stats };
|
|
140
|
+
}
|
|
141
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
142
|
+
// 对外主入口
|
|
143
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
144
|
+
/**
|
|
145
|
+
* 会话可用性总入口: 挂到工作区 + 保证不在归档里(两者都幂等 + fail-soft)。
|
|
146
|
+
* SessionManager.getOrCreate **创建/恢复**会话后调用, fire-and-forget 不阻塞主链。
|
|
147
|
+
*/
|
|
148
|
+
export async function attachSessionToWorkspace(ctx, cwd, sessionId, logger) {
|
|
149
|
+
const registry = getRegistry(ctx);
|
|
150
|
+
if (!registry)
|
|
151
|
+
return; // workspaceRegistry 未挂载(如 headless profile) → 静默跳过
|
|
152
|
+
if (cwd) {
|
|
153
|
+
try {
|
|
154
|
+
if (typeof registry.create === 'function') {
|
|
155
|
+
const workspace = await registry.create(cwd);
|
|
156
|
+
if (workspace?.attachSession) {
|
|
157
|
+
await workspace.attachSession(sessionId);
|
|
158
|
+
logger.info(`[workspace-attach] session ${sessionId} → workspace ${cwd}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
// fail-soft: 挂载失败绝不影响会话使用; 留 warn 便于主人查(无 workspaceRegistry 时宿主会抛)
|
|
164
|
+
logger.warn?.(`[workspace-attach] skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
165
|
+
}
|
|
19
166
|
}
|
|
167
|
+
// 顺带把误归档的会话拉回可见(归档与工作区归属无关, 故不依赖 cwd)
|
|
168
|
+
await unarchiveSession(ctx, sessionId, logger);
|
|
20
169
|
}
|
|
21
170
|
//# sourceMappingURL=workspace-attach.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-attach.js","sourceRoot":"","sources":["../../src/session/workspace-attach.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"workspace-attach.js","sourceRoot":"","sources":["../../src/session/workspace-attach.ts"],"names":[],"mappings":"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"}
|
package/dist/setup.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export declare function runQrSetup(source?: string): Promise<SetupCredentials |
|
|
|
19
19
|
* 文件其它内容(含 !!js、其它实例、insert 包装)原样保留。
|
|
20
20
|
*
|
|
21
21
|
* ⚠️ 2026-09-10 修复两处线上事故:
|
|
22
|
-
* 1. 旧实现把条目名硬编码成 `im-qqbot`, 对
|
|
22
|
+
* 1. 旧实现把条目名硬编码成 `im-qqbot`, 对 某实例 这类实例找不到块 →
|
|
23
23
|
* 在文件末尾追加了一个顶层 `- id: im-qqbot`(新版 dsh 无此 entry, 会让整棵插件树加载失败);
|
|
24
24
|
* 现按 instEntryId(来自 config.settingsNs)定位, 且**绝不新建顶层 entry id**。
|
|
25
25
|
* 2. appId 必须写为**带引号的字符串** —— 新版 cordis 严格校验 `$.appId expected string`,
|
package/dist/setup.js
CHANGED
|
@@ -76,7 +76,7 @@ export async function runQrSetup(source = 'dsh-qqbot') {
|
|
|
76
76
|
* 文件其它内容(含 !!js、其它实例、insert 包装)原样保留。
|
|
77
77
|
*
|
|
78
78
|
* ⚠️ 2026-09-10 修复两处线上事故:
|
|
79
|
-
* 1. 旧实现把条目名硬编码成 `im-qqbot`, 对
|
|
79
|
+
* 1. 旧实现把条目名硬编码成 `im-qqbot`, 对 某实例 这类实例找不到块 →
|
|
80
80
|
* 在文件末尾追加了一个顶层 `- id: im-qqbot`(新版 dsh 无此 entry, 会让整棵插件树加载失败);
|
|
81
81
|
* 现按 instEntryId(来自 config.settingsNs)定位, 且**绝不新建顶层 entry id**。
|
|
82
82
|
* 2. appId 必须写为**带引号的字符串** —— 新版 cordis 严格校验 `$.appId expected string`,
|
package/package.json
CHANGED
package/settings-host.js
CHANGED
|
@@ -153,7 +153,13 @@ export function apply(ctx) {
|
|
|
153
153
|
const all = ctx.settings.describe({});
|
|
154
154
|
nss = (Array.isArray(all) ? all : []).map((x) => x.ns);
|
|
155
155
|
} catch (e) { describeErr = String(e?.message ?? e); }
|
|
156
|
-
|
|
156
|
+
// 触发式反归档诊断(2026-09-11): 有多少次真的把归档的 QQ 会话拉回可见(见 dist/session/workspace-attach.js)
|
|
157
|
+
let workspaceAttach = null;
|
|
158
|
+
try {
|
|
159
|
+
const wa = await import('./dist/session/workspace-attach.js');
|
|
160
|
+
workspaceAttach = typeof wa.workspaceAttachState === 'function' ? wa.workspaceAttachState() : null;
|
|
161
|
+
} catch { /* 模块未部署时忽略 */ }
|
|
162
|
+
writeJson(res, 200, { hasSettings, nss, describeErr, workspaceAttach });
|
|
157
163
|
} catch (e) { writeJson(res, 500, { error: String(e?.message ?? e) }); }
|
|
158
164
|
});
|
|
159
165
|
|