@xgjktech/xg_cwork_im 1.17.50 → 1.17.51
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/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/src/account-connection.d.ts.map +1 -1
- package/dist/src/account-connection.js +2 -0
- package/dist/src/account-connection.js.map +1 -1
- package/dist/src/account-reconciler.d.ts.map +1 -1
- package/dist/src/account-reconciler.js +2 -0
- package/dist/src/account-reconciler.js.map +1 -1
- package/dist/src/deliver-text.test.js +22 -22
- package/dist/src/gateway-session-queue.d.ts +2 -11
- package/dist/src/gateway-session-queue.d.ts.map +1 -1
- package/dist/src/gateway-session-queue.js +6 -9
- package/dist/src/gateway-session-queue.js.map +1 -1
- package/dist/src/plan-session-registry.d.ts +24 -0
- package/dist/src/plan-session-registry.d.ts.map +1 -0
- package/dist/src/plan-session-registry.js +84 -0
- package/dist/src/plan-session-registry.js.map +1 -0
- package/dist/src/plan-session-registry.test.d.ts +2 -0
- package/dist/src/plan-session-registry.test.d.ts.map +1 -0
- package/dist/src/plan-session-registry.test.js +109 -0
- package/dist/src/plan-session-registry.test.js.map +1 -0
- package/dist/src/plan-store-access.test.js +9 -9
- package/dist/src/plan-ws-registry.d.ts +2 -0
- package/dist/src/plan-ws-registry.d.ts.map +1 -1
- package/dist/src/plan-ws-registry.js +8 -0
- package/dist/src/plan-ws-registry.js.map +1 -1
- package/dist/src/plan-ws-registry.test.js +19 -1
- package/dist/src/plan-ws-registry.test.js.map +1 -1
- package/dist/src/plugin-dispose.d.ts +4 -2
- package/dist/src/plugin-dispose.d.ts.map +1 -1
- package/dist/src/plugin-dispose.js +10 -7
- package/dist/src/plugin-dispose.js.map +1 -1
- package/dist/src/turn-deliver-buffer.test.js +25 -25
- package/openclaw.plugin.json +30 -30
- package/package.json +78 -78
- package/dist/src/single-chat-no-reply-fallback.d.ts +0 -14
- package/dist/src/single-chat-no-reply-fallback.d.ts.map +0 -1
- package/dist/src/single-chat-no-reply-fallback.js +0 -20
- package/dist/src/single-chat-no-reply-fallback.js.map +0 -1
- package/dist/src/subagent-progress-hooks.d.ts +0 -11
- package/dist/src/subagent-progress-hooks.d.ts.map +0 -1
- package/dist/src/subagent-progress-hooks.js +0 -41
- package/dist/src/subagent-progress-hooks.js.map +0 -1
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { beforeEach, describe, it } from "node:test";
|
|
3
|
+
import { diffAndMarkBlockedNotices, registerToolCallTarget, resetPlanSessionRegistryForTest, setNowFnForTest, takeToolCallTarget, } from "./plan-session-registry.js";
|
|
4
|
+
function makeTarget(overrides = {}) {
|
|
5
|
+
return {
|
|
6
|
+
groupId: "group-1",
|
|
7
|
+
token: "token-1",
|
|
8
|
+
...overrides,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function makeNotice(overrides = {}) {
|
|
12
|
+
return {
|
|
13
|
+
key: "plan-1::0::缺少权限",
|
|
14
|
+
taskIndex: 0,
|
|
15
|
+
taskTitle: "备份旧配置",
|
|
16
|
+
note: "缺少权限",
|
|
17
|
+
content: "计划「X」卡在任务「备份旧配置」:缺少权限\n需要人工介入才能继续。",
|
|
18
|
+
...overrides,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
resetPlanSessionRegistryForTest();
|
|
23
|
+
});
|
|
24
|
+
describe("registerToolCallTarget / takeToolCallTarget", () => {
|
|
25
|
+
it("hits with the registered target and deletes it on consume (take twice → second undefined)", () => {
|
|
26
|
+
registerToolCallTarget("call-1", makeTarget());
|
|
27
|
+
const first = takeToolCallTarget("call-1");
|
|
28
|
+
assert.deepEqual(first, makeTarget());
|
|
29
|
+
const second = takeToolCallTarget("call-1");
|
|
30
|
+
assert.equal(second, undefined);
|
|
31
|
+
});
|
|
32
|
+
it("misses for an unregistered id", () => {
|
|
33
|
+
assert.equal(takeToolCallTarget("does-not-exist"), undefined);
|
|
34
|
+
});
|
|
35
|
+
it("expires entries past TTL (injected now, no sleep)", () => {
|
|
36
|
+
let t = 0;
|
|
37
|
+
setNowFnForTest(() => t);
|
|
38
|
+
registerToolCallTarget("call-ttl", makeTarget());
|
|
39
|
+
t = 10 * 60 * 1000 + 1; // TTL + 1ms
|
|
40
|
+
assert.equal(takeToolCallTarget("call-ttl"), undefined);
|
|
41
|
+
});
|
|
42
|
+
it("does not expire an entry read exactly at TTL boundary", () => {
|
|
43
|
+
let t = 0;
|
|
44
|
+
setNowFnForTest(() => t);
|
|
45
|
+
registerToolCallTarget("call-boundary", makeTarget());
|
|
46
|
+
t = 10 * 60 * 1000; // exactly TTL, not yet exceeded
|
|
47
|
+
assert.ok(takeToolCallTarget("call-boundary"));
|
|
48
|
+
});
|
|
49
|
+
it("evicts the oldest entry when capacity is exceeded", () => {
|
|
50
|
+
let t = 0;
|
|
51
|
+
setNowFnForTest(() => t);
|
|
52
|
+
for (let i = 0; i < 500; i++) {
|
|
53
|
+
t += 1;
|
|
54
|
+
registerToolCallTarget(`call-${i}`, makeTarget({ groupId: `g${i}` }));
|
|
55
|
+
}
|
|
56
|
+
// 表已满 500 条,call-0 是最旧的
|
|
57
|
+
t += 1;
|
|
58
|
+
registerToolCallTarget("call-500", makeTarget({ groupId: "g500" }));
|
|
59
|
+
assert.equal(takeToolCallTarget("call-0"), undefined, "oldest entry should have been evicted");
|
|
60
|
+
const kept = takeToolCallTarget("call-500");
|
|
61
|
+
assert.ok(kept);
|
|
62
|
+
assert.equal(kept.groupId, "g500");
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe("diffAndMarkBlockedNotices", () => {
|
|
66
|
+
it("returns all notices on first call", () => {
|
|
67
|
+
const notices = [makeNotice()];
|
|
68
|
+
const fresh = diffAndMarkBlockedNotices("plan-1", notices);
|
|
69
|
+
assert.deepEqual(fresh, notices);
|
|
70
|
+
});
|
|
71
|
+
it("returns empty on repeated identical call", () => {
|
|
72
|
+
const notices = [makeNotice()];
|
|
73
|
+
diffAndMarkBlockedNotices("plan-1", notices);
|
|
74
|
+
const second = diffAndMarkBlockedNotices("plan-1", notices);
|
|
75
|
+
assert.deepEqual(second, []);
|
|
76
|
+
});
|
|
77
|
+
it("treats a note change as a new notification (different key)", () => {
|
|
78
|
+
const first = [makeNotice({ key: "plan-1::0::缺少权限" })];
|
|
79
|
+
diffAndMarkBlockedNotices("plan-1", first);
|
|
80
|
+
const changed = [makeNotice({ key: "plan-1::0::权限问题已升级", note: "权限问题已升级" })];
|
|
81
|
+
const fresh = diffAndMarkBlockedNotices("plan-1", changed);
|
|
82
|
+
assert.deepEqual(fresh, changed);
|
|
83
|
+
});
|
|
84
|
+
it("clears a key once the task is no longer blocked, allowing re-notification later", () => {
|
|
85
|
+
const notice = makeNotice({ key: "plan-1::0::缺少权限" });
|
|
86
|
+
diffAndMarkBlockedNotices("plan-1", [notice]);
|
|
87
|
+
// task 修复:本次扫描不再含该 key
|
|
88
|
+
const clearedFresh = diffAndMarkBlockedNotices("plan-1", []);
|
|
89
|
+
assert.deepEqual(clearedFresh, []);
|
|
90
|
+
// 再次 blocked,同 key 应视为新增重新推送
|
|
91
|
+
const reblocked = diffAndMarkBlockedNotices("plan-1", [notice]);
|
|
92
|
+
assert.deepEqual(reblocked, [notice]);
|
|
93
|
+
});
|
|
94
|
+
it("keeps separate planIds independent", () => {
|
|
95
|
+
const noticeA = makeNotice({ key: "plan-a::0::原因A" });
|
|
96
|
+
const noticeB = makeNotice({ key: "plan-b::0::原因B" });
|
|
97
|
+
const freshA = diffAndMarkBlockedNotices("plan-a", [noticeA]);
|
|
98
|
+
const freshB = diffAndMarkBlockedNotices("plan-b", [noticeB]);
|
|
99
|
+
assert.deepEqual(freshA, [noticeA]);
|
|
100
|
+
assert.deepEqual(freshB, [noticeB]);
|
|
101
|
+
// plan-a 重复调用不应受 plan-b 影响,反之亦然
|
|
102
|
+
assert.deepEqual(diffAndMarkBlockedNotices("plan-a", [noticeA]), []);
|
|
103
|
+
assert.deepEqual(diffAndMarkBlockedNotices("plan-b", [noticeB]), []);
|
|
104
|
+
});
|
|
105
|
+
it("returns an empty array and does not throw when there are no notices", () => {
|
|
106
|
+
assert.deepEqual(diffAndMarkBlockedNotices("plan-empty", []), []);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
//# sourceMappingURL=plan-session-registry.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-session-registry.test.js","sourceRoot":"","sources":["../../src/plan-session-registry.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -140,14 +140,14 @@ describe("未设置 stateDir", () => {
|
|
|
140
140
|
/** 手工建一个 v1(无 origin 列)的 plans 表,模拟旧库升级前的真实状态(同 shared TASK-2x-1 手法)。 */
|
|
141
141
|
function createV1Schema(dbPath) {
|
|
142
142
|
const db = new DatabaseSync(dbPath);
|
|
143
|
-
db.exec(`
|
|
144
|
-
CREATE TABLE IF NOT EXISTS plans (
|
|
145
|
-
plan_id TEXT PRIMARY KEY,
|
|
146
|
-
goal TEXT NOT NULL,
|
|
147
|
-
created_at TEXT NOT NULL,
|
|
148
|
-
updated_at TEXT NOT NULL,
|
|
149
|
-
doc TEXT NOT NULL
|
|
150
|
-
) STRICT;
|
|
143
|
+
db.exec(`
|
|
144
|
+
CREATE TABLE IF NOT EXISTS plans (
|
|
145
|
+
plan_id TEXT PRIMARY KEY,
|
|
146
|
+
goal TEXT NOT NULL,
|
|
147
|
+
created_at TEXT NOT NULL,
|
|
148
|
+
updated_at TEXT NOT NULL,
|
|
149
|
+
doc TEXT NOT NULL
|
|
150
|
+
) STRICT;
|
|
151
151
|
`);
|
|
152
152
|
db.exec("CREATE INDEX IF NOT EXISTS idx_plans_updated_at ON plans(updated_at);");
|
|
153
153
|
db.exec("PRAGMA user_version = 1;");
|
|
@@ -155,7 +155,7 @@ function createV1Schema(dbPath) {
|
|
|
155
155
|
}
|
|
156
156
|
function insertV1Row(dbPath, plan) {
|
|
157
157
|
const db = new DatabaseSync(dbPath);
|
|
158
|
-
db.prepare(`INSERT INTO plans (plan_id, goal, created_at, updated_at, doc)
|
|
158
|
+
db.prepare(`INSERT INTO plans (plan_id, goal, created_at, updated_at, doc)
|
|
159
159
|
VALUES (@planId, @goal, @createdAt, @updatedAt, @doc)`).run({
|
|
160
160
|
planId: plan.planId,
|
|
161
161
|
goal: plan.goal,
|
|
@@ -6,6 +6,8 @@ export interface PlanWsTarget {
|
|
|
6
6
|
/** 按 groupId 覆盖登记(新一轮会话的 client 取代旧的)。 */
|
|
7
7
|
export declare function setPlanWsClient(groupId: string, client: ImStreamClient, replyToMsgId: string): void;
|
|
8
8
|
export declare function getPlanWsClient(groupId: string): PlanWsTarget | undefined;
|
|
9
|
+
/** 账号真正停止时,移除指向该物理 client 的全部群组路由;其他账号路由不受影响。 */
|
|
10
|
+
export declare function removePlanWsClientsByClient(client: ImStreamClient): void;
|
|
9
11
|
/** 测试用:重置模块级缓存 */
|
|
10
12
|
export declare function resetPlanWsRegistryForTest(): void;
|
|
11
13
|
/** 插件卸载/重载时清空计划 WS 登记表。 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan-ws-registry.d.ts","sourceRoot":"","sources":["../../src/plan-ws-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,MAAM,WAAW,YAAY;IACzB,MAAM,EAAE,cAAc,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACxB;AAiBD,0CAA0C;AAC1C,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAKnG;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEzE;AAED,kBAAkB;AAClB,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD;AAED,2BAA2B;AAC3B,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C"}
|
|
1
|
+
{"version":3,"file":"plan-ws-registry.d.ts","sourceRoot":"","sources":["../../src/plan-ws-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,MAAM,WAAW,YAAY;IACzB,MAAM,EAAE,cAAc,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACxB;AAiBD,0CAA0C;AAC1C,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAKnG;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEzE;AAED,iDAAiD;AACjD,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAMxE;AAED,kBAAkB;AAClB,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD;AAED,2BAA2B;AAC3B,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C"}
|
|
@@ -20,6 +20,14 @@ export function setPlanWsClient(groupId, client, replyToMsgId) {
|
|
|
20
20
|
export function getPlanWsClient(groupId) {
|
|
21
21
|
return planWsClients.get(groupId);
|
|
22
22
|
}
|
|
23
|
+
/** 账号真正停止时,移除指向该物理 client 的全部群组路由;其他账号路由不受影响。 */
|
|
24
|
+
export function removePlanWsClientsByClient(client) {
|
|
25
|
+
for (const [groupId, target] of planWsClients) {
|
|
26
|
+
if (target.client === client) {
|
|
27
|
+
planWsClients.delete(groupId);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
23
31
|
/** 测试用:重置模块级缓存 */
|
|
24
32
|
export function resetPlanWsRegistryForTest() {
|
|
25
33
|
disposePlanWsRegistry();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan-ws-registry.js","sourceRoot":"","sources":["../../src/plan-ws-registry.ts"],"names":[],"mappings":"AAOA,gDAAgD;AAChD,MAAM,yBAAyB,GAAG,GAAG,CAAC;AAEtC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAwB,CAAC;AAEtD,SAAS,uBAAuB;IAC5B,OAAO,aAAa,CAAC,IAAI,GAAG,yBAAyB,EAAE,CAAC;QACpD,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;QACpD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM;QACV,CAAC;QACD,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpC,CAAC;AACL,CAAC;AAED,0CAA0C;AAC1C,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,MAAsB,EAAE,YAAoB;IACzF,+BAA+B;IAC/B,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9B,aAAa,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;IACrD,uBAAuB,EAAE,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAe;IAC3C,OAAO,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACtC,CAAC;AAED,kBAAkB;AAClB,MAAM,UAAU,0BAA0B;IACtC,qBAAqB,EAAE,CAAC;AAC5B,CAAC;AAED,2BAA2B;AAC3B,MAAM,UAAU,qBAAqB;IACjC,aAAa,CAAC,KAAK,EAAE,CAAC;AAC1B,CAAC"}
|
|
1
|
+
{"version":3,"file":"plan-ws-registry.js","sourceRoot":"","sources":["../../src/plan-ws-registry.ts"],"names":[],"mappings":"AAOA,gDAAgD;AAChD,MAAM,yBAAyB,GAAG,GAAG,CAAC;AAEtC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAwB,CAAC;AAEtD,SAAS,uBAAuB;IAC5B,OAAO,aAAa,CAAC,IAAI,GAAG,yBAAyB,EAAE,CAAC;QACpD,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;QACpD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM;QACV,CAAC;QACD,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpC,CAAC;AACL,CAAC;AAED,0CAA0C;AAC1C,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,MAAsB,EAAE,YAAoB;IACzF,+BAA+B;IAC/B,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9B,aAAa,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;IACrD,uBAAuB,EAAE,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAe;IAC3C,OAAO,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACtC,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,2BAA2B,CAAC,MAAsB;IAC9D,KAAK,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;QAC5C,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC3B,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAClC,CAAC;IACL,CAAC;AACL,CAAC;AAED,kBAAkB;AAClB,MAAM,UAAU,0BAA0B;IACtC,qBAAqB,EAAE,CAAC;AAC5B,CAAC;AAED,2BAA2B;AAC3B,MAAM,UAAU,qBAAqB;IACjC,aAAa,CAAC,KAAK,EAAE,CAAC;AAC1B,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import { describe, it, beforeEach } from "node:test";
|
|
3
|
-
import { getPlanWsClient, resetPlanWsRegistryForTest, setPlanWsClient, } from "./plan-ws-registry.js";
|
|
3
|
+
import { getPlanWsClient, removePlanWsClientsByClient, resetPlanWsRegistryForTest, setPlanWsClient, } from "./plan-ws-registry.js";
|
|
4
|
+
import { disposePluginModule } from "./plugin-dispose.js";
|
|
4
5
|
function makeClient() {
|
|
5
6
|
return {
|
|
6
7
|
start: async () => { },
|
|
@@ -39,5 +40,22 @@ describe("plan-ws-registry", () => {
|
|
|
39
40
|
it("未登记的 groupId → undefined", () => {
|
|
40
41
|
assert.equal(getPlanWsClient("g-never-registered"), undefined);
|
|
41
42
|
});
|
|
43
|
+
it("按物理 client 定向移除路由时不影响其他 client", () => {
|
|
44
|
+
const clientA = makeClient();
|
|
45
|
+
const clientB = makeClient();
|
|
46
|
+
setPlanWsClient("g-a1", clientA, "msg-a1");
|
|
47
|
+
setPlanWsClient("g-a2", clientA, "msg-a2");
|
|
48
|
+
setPlanWsClient("g-b1", clientB, "msg-b1");
|
|
49
|
+
removePlanWsClientsByClient(clientA);
|
|
50
|
+
assert.equal(getPlanWsClient("g-a1"), undefined);
|
|
51
|
+
assert.equal(getPlanWsClient("g-a2"), undefined);
|
|
52
|
+
assert.equal(getPlanWsClient("g-b1")?.client, clientB);
|
|
53
|
+
});
|
|
54
|
+
it("registry cleanup 跳过计划资源时保留 WS 路由", async () => {
|
|
55
|
+
const client = makeClient();
|
|
56
|
+
setPlanWsClient("g-keep", client, "msg-keep");
|
|
57
|
+
await disposePluginModule({ skipConnections: true, skipPlanResources: true });
|
|
58
|
+
assert.equal(getPlanWsClient("g-keep")?.client, client);
|
|
59
|
+
});
|
|
42
60
|
});
|
|
43
61
|
//# sourceMappingURL=plan-ws-registry.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan-ws-registry.test.js","sourceRoot":"","sources":["../../src/plan-ws-registry.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAErD,OAAO,EACH,eAAe,EACf,0BAA0B,EAC1B,eAAe,GAClB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"plan-ws-registry.test.js","sourceRoot":"","sources":["../../src/plan-ws-registry.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,14 +5,16 @@
|
|
|
5
5
|
* - 真卸载 / gateway_stop:`disposePluginModule()`(skipConnections=false)——连同进程级共享的
|
|
6
6
|
* account-reconciler 一起 stopAll,并清空全部共享内存态(连接/流客户端/会话上下文/轮次/去重/env/
|
|
7
7
|
* subagent 监控)。由 index.ts 的 gateway_stop 钩子触发,且用 once 闸门保证只执行一次。
|
|
8
|
-
* - 插件热重载 / registry 代际交替:cleanup
|
|
9
|
-
*
|
|
8
|
+
* - 插件热重载 / registry 代际交替:cleanup 以 `disposePluginModule({ skipConnections: true,
|
|
9
|
+
* skipPlanResources: true })` 调用——只收尾可安全代际清理的句柄,保留计划读库与 plan-ws 路由,
|
|
10
10
|
* **绝不 stopAll、绝不清理共享连接/内存态**。连接只在 AccountReconciler(配置 diff,账号级)
|
|
11
11
|
* 与 gateway_stop(进程停机)处拆解,避免 OpenClaw runtime 代际交替误拆全部 WebSocket。
|
|
12
12
|
*/
|
|
13
13
|
export interface DisposePluginModuleOptions {
|
|
14
14
|
/** 注册表代际交替(热重载)场景:只收尾独占句柄,跳过共享连接与共享内存态。 */
|
|
15
15
|
skipConnections?: boolean;
|
|
16
|
+
/** 注册表代际交替时保留计划读库句柄与计划 WS 路由;gateway_stop 使用默认 false 完整清理。 */
|
|
17
|
+
skipPlanResources?: boolean;
|
|
16
18
|
}
|
|
17
19
|
/** skipConnections=false(gateway_stop)时停连接+清共享态;true(cleanup)只收尾独占句柄。 */
|
|
18
20
|
export declare function disposePluginModule(options?: DisposePluginModuleOptions): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-dispose.d.ts","sourceRoot":"","sources":["../../src/plugin-dispose.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAiBH,MAAM,WAAW,0BAA0B;IACvC,2CAA2C;IAC3C,eAAe,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin-dispose.d.ts","sourceRoot":"","sources":["../../src/plugin-dispose.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAiBH,MAAM,WAAW,0BAA0B;IACvC,2CAA2C;IAC3C,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,8DAA8D;IAC9D,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,yEAAyE;AACzE,wBAAsB,mBAAmB,CACrC,OAAO,GAAE,0BAA+B,GACzC,OAAO,CAAC,IAAI,CAAC,CA4Bf"}
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* - 真卸载 / gateway_stop:`disposePluginModule()`(skipConnections=false)——连同进程级共享的
|
|
6
6
|
* account-reconciler 一起 stopAll,并清空全部共享内存态(连接/流客户端/会话上下文/轮次/去重/env/
|
|
7
7
|
* subagent 监控)。由 index.ts 的 gateway_stop 钩子触发,且用 once 闸门保证只执行一次。
|
|
8
|
-
* - 插件热重载 / registry 代际交替:cleanup
|
|
9
|
-
*
|
|
8
|
+
* - 插件热重载 / registry 代际交替:cleanup 以 `disposePluginModule({ skipConnections: true,
|
|
9
|
+
* skipPlanResources: true })` 调用——只收尾可安全代际清理的句柄,保留计划读库与 plan-ws 路由,
|
|
10
10
|
* **绝不 stopAll、绝不清理共享连接/内存态**。连接只在 AccountReconciler(配置 diff,账号级)
|
|
11
11
|
* 与 gateway_stop(进程停机)处拆解,避免 OpenClaw runtime 代际交替误拆全部 WebSocket。
|
|
12
12
|
*/
|
|
@@ -27,8 +27,10 @@ import { disposeSubagentMonitor } from "./subagent-monitor.js";
|
|
|
27
27
|
/** skipConnections=false(gateway_stop)时停连接+清共享态;true(cleanup)只收尾独占句柄。 */
|
|
28
28
|
export async function disposePluginModule(options = {}) {
|
|
29
29
|
const { skipConnections = false } = options;
|
|
30
|
+
const { skipPlanResources = false } = options;
|
|
30
31
|
if (skipConnections) {
|
|
31
|
-
console.log(
|
|
32
|
+
console.log(`[xg_cwork_im] [reload] disposePluginModule skipConnections=true ` +
|
|
33
|
+
`skipPlanResources=${skipPlanResources} (registry cycle)`);
|
|
32
34
|
}
|
|
33
35
|
else {
|
|
34
36
|
// gateway_stop:停共享连接 + 清空共享热路径内存态(含 subagent 监控 maps/ticker)。
|
|
@@ -42,11 +44,12 @@ export async function disposePluginModule(options = {}) {
|
|
|
42
44
|
clearSessionNasVolumeStates();
|
|
43
45
|
disposeSessionEnvStore();
|
|
44
46
|
}
|
|
45
|
-
//
|
|
46
|
-
// plan/action/cron SQLite 句柄、plan-ws 句柄、token 缓存。
|
|
47
|
+
// 计划资源在 registry 代际交替时由新一代继续使用,不能被旧 cleanup 清空;gateway_stop 仍完整释放。
|
|
47
48
|
disposeActionStore();
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
if (!skipPlanResources) {
|
|
50
|
+
disposePlanStore();
|
|
51
|
+
disposePlanWsRegistry();
|
|
52
|
+
}
|
|
50
53
|
disposeCronAppKeyBindingStore();
|
|
51
54
|
clearAllTokenCache();
|
|
52
55
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-dispose.js","sourceRoot":"","sources":["../../src/plugin-dispose.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAC/E,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,2BAA2B,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,8BAA8B,EAAE,MAAM,gCAAgC,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin-dispose.js","sourceRoot":"","sources":["../../src/plugin-dispose.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAC/E,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,2BAA2B,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,8BAA8B,EAAE,MAAM,gCAAgC,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAS/D,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACrC,UAAsC,EAAE;IAExC,MAAM,EAAE,eAAe,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IAC5C,MAAM,EAAE,iBAAiB,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IAC9C,IAAI,eAAe,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CACP,kEAAkE;YAC9D,qBAAqB,iBAAiB,mBAAmB,CAChE,CAAC;IACN,CAAC;SAAM,CAAC;QACJ,8DAA8D;QAC9D,MAAM,iBAAiB,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QAChD,sBAAsB,EAAE,CAAC;QACzB,kBAAkB,EAAE,CAAC;QACrB,uBAAuB,EAAE,CAAC;QAC1B,0BAA0B,EAAE,CAAC;QAC7B,yBAAyB,EAAE,CAAC;QAC5B,8BAA8B,EAAE,CAAC;QACjC,2BAA2B,EAAE,CAAC;QAC9B,sBAAsB,EAAE,CAAC;IAC7B,CAAC;IACD,mEAAmE;IACnE,kBAAkB,EAAE,CAAC;IACrB,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACrB,gBAAgB,EAAE,CAAC;QACnB,qBAAqB,EAAE,CAAC;IAC5B,CAAC;IACD,6BAA6B,EAAE,CAAC;IAChC,kBAAkB,EAAE,CAAC;AACzB,CAAC"}
|
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import { describe, it } from "node:test";
|
|
3
3
|
import { isDeliverPayloadSendable, isDeliverTextRevision, snapshotSupersedesBufferText, TurnDeliverBuffer, } from "./turn-deliver-buffer.js";
|
|
4
|
-
const HOUTONG_BODY_LOOSE = `确实是这个问题:昨天那版虽然用了内嵌 SVG,但你现在的文档预览器没有把 SVG 正常渲染出来,所以流程看不到。
|
|
5
|
-
|
|
6
|
-
我已经重新生成了一版**纯 Markdown 可读版**:
|
|
7
|
-
|
|
8
|
-
- 不用 SVG
|
|
9
|
-
新文件:
|
|
10
|
-
|
|
4
|
+
const HOUTONG_BODY_LOOSE = `确实是这个问题:昨天那版虽然用了内嵌 SVG,但你现在的文档预览器没有把 SVG 正常渲染出来,所以流程看不到。
|
|
5
|
+
|
|
6
|
+
我已经重新生成了一版**纯 Markdown 可读版**:
|
|
7
|
+
|
|
8
|
+
- 不用 SVG
|
|
9
|
+
新文件:
|
|
10
|
+
|
|
11
11
|
-----`;
|
|
12
|
-
const HOUTONG_BODY_TIGHT = `确实是这个问题:昨天那版虽然用了内嵌 SVG,但你现在的文档预览器没有把 SVG 正常渲染出来,所以流程看不到。
|
|
13
|
-
我已经重新生成了一版**纯 Markdown 可读版**:
|
|
14
|
-
- 不用 SVG
|
|
12
|
+
const HOUTONG_BODY_TIGHT = `确实是这个问题:昨天那版虽然用了内嵌 SVG,但你现在的文档预览器没有把 SVG 正常渲染出来,所以流程看不到。
|
|
13
|
+
我已经重新生成了一版**纯 Markdown 可读版**:
|
|
14
|
+
- 不用 SVG
|
|
15
15
|
新文件:`;
|
|
16
|
-
const WORLD_CUP_PARTIAL = `| 场次 | 时间 |
|
|
17
|
-
| --- | --- |
|
|
18
|
-
| 1 | 21:00 |
|
|
16
|
+
const WORLD_CUP_PARTIAL = `| 场次 | 时间 |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| 1 | 21:00 |
|
|
19
19
|
| 2 |`;
|
|
20
|
-
const WORLD_CUP_FULL = `| 场次 | 时间 |
|
|
21
|
-
| --- | --- |
|
|
22
|
-
| 1 | 21:00 |
|
|
23
|
-
| 2 | 00:00 |
|
|
20
|
+
const WORLD_CUP_FULL = `| 场次 | 时间 |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
| 1 | 21:00 |
|
|
23
|
+
| 2 | 00:00 |
|
|
24
24
|
| 3 | 03:00 |`;
|
|
25
|
-
const RT002_PART1 = `BEGIN_123
|
|
26
|
-
|
|
27
|
-
## 一、背景
|
|
28
|
-
|
|
25
|
+
const RT002_PART1 = `BEGIN_123
|
|
26
|
+
|
|
27
|
+
## 一、背景
|
|
28
|
+
|
|
29
29
|
随着人工智能技术的快速发展,企业级AI助手在提升工作效率中发挥着日益重要的作用。`;
|
|
30
|
-
const RT002_PART2 = `- 工具调用的完整日志必须被记录,包括调用时间、调用者、工具名称。
|
|
31
|
-
|
|
32
|
-
## 六、审计
|
|
33
|
-
|
|
30
|
+
const RT002_PART2 = `- 工具调用的完整日志必须被记录,包括调用时间、调用者、工具名称。
|
|
31
|
+
|
|
32
|
+
## 六、审计
|
|
33
|
+
|
|
34
34
|
审计是AI助手治理的监督机制。`;
|
|
35
35
|
function entry(textPart, hasMedia = false) {
|
|
36
36
|
return {
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
{
|
|
2
|
-
"id": "xg_cwork_im",
|
|
3
|
-
"channels": [
|
|
4
|
-
"xg_cwork_im"
|
|
5
|
-
],
|
|
6
|
-
"channelConfigs": {
|
|
7
|
-
"xg_cwork_im": {
|
|
8
|
-
"schema": {
|
|
9
|
-
"type": "object",
|
|
10
|
-
"additionalProperties": true,
|
|
11
|
-
"properties": {}
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
},
|
|
15
|
-
"configSchema": {
|
|
16
|
-
"type": "object",
|
|
17
|
-
"additionalProperties": true,
|
|
18
|
-
"properties": {}
|
|
19
|
-
},
|
|
20
|
-
"contracts": {
|
|
21
|
-
"tools": [
|
|
22
|
-
"xg_cwork_im_get_group_chat_history",
|
|
23
|
-
"xg_cwork_im_send_group_message",
|
|
24
|
-
"xg_cwork_im_send_file"
|
|
25
|
-
],
|
|
26
|
-
"agentToolResultMiddleware": [
|
|
27
|
-
"openclaw",
|
|
28
|
-
"codex"
|
|
29
|
-
]
|
|
30
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"id": "xg_cwork_im",
|
|
3
|
+
"channels": [
|
|
4
|
+
"xg_cwork_im"
|
|
5
|
+
],
|
|
6
|
+
"channelConfigs": {
|
|
7
|
+
"xg_cwork_im": {
|
|
8
|
+
"schema": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"additionalProperties": true,
|
|
11
|
+
"properties": {}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"configSchema": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"additionalProperties": true,
|
|
18
|
+
"properties": {}
|
|
19
|
+
},
|
|
20
|
+
"contracts": {
|
|
21
|
+
"tools": [
|
|
22
|
+
"xg_cwork_im_get_group_chat_history",
|
|
23
|
+
"xg_cwork_im_send_group_message",
|
|
24
|
+
"xg_cwork_im_send_file"
|
|
25
|
+
],
|
|
26
|
+
"agentToolResultMiddleware": [
|
|
27
|
+
"openclaw",
|
|
28
|
+
"codex"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
31
|
}
|
package/package.json
CHANGED
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@xgjktech/xg_cwork_im",
|
|
3
|
-
"version": "1.17.
|
|
4
|
-
"description": "XG CWork IM channel plugin for OpenClaw",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"bot",
|
|
7
|
-
"channel",
|
|
8
|
-
"openclaw",
|
|
9
|
-
"xg_cwork_im",
|
|
10
|
-
"im"
|
|
11
|
-
],
|
|
12
|
-
"license": "MIT",
|
|
13
|
-
"type": "module",
|
|
14
|
-
"main": "dist/index.js",
|
|
15
|
-
"types": "dist/index.d.ts",
|
|
16
|
-
"engines": {
|
|
17
|
-
"node": ">=22.19.0"
|
|
18
|
-
},
|
|
19
|
-
"files": [
|
|
20
|
-
".npmrc",
|
|
21
|
-
"dist/**/*",
|
|
22
|
-
"openclaw.plugin.json"
|
|
23
|
-
],
|
|
24
|
-
"scripts": {
|
|
25
|
-
"build": "tsc -p tsconfig.json",
|
|
26
|
-
"type-check": "tsc -p tsconfig.json --noEmit",
|
|
27
|
-
"lint": "tsc -p tsconfig.json --noEmit",
|
|
28
|
-
"test": "npm run build && node --test dist/src/account-reconciler.test.js dist/src/inbound-terminal-state.test.js dist/src/user-facing-errors.test.js dist/src/deliver-text.test.js dist/src/agent-context-types.test.js dist/src/build-project-prompt.test.js dist/src/nas-volumes.test.js dist/src/workspace-event.test.js dist/src/workspace-event-scheduler.test.js dist/src/connection-workspace-event.test.js dist/src/block-streaming-config.test.js dist/src/channel-disabled-account.test.js dist/src/per-message-fallback-notice.test.js dist/src/thinking-ws-progress.test.js dist/src/resource-file.test.js dist/src/turn-deliver-buffer.test.js dist/src/run-usage.test.js dist/src/ws-run-event-unmapped.test.js dist/src/item-event-guard.test.js dist/src/inbound-model.test.js dist/src/auto-model-router.test.js dist/src/channel-config.test.js dist/src/send-service.test.js dist/src/send-file-tool.test.js dist/src/plan-tool-result.test.js dist/src/plan-blocked-notice.test.js dist/src/plan-store-access.test.js dist/src/plan-tool-middleware.test.js dist/src/plan-event-subscription.test.js dist/src/plan-ws-registry.test.js dist/src/plan-stat-event.test.js dist/src/active-round-registry.test.js dist/src/interrupt-round.test.js dist/src/subagent-monitor.test.js dist/src/session-env-store.test.js dist/src/register-exec-env-hook.test.js dist/src/cron-appkey-binding-store.test.js dist/src/ws-inbound-schema.test.js",
|
|
29
|
-
"install:prod": "npm install --omit=dev",
|
|
30
|
-
"prepublishOnly": "npm run build"
|
|
31
|
-
},
|
|
32
|
-
"dependencies": {
|
|
33
|
-
"@sinclair/typebox": "^0.32.0",
|
|
34
|
-
"@xgjktech/xg-openclaw-shared": "^0.2.2",
|
|
35
|
-
"adm-zip": "^0.6.0",
|
|
36
|
-
"axios": "^1.6.0",
|
|
37
|
-
"tar": "^7.5.22",
|
|
38
|
-
"ws": "^8.17.0",
|
|
39
|
-
"zod": "^3.22.0"
|
|
40
|
-
},
|
|
41
|
-
"devDependencies": {
|
|
42
|
-
"@types/node": "^22.19.0",
|
|
43
|
-
"@types/ws": "^8.5.10",
|
|
44
|
-
"openclaw": "^2026.6.10",
|
|
45
|
-
"typescript": "^5.3.0"
|
|
46
|
-
},
|
|
47
|
-
"peerDependencies": {
|
|
48
|
-
"openclaw": ">=2026.6.10"
|
|
49
|
-
},
|
|
50
|
-
"peerDependenciesMeta": {
|
|
51
|
-
"openclaw": {
|
|
52
|
-
"optional": true
|
|
53
|
-
}
|
|
54
|
-
},
|
|
55
|
-
"openclaw": {
|
|
56
|
-
"extensions": [
|
|
57
|
-
"./dist/index.js"
|
|
58
|
-
],
|
|
59
|
-
"channels": [
|
|
60
|
-
"xg_cwork_im"
|
|
61
|
-
],
|
|
62
|
-
"installDependencies": false,
|
|
63
|
-
"channel": {
|
|
64
|
-
"id": "xg_cwork_im",
|
|
65
|
-
"label": "XG CWork IM",
|
|
66
|
-
"selectionLabel": "XG CWork IM (工作说说)",
|
|
67
|
-
"blurb": "工作说说 IM 机器人 Channel 插件,通过 WebSocket 长连接接收消息。",
|
|
68
|
-
"aliases": [
|
|
69
|
-
"xg_cwork_im",
|
|
70
|
-
"im"
|
|
71
|
-
]
|
|
72
|
-
},
|
|
73
|
-
"install": {
|
|
74
|
-
"localPath": ".",
|
|
75
|
-
"defaultChoice": "local"
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@xgjktech/xg_cwork_im",
|
|
3
|
+
"version": "1.17.51",
|
|
4
|
+
"description": "XG CWork IM channel plugin for OpenClaw",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"bot",
|
|
7
|
+
"channel",
|
|
8
|
+
"openclaw",
|
|
9
|
+
"xg_cwork_im",
|
|
10
|
+
"im"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "dist/index.js",
|
|
15
|
+
"types": "dist/index.d.ts",
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=22.19.0"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
".npmrc",
|
|
21
|
+
"dist/**/*",
|
|
22
|
+
"openclaw.plugin.json"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsc -p tsconfig.json",
|
|
26
|
+
"type-check": "tsc -p tsconfig.json --noEmit",
|
|
27
|
+
"lint": "tsc -p tsconfig.json --noEmit",
|
|
28
|
+
"test": "npm run build && node --test dist/src/account-reconciler.test.js dist/src/inbound-terminal-state.test.js dist/src/user-facing-errors.test.js dist/src/deliver-text.test.js dist/src/agent-context-types.test.js dist/src/build-project-prompt.test.js dist/src/nas-volumes.test.js dist/src/workspace-event.test.js dist/src/workspace-event-scheduler.test.js dist/src/connection-workspace-event.test.js dist/src/block-streaming-config.test.js dist/src/channel-disabled-account.test.js dist/src/per-message-fallback-notice.test.js dist/src/thinking-ws-progress.test.js dist/src/resource-file.test.js dist/src/turn-deliver-buffer.test.js dist/src/run-usage.test.js dist/src/ws-run-event-unmapped.test.js dist/src/item-event-guard.test.js dist/src/inbound-model.test.js dist/src/auto-model-router.test.js dist/src/channel-config.test.js dist/src/send-service.test.js dist/src/send-file-tool.test.js dist/src/plan-tool-result.test.js dist/src/plan-blocked-notice.test.js dist/src/plan-store-access.test.js dist/src/plan-tool-middleware.test.js dist/src/plan-event-subscription.test.js dist/src/plan-ws-registry.test.js dist/src/plan-stat-event.test.js dist/src/active-round-registry.test.js dist/src/interrupt-round.test.js dist/src/subagent-monitor.test.js dist/src/session-env-store.test.js dist/src/register-exec-env-hook.test.js dist/src/cron-appkey-binding-store.test.js dist/src/ws-inbound-schema.test.js",
|
|
29
|
+
"install:prod": "npm install --omit=dev",
|
|
30
|
+
"prepublishOnly": "npm run build"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@sinclair/typebox": "^0.32.0",
|
|
34
|
+
"@xgjktech/xg-openclaw-shared": "^0.2.2",
|
|
35
|
+
"adm-zip": "^0.6.0",
|
|
36
|
+
"axios": "^1.6.0",
|
|
37
|
+
"tar": "^7.5.22",
|
|
38
|
+
"ws": "^8.17.0",
|
|
39
|
+
"zod": "^3.22.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^22.19.0",
|
|
43
|
+
"@types/ws": "^8.5.10",
|
|
44
|
+
"openclaw": "^2026.6.10",
|
|
45
|
+
"typescript": "^5.3.0"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"openclaw": ">=2026.6.10"
|
|
49
|
+
},
|
|
50
|
+
"peerDependenciesMeta": {
|
|
51
|
+
"openclaw": {
|
|
52
|
+
"optional": true
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"openclaw": {
|
|
56
|
+
"extensions": [
|
|
57
|
+
"./dist/index.js"
|
|
58
|
+
],
|
|
59
|
+
"channels": [
|
|
60
|
+
"xg_cwork_im"
|
|
61
|
+
],
|
|
62
|
+
"installDependencies": false,
|
|
63
|
+
"channel": {
|
|
64
|
+
"id": "xg_cwork_im",
|
|
65
|
+
"label": "XG CWork IM",
|
|
66
|
+
"selectionLabel": "XG CWork IM (工作说说)",
|
|
67
|
+
"blurb": "工作说说 IM 机器人 Channel 插件,通过 WebSocket 长连接接收消息。",
|
|
68
|
+
"aliases": [
|
|
69
|
+
"xg_cwork_im",
|
|
70
|
+
"im"
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
"install": {
|
|
74
|
+
"localPath": ".",
|
|
75
|
+
"defaultChoice": "local"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 单聊轮次结束但未向 IM 发出正文时的兜底话术(如模型输出 NO_REPLY、deliver 未被调用)。
|
|
3
|
-
*/
|
|
4
|
-
import type { WsMessageParams } from "./types.js";
|
|
5
|
-
export declare function shouldSendSingleChatNoReplyFallback(args: {
|
|
6
|
-
params: WsMessageParams;
|
|
7
|
-
hasFirstReply: boolean;
|
|
8
|
-
deliverCallCount: number;
|
|
9
|
-
dispatchError?: unknown;
|
|
10
|
-
lastDeliverError?: unknown;
|
|
11
|
-
}): boolean;
|
|
12
|
-
/** 单聊静默轮次兜底:简短告知并引导重试。 */
|
|
13
|
-
export declare function buildSingleChatNoReplyFallbackText(): string;
|
|
14
|
-
//# sourceMappingURL=single-chat-no-reply-fallback.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"single-chat-no-reply-fallback.d.ts","sourceRoot":"","sources":["../../src/single-chat-no-reply-fallback.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,wBAAgB,mCAAmC,CAAC,IAAI,EAAE;IACtD,MAAM,EAAE,eAAe,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B,GAAG,OAAO,CAMV;AAED,0BAA0B;AAC1B,wBAAgB,kCAAkC,IAAI,MAAM,CAE3D"}
|