@ai-setting/roy-agent-core 1.7.77 → 1.7.88
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/config/config-protection.d.ts +89 -0
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.js +23 -7
- package/dist/env/agent/agent-component.d.ts +43 -22
- package/dist/env/agent/agent-component.js +13 -12
- package/dist/env/agent/index.js +13 -12
- package/dist/env/agent/types.d.ts +46 -12
- package/dist/env/commands/index.js +7 -7
- package/dist/env/context/index.js +3 -3
- package/dist/env/debug/index.js +7 -7
- package/dist/env/error-reply.d.ts +6 -0
- package/dist/env/error-reply.js +1 -1
- package/dist/env/event-source/bounty-im-handler.d.ts +8 -0
- package/dist/env/event-source/es-command.d.ts +39 -0
- package/dist/env/event-source/es-plugins.d.ts +68 -0
- package/dist/env/event-source/event-source-component.d.ts +15 -0
- package/dist/env/event-source/event-source-handlers.d.ts +84 -0
- package/dist/env/event-source/event-source-handlers.js +40 -23
- package/dist/env/event-source/event-store.js +2 -2
- package/dist/env/event-source/index.d.ts +5 -1
- package/dist/env/event-source/index.js +75 -23
- package/dist/env/event-source/timer-handler.d.ts +98 -0
- package/dist/env/event-source/types.d.ts +154 -2
- package/dist/env/event-source/wecom-card-action-handler.d.ts +373 -0
- package/dist/env/event-source/wecom-card-builder.d.ts +426 -0
- package/dist/env/event-source/wecom-cli-handler.d.ts +291 -0
- package/dist/env/event-source/wecom-cli-sender.d.ts +88 -0
- package/dist/env/event-source/wecom-media.d.ts +130 -0
- package/dist/env/event-source/wecom-respond-registry.d.ts +151 -0
- package/dist/env/event-source/wecom-respond-registry.js +33 -0
- package/dist/env/event-source/wecom-session-card-sender.d.ts +135 -0
- package/dist/env/event-source/wecom-session-card-sender.js +153 -0
- package/dist/env/event-source/wecom-ws-bridge.d.ts +213 -0
- package/dist/env/hook/index.js +5 -5
- package/dist/env/index.js +51 -45
- package/dist/env/llm/index.js +9 -8
- package/dist/env/log-trace/index.js +7 -7
- package/dist/env/log-trace/trace-filters.d.ts +6 -1
- package/dist/env/mcp/index.js +7 -7
- package/dist/env/memory/index.js +7 -7
- package/dist/env/plugin/index.js +7 -7
- package/dist/env/prompt/index.js +8 -8
- package/dist/env/prompt/prompts-index.d.ts +1 -1
- package/dist/env/session/group-session-link.d.ts +99 -0
- package/dist/env/session/index.js +11 -10
- package/dist/env/session/session-component.d.ts +89 -0
- package/dist/env/session/storage/index.js +5 -4
- package/dist/env/session/types.d.ts +10 -0
- package/dist/env/skill/index.js +7 -7
- package/dist/env/task/delegate/delegate-channel-hint.d.ts +39 -0
- package/dist/env/task/delegate/delegate-tool.d.ts +132 -7
- package/dist/env/task/delegate/delegate-tool.js +13 -9
- package/dist/env/task/delegate/index.js +8 -8
- package/dist/env/task/index.js +18 -18
- package/dist/env/task/mcp/index.js +4 -4
- package/dist/env/task/plugins/card-subject.d.ts +117 -0
- package/dist/env/task/plugins/index.d.ts +2 -0
- package/dist/env/task/plugins/index.js +39 -16
- package/dist/env/task/plugins/lark-card-action-handler.d.ts +261 -6
- package/dist/env/task/plugins/lark-card-patch-notifier.d.ts +542 -2
- package/dist/env/task/plugins/lark-card-patch-notifier.js +12 -2
- package/dist/env/task/plugins/lark-card-state-store.d.ts +60 -0
- package/dist/env/task/plugins/lark-cli-task-notify-plugin.d.ts +61 -0
- package/dist/env/task/plugins/sub-session-activity.d.ts +415 -0
- package/dist/env/task/plugins/wecom-card-state-store.d.ts +121 -0
- package/dist/env/task/plugins/wecom-session-card-store.d.ts +134 -0
- package/dist/env/task/plugins/wecom-session-card-store.js +23 -0
- package/dist/env/task/plugins/wecom-task-notify-plugin.d.ts +264 -0
- package/dist/env/task/storage/index.js +3 -3
- package/dist/env/task/tools/index.js +4 -4
- package/dist/env/tool/built-in/index.d.ts +2 -0
- package/dist/env/tool/built-in/index.js +9 -2
- package/dist/env/tool/index.js +14 -9
- package/dist/env/tool/types.d.ts +25 -0
- package/dist/env/tool/validator.d.ts +8 -0
- package/dist/env/workflow/engine/index.js +12 -12
- package/dist/env/workflow/hooks/index.js +7 -7
- package/dist/env/workflow/index.js +24 -23
- package/dist/env/workflow/nodes/index.js +2 -2
- package/dist/env/workflow/plugins/index.js +10 -8
- package/dist/env/workflow/service/index.js +2 -2
- package/dist/env/workflow/storage/index.js +3 -3
- package/dist/env/workflow/tools/index.js +16 -15
- package/dist/env/workflow/utils/index.js +4 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +118 -62
- package/dist/shared/@ai-setting/{roy-agent-core-dc9zq75z.js → roy-agent-core-0crmsc12.js} +3 -3
- package/dist/shared/@ai-setting/{roy-agent-core-aa2j7bk9.js → roy-agent-core-0sbmdz8d.js} +171 -36
- package/dist/shared/@ai-setting/{roy-agent-core-87942bw4.js → roy-agent-core-1mhyh4c5.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-v6vr6za7.js → roy-agent-core-1vv4fx15.js} +4 -4
- package/dist/shared/@ai-setting/roy-agent-core-2stt4rp5.js +134 -0
- package/dist/shared/@ai-setting/{roy-agent-core-nwbfepba.js → roy-agent-core-3e040tc5.js} +1 -1
- package/dist/shared/@ai-setting/roy-agent-core-418zc9ha.js +288 -0
- package/dist/shared/@ai-setting/{roy-agent-core-r5wt1h3c.js → roy-agent-core-4fkxy2gv.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-na18zwj0.js → roy-agent-core-4t3yskp8.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-5pr4zp88.js → roy-agent-core-5kzhaap1.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-qq96p0tj.js → roy-agent-core-5s2t8z00.js} +22 -1
- package/dist/shared/@ai-setting/{roy-agent-core-6rh8k6ba.js → roy-agent-core-6gj1hc5z.js} +7 -7
- package/dist/shared/@ai-setting/{roy-agent-core-ezvpreqz.js → roy-agent-core-6k8mb7zx.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-g8htfwxj.js → roy-agent-core-7f10p7m2.js} +1 -1
- package/dist/shared/@ai-setting/roy-agent-core-7kvpc0w5.js +177 -0
- package/dist/shared/@ai-setting/{roy-agent-core-h21gngxf.js → roy-agent-core-7yh5wps0.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-efkjyh69.js → roy-agent-core-9710zwwz.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-6cy43nss.js → roy-agent-core-9c565frx.js} +49 -9
- package/dist/shared/@ai-setting/{roy-agent-core-fghc2m8z.js → roy-agent-core-aa8kv18f.js} +34 -2
- package/dist/shared/@ai-setting/{roy-agent-core-ew6qb5yx.js → roy-agent-core-an35dzbf.js} +6 -6
- package/dist/shared/@ai-setting/{roy-agent-core-mww0mnd9.js → roy-agent-core-azyz78ky.js} +7 -7
- package/dist/shared/@ai-setting/{roy-agent-core-264qexac.js → roy-agent-core-b7h39vrc.js} +4 -4
- package/dist/shared/@ai-setting/{roy-agent-core-dqxec05w.js → roy-agent-core-bjtc9d35.js} +2 -2
- package/dist/shared/@ai-setting/roy-agent-core-c4ec7k0p.js +426 -0
- package/dist/shared/@ai-setting/{roy-agent-core-ddyk1rc0.js → roy-agent-core-cre2y2ct.js} +160 -4
- package/dist/shared/@ai-setting/{roy-agent-core-tr3ep81v.js → roy-agent-core-d6zdbgtc.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-0qyrk5k0.js → roy-agent-core-ds6qzmf8.js} +14 -5
- package/dist/shared/@ai-setting/{roy-agent-core-cgtq6427.js → roy-agent-core-e08bvpaq.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-12n08pg5.js → roy-agent-core-e69qxdyy.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-rhtdspx6.js → roy-agent-core-fan8g0z1.js} +10 -10
- package/dist/shared/@ai-setting/{roy-agent-core-xcp8vwax.js → roy-agent-core-fepm835e.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-6j02sbee.js → roy-agent-core-fhg03v43.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-99nwgj84.js → roy-agent-core-fzw9xzm1.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-dvtg4sn0.js → roy-agent-core-g8yr733d.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-3gpygqcx.js → roy-agent-core-gr5h1dyr.js} +2753 -358
- package/dist/shared/@ai-setting/roy-agent-core-h1e1fm9b.js +380 -0
- package/dist/shared/@ai-setting/{roy-agent-core-c2gbt68e.js → roy-agent-core-h83zdsrq.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-8ez6mccb.js → roy-agent-core-k3gcvybs.js} +5 -1
- package/dist/shared/@ai-setting/{roy-agent-core-pgvcf91v.js → roy-agent-core-m39v7qpx.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-tm1mxttk.js → roy-agent-core-mf5p38yf.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-83bewqx8.js → roy-agent-core-mvh0td7p.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-v85n42ve.js → roy-agent-core-mx855td4.js} +17 -38
- package/dist/shared/@ai-setting/{roy-agent-core-v87njmq7.js → roy-agent-core-n197medr.js} +13 -13
- package/dist/shared/@ai-setting/{roy-agent-core-cmprygrp.js → roy-agent-core-nqkfkpf4.js} +4 -4
- package/dist/shared/@ai-setting/{roy-agent-core-7cbpmk4q.js → roy-agent-core-p31ftgq9.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-vffccgf6.js → roy-agent-core-qwd2dq5q.js} +10 -3
- package/dist/shared/@ai-setting/{roy-agent-core-rsn44n9y.js → roy-agent-core-ra66sf50.js} +2526 -942
- package/dist/shared/@ai-setting/{roy-agent-core-1v4g0d4x.js → roy-agent-core-rm7seqwb.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-w0qjeq2v.js → roy-agent-core-shb1qsyg.js} +1041 -18
- package/dist/shared/@ai-setting/{roy-agent-core-ax9e9szb.js → roy-agent-core-smf94h73.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-acj8ag08.js → roy-agent-core-tjnabyvq.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-qqaak24r.js → roy-agent-core-tkpp1ba0.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-9vhq7fvv.js → roy-agent-core-tpm1dd1g.js} +34 -88
- package/dist/shared/@ai-setting/{roy-agent-core-ed233k5z.js → roy-agent-core-v1n0106v.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-zxz5fkwj.js → roy-agent-core-v6yshv0z.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-mcy5apay.js → roy-agent-core-vf9sp6s3.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-q813vafd.js → roy-agent-core-vpcxv1ty.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-bxkjk7zx.js → roy-agent-core-vx8zc847.js} +4 -1
- package/dist/shared/@ai-setting/{roy-agent-core-xvt7kf7p.js → roy-agent-core-w9ryeg2p.js} +3 -3
- package/dist/shared/@ai-setting/{roy-agent-core-es203w7p.js → roy-agent-core-wqs6yypq.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-hd3n57zs.js → roy-agent-core-wr1qexzq.js} +5 -5
- package/dist/shared/@ai-setting/roy-agent-core-wxrkcb17.js +56 -0
- package/dist/shared/@ai-setting/{roy-agent-core-0snm5hc5.js → roy-agent-core-y6shd91r.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-9vxh6f8h.js → roy-agent-core-y7fqtzk2.js} +7 -7
- package/dist/shared/@ai-setting/{roy-agent-core-cpcd24n2.js → roy-agent-core-yet36q5k.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-3fh1f7s7.js → roy-agent-core-yfpnkc4z.js} +5 -5
- package/dist/shared/@ai-setting/{roy-agent-core-0v27y99n.js → roy-agent-core-yh68z1bg.js} +65 -4
- package/package.json +18 -1
- /package/dist/shared/@ai-setting/{roy-agent-core-b4x6x4k2.js → roy-agent-core-m1fgtnrc.js} +0 -0
|
@@ -1,27 +1,326 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formatActivityLines,
|
|
3
|
+
formatRecentToolCallLines
|
|
4
|
+
} from "./roy-agent-core-418zc9ha.js";
|
|
5
|
+
import {
|
|
6
|
+
createCompatibleDatabase,
|
|
7
|
+
init_sqlite_task_store
|
|
8
|
+
} from "./roy-agent-core-6k8mb7zx.js";
|
|
1
9
|
import {
|
|
2
10
|
TracedAs,
|
|
3
11
|
init_decorator
|
|
4
|
-
} from "./roy-agent-core-
|
|
12
|
+
} from "./roy-agent-core-5s2t8z00.js";
|
|
5
13
|
import {
|
|
6
14
|
createLogger,
|
|
7
15
|
init_logger
|
|
8
16
|
} from "./roy-agent-core-7f7t9wwp.js";
|
|
9
17
|
import {
|
|
10
|
-
__legacyDecorateClassTS
|
|
18
|
+
__legacyDecorateClassTS,
|
|
19
|
+
__require
|
|
11
20
|
} from "./roy-agent-core-fs0mn2jk.js";
|
|
12
21
|
|
|
22
|
+
// src/env/task/plugins/lark-card-patch-notifier.ts
|
|
23
|
+
import { spawn } from "node:child_process";
|
|
24
|
+
|
|
25
|
+
// src/env/task/plugins/lark-card-state-store.ts
|
|
26
|
+
init_logger();
|
|
27
|
+
init_sqlite_task_store();
|
|
28
|
+
import { join } from "path";
|
|
29
|
+
var logger = createLogger("lark-cli:card-state");
|
|
30
|
+
|
|
31
|
+
class MemoryLarkCardStateStore {
|
|
32
|
+
records = new Map;
|
|
33
|
+
upsert(state) {
|
|
34
|
+
this.records.set(state.taskId, { ...state });
|
|
35
|
+
}
|
|
36
|
+
get(taskId) {
|
|
37
|
+
const r = this.records.get(taskId);
|
|
38
|
+
return r ? { ...r } : undefined;
|
|
39
|
+
}
|
|
40
|
+
list() {
|
|
41
|
+
return [...this.records.values()].map((r) => ({ ...r }));
|
|
42
|
+
}
|
|
43
|
+
markPinned(taskId, pinned) {
|
|
44
|
+
const r = this.records.get(taskId);
|
|
45
|
+
if (!r)
|
|
46
|
+
return;
|
|
47
|
+
r.pinned = pinned;
|
|
48
|
+
r.updatedAt = Date.now();
|
|
49
|
+
}
|
|
50
|
+
markPaused(taskId) {
|
|
51
|
+
const r = this.records.get(taskId);
|
|
52
|
+
if (!r)
|
|
53
|
+
return;
|
|
54
|
+
r.status = "paused";
|
|
55
|
+
r.updatedAt = Date.now();
|
|
56
|
+
}
|
|
57
|
+
markReopened(taskId) {
|
|
58
|
+
const r = this.records.get(taskId);
|
|
59
|
+
if (!r)
|
|
60
|
+
return;
|
|
61
|
+
r.status = "open";
|
|
62
|
+
delete r.closedAt;
|
|
63
|
+
r.updatedAt = Date.now();
|
|
64
|
+
}
|
|
65
|
+
markClosed(taskId) {
|
|
66
|
+
const r = this.records.get(taskId);
|
|
67
|
+
if (!r)
|
|
68
|
+
return;
|
|
69
|
+
const now = Date.now();
|
|
70
|
+
r.status = "closed";
|
|
71
|
+
r.closedAt = now;
|
|
72
|
+
r.updatedAt = now;
|
|
73
|
+
}
|
|
74
|
+
delete(taskId) {
|
|
75
|
+
this.records.delete(taskId);
|
|
76
|
+
}
|
|
77
|
+
close() {
|
|
78
|
+
this.records.clear();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function rowToState(row) {
|
|
82
|
+
const state = {
|
|
83
|
+
taskId: row.task_id,
|
|
84
|
+
messageId: row.message_id,
|
|
85
|
+
chatId: row.chat_id,
|
|
86
|
+
pinned: row.pinned === 1,
|
|
87
|
+
status: row.status ?? "open",
|
|
88
|
+
createdAt: row.created_at,
|
|
89
|
+
updatedAt: row.updated_at
|
|
90
|
+
};
|
|
91
|
+
if (row.profile)
|
|
92
|
+
state.profile = row.profile;
|
|
93
|
+
if (row.closed_at !== null && row.closed_at !== undefined) {
|
|
94
|
+
state.closedAt = row.closed_at;
|
|
95
|
+
}
|
|
96
|
+
if (row.timeline)
|
|
97
|
+
state.timeline = row.timeline;
|
|
98
|
+
if (row.session_id)
|
|
99
|
+
state.sessionId = row.session_id;
|
|
100
|
+
return state;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
class SqliteLarkCardStateStore {
|
|
104
|
+
db;
|
|
105
|
+
constructor(dbPath) {
|
|
106
|
+
if (dbPath !== ":memory:") {
|
|
107
|
+
const { mkdirSync } = __require("fs");
|
|
108
|
+
const dir = __require("path").dirname(dbPath);
|
|
109
|
+
try {
|
|
110
|
+
mkdirSync(dir, { recursive: true });
|
|
111
|
+
} catch {}
|
|
112
|
+
}
|
|
113
|
+
this.db = createCompatibleDatabase(dbPath);
|
|
114
|
+
try {
|
|
115
|
+
this.db.run("PRAGMA journal_mode = WAL");
|
|
116
|
+
this.db.run("PRAGMA busy_timeout = 5000");
|
|
117
|
+
this.db.run("PRAGMA synchronous = NORMAL");
|
|
118
|
+
} catch {}
|
|
119
|
+
this.db.run(`
|
|
120
|
+
CREATE TABLE IF NOT EXISTS lark_card (
|
|
121
|
+
task_id INTEGER PRIMARY KEY,
|
|
122
|
+
message_id TEXT NOT NULL,
|
|
123
|
+
chat_id TEXT NOT NULL,
|
|
124
|
+
profile TEXT,
|
|
125
|
+
pinned INTEGER NOT NULL DEFAULT 0,
|
|
126
|
+
status TEXT NOT NULL DEFAULT 'open',
|
|
127
|
+
created_at INTEGER NOT NULL,
|
|
128
|
+
updated_at INTEGER NOT NULL,
|
|
129
|
+
closed_at INTEGER,
|
|
130
|
+
timeline TEXT,
|
|
131
|
+
session_id TEXT
|
|
132
|
+
)
|
|
133
|
+
`);
|
|
134
|
+
try {
|
|
135
|
+
this.db.run("ALTER TABLE lark_card ADD COLUMN timeline TEXT");
|
|
136
|
+
} catch {}
|
|
137
|
+
try {
|
|
138
|
+
this.db.run("ALTER TABLE lark_card ADD COLUMN session_id TEXT");
|
|
139
|
+
} catch {}
|
|
140
|
+
this.db.run("CREATE INDEX IF NOT EXISTS idx_lark_card_status ON lark_card(status)");
|
|
141
|
+
}
|
|
142
|
+
upsert(state) {
|
|
143
|
+
this.db.prepare(`INSERT INTO lark_card
|
|
144
|
+
(task_id, message_id, chat_id, profile, pinned, status, created_at, updated_at, closed_at, timeline, session_id)
|
|
145
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
146
|
+
ON CONFLICT(task_id) DO UPDATE SET
|
|
147
|
+
message_id = excluded.message_id,
|
|
148
|
+
chat_id = excluded.chat_id,
|
|
149
|
+
profile = excluded.profile,
|
|
150
|
+
pinned = excluded.pinned,
|
|
151
|
+
status = excluded.status,
|
|
152
|
+
updated_at = excluded.updated_at,
|
|
153
|
+
closed_at = excluded.closed_at,
|
|
154
|
+
timeline = excluded.timeline,
|
|
155
|
+
session_id = COALESCE(excluded.session_id, lark_card.session_id)`).run(state.taskId, state.messageId, state.chatId, state.profile ?? null, state.pinned ? 1 : 0, state.status, state.createdAt, state.updatedAt, state.closedAt ?? null, state.timeline ?? null, state.sessionId ?? null);
|
|
156
|
+
}
|
|
157
|
+
get(taskId) {
|
|
158
|
+
const row = this.db.prepare("SELECT * FROM lark_card WHERE task_id = ?").get(taskId);
|
|
159
|
+
return row ? rowToState(row) : undefined;
|
|
160
|
+
}
|
|
161
|
+
list() {
|
|
162
|
+
const rows = this.db.prepare("SELECT * FROM lark_card ORDER BY task_id ASC").all();
|
|
163
|
+
return rows.map(rowToState);
|
|
164
|
+
}
|
|
165
|
+
markPinned(taskId, pinned) {
|
|
166
|
+
this.db.prepare("UPDATE lark_card SET pinned = ?, updated_at = ? WHERE task_id = ?").run(pinned ? 1 : 0, Date.now(), taskId);
|
|
167
|
+
}
|
|
168
|
+
markPaused(taskId) {
|
|
169
|
+
this.db.prepare("UPDATE lark_card SET status = 'paused', updated_at = ? WHERE task_id = ?").run(Date.now(), taskId);
|
|
170
|
+
}
|
|
171
|
+
markReopened(taskId) {
|
|
172
|
+
this.db.prepare("UPDATE lark_card SET status = 'open', closed_at = NULL, updated_at = ? WHERE task_id = ?").run(Date.now(), taskId);
|
|
173
|
+
}
|
|
174
|
+
markClosed(taskId) {
|
|
175
|
+
const now = Date.now();
|
|
176
|
+
this.db.prepare("UPDATE lark_card SET status = 'closed', closed_at = ?, updated_at = ? WHERE task_id = ?").run(now, now, taskId);
|
|
177
|
+
}
|
|
178
|
+
delete(taskId) {
|
|
179
|
+
this.db.prepare("DELETE FROM lark_card WHERE task_id = ?").run(taskId);
|
|
180
|
+
}
|
|
181
|
+
close() {
|
|
182
|
+
try {
|
|
183
|
+
this.db.close?.();
|
|
184
|
+
} catch {}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function getDefaultLarkCardDbPath() {
|
|
188
|
+
const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
|
|
189
|
+
return join(home, ".local", "share", "roy-agent", "lark-cards.db");
|
|
190
|
+
}
|
|
191
|
+
function createLarkCardStateStore(dbPath) {
|
|
192
|
+
const isTestEnv = "BUN_TEST_WORKER_ID" in process.env;
|
|
193
|
+
if (!dbPath && !process.env.ROY_AGENT_LARK_CARD_DB && isTestEnv) {
|
|
194
|
+
return new MemoryLarkCardStateStore;
|
|
195
|
+
}
|
|
196
|
+
const path = dbPath ?? process.env.ROY_AGENT_LARK_CARD_DB ?? getDefaultLarkCardDbPath();
|
|
197
|
+
try {
|
|
198
|
+
return new SqliteLarkCardStateStore(path);
|
|
199
|
+
} catch (err) {
|
|
200
|
+
logger.warn(`LarkCardStateStore: sqlite unavailable at ${path} (${err.message}) ` + `→ falling back to in-memory (卡片仍可发,但重启后无法 patch 旧卡)`);
|
|
201
|
+
return new MemoryLarkCardStateStore;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
var sharedStateStore;
|
|
205
|
+
function getSharedLarkCardStateStore() {
|
|
206
|
+
if (!sharedStateStore)
|
|
207
|
+
sharedStateStore = createLarkCardStateStore();
|
|
208
|
+
return sharedStateStore;
|
|
209
|
+
}
|
|
210
|
+
class MemoryLarkSessionCardStore {
|
|
211
|
+
records = new Map;
|
|
212
|
+
upsert(rec) {
|
|
213
|
+
this.records.set(rec.sessionId, { ...rec });
|
|
214
|
+
}
|
|
215
|
+
get(sessionId) {
|
|
216
|
+
const r = this.records.get(sessionId);
|
|
217
|
+
return r ? { ...r } : undefined;
|
|
218
|
+
}
|
|
219
|
+
list() {
|
|
220
|
+
return [...this.records.values()].map((r) => ({ ...r }));
|
|
221
|
+
}
|
|
222
|
+
delete(sessionId) {
|
|
223
|
+
this.records.delete(sessionId);
|
|
224
|
+
}
|
|
225
|
+
close() {
|
|
226
|
+
this.records.clear();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
class SqliteLarkSessionCardStore {
|
|
231
|
+
db;
|
|
232
|
+
constructor(dbPath) {
|
|
233
|
+
this.db = createCompatibleDatabase(dbPath);
|
|
234
|
+
try {
|
|
235
|
+
this.db.run("PRAGMA journal_mode = WAL");
|
|
236
|
+
this.db.run("PRAGMA busy_timeout = 5000");
|
|
237
|
+
} catch {}
|
|
238
|
+
this.db.run(`
|
|
239
|
+
CREATE TABLE IF NOT EXISTS lark_session_card (
|
|
240
|
+
session_id TEXT PRIMARY KEY,
|
|
241
|
+
message_id TEXT NOT NULL,
|
|
242
|
+
chat_id TEXT NOT NULL,
|
|
243
|
+
profile TEXT,
|
|
244
|
+
created_at INTEGER NOT NULL,
|
|
245
|
+
updated_at INTEGER NOT NULL
|
|
246
|
+
)
|
|
247
|
+
`);
|
|
248
|
+
}
|
|
249
|
+
upsert(rec) {
|
|
250
|
+
this.db.prepare(`INSERT INTO lark_session_card
|
|
251
|
+
(session_id, message_id, chat_id, profile, created_at, updated_at)
|
|
252
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
253
|
+
ON CONFLICT(session_id) DO UPDATE SET
|
|
254
|
+
message_id = excluded.message_id,
|
|
255
|
+
chat_id = excluded.chat_id,
|
|
256
|
+
profile = COALESCE(excluded.profile, lark_session_card.profile),
|
|
257
|
+
updated_at = excluded.updated_at`).run(rec.sessionId, rec.messageId, rec.chatId, rec.profile ?? null, rec.createdAt, rec.updatedAt);
|
|
258
|
+
}
|
|
259
|
+
get(sessionId) {
|
|
260
|
+
const row = this.db.prepare("SELECT * FROM lark_session_card WHERE session_id = ?").get(sessionId);
|
|
261
|
+
if (!row)
|
|
262
|
+
return;
|
|
263
|
+
return {
|
|
264
|
+
sessionId: row.session_id,
|
|
265
|
+
messageId: row.message_id,
|
|
266
|
+
chatId: row.chat_id,
|
|
267
|
+
...row.profile ? { profile: row.profile } : {},
|
|
268
|
+
createdAt: row.created_at,
|
|
269
|
+
updatedAt: row.updated_at
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
list() {
|
|
273
|
+
const rows = this.db.prepare("SELECT * FROM lark_session_card ORDER BY updated_at DESC").all();
|
|
274
|
+
return rows.map((row) => ({
|
|
275
|
+
sessionId: row.session_id,
|
|
276
|
+
messageId: row.message_id,
|
|
277
|
+
chatId: row.chat_id,
|
|
278
|
+
...row.profile ? { profile: row.profile } : {},
|
|
279
|
+
createdAt: row.created_at,
|
|
280
|
+
updatedAt: row.updated_at
|
|
281
|
+
}));
|
|
282
|
+
}
|
|
283
|
+
delete(sessionId) {
|
|
284
|
+
this.db.prepare("DELETE FROM lark_session_card WHERE session_id = ?").run(sessionId);
|
|
285
|
+
}
|
|
286
|
+
close() {
|
|
287
|
+
try {
|
|
288
|
+
this.db.close?.();
|
|
289
|
+
} catch {}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function createLarkSessionCardStore(dbPath) {
|
|
293
|
+
const isTestEnv = "BUN_TEST_WORKER_ID" in process.env;
|
|
294
|
+
if (!dbPath && isTestEnv)
|
|
295
|
+
return new MemoryLarkSessionCardStore;
|
|
296
|
+
const path = dbPath ?? getDefaultLarkCardDbPath();
|
|
297
|
+
try {
|
|
298
|
+
return new SqliteLarkSessionCardStore(path);
|
|
299
|
+
} catch (err) {
|
|
300
|
+
logger.warn(`LarkSessionCardStore: sqlite unavailable at ${path} (${err.message}) ` + `→ falling back to in-memory (卡片仍可发,但重启后无法认领旧卡)`);
|
|
301
|
+
return new MemoryLarkSessionCardStore;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
var sharedSessionCardStore;
|
|
305
|
+
function getSharedLarkSessionCardStore() {
|
|
306
|
+
if (!sharedSessionCardStore) {
|
|
307
|
+
sharedSessionCardStore = createLarkSessionCardStore();
|
|
308
|
+
}
|
|
309
|
+
return sharedSessionCardStore;
|
|
310
|
+
}
|
|
311
|
+
|
|
13
312
|
// src/env/task/plugins/lark-card-patch-notifier.ts
|
|
14
313
|
init_logger();
|
|
15
314
|
init_decorator();
|
|
16
|
-
|
|
17
|
-
var logger = createLogger("lark-cli:card-patch-notifier");
|
|
315
|
+
var logger2 = createLogger("lark-cli:card-patch-notifier");
|
|
18
316
|
var HEADER_TEMPLATE = {
|
|
19
317
|
running: "blue",
|
|
20
318
|
completed: "green",
|
|
21
319
|
failed: "red",
|
|
22
320
|
stopped: "grey",
|
|
23
321
|
cancelled: "grey",
|
|
24
|
-
deleted: "grey"
|
|
322
|
+
deleted: "grey",
|
|
323
|
+
to_validate: "turquoise"
|
|
25
324
|
};
|
|
26
325
|
var STATUS_PHRASE = {
|
|
27
326
|
running: "实时同步中",
|
|
@@ -29,7 +328,8 @@ var STATUS_PHRASE = {
|
|
|
29
328
|
failed: "\uD83D\uDEA8 任务失败",
|
|
30
329
|
stopped: "⏹️ 已停止",
|
|
31
330
|
cancelled: "\uD83D\uDEAB 已取消",
|
|
32
|
-
deleted: "\uD83D\uDDD1️ 已删除"
|
|
331
|
+
deleted: "\uD83D\uDDD1️ 已删除",
|
|
332
|
+
to_validate: "\uD83D\uDD0D 待验证"
|
|
33
333
|
};
|
|
34
334
|
var FINAL_MILESTONE_TITLE = {
|
|
35
335
|
running: "Task 进行中",
|
|
@@ -37,7 +337,8 @@ var FINAL_MILESTONE_TITLE = {
|
|
|
37
337
|
failed: "Task 失败",
|
|
38
338
|
stopped: "Task 已暂停",
|
|
39
339
|
cancelled: "Task 已取消",
|
|
40
|
-
deleted: "Task 已删除"
|
|
340
|
+
deleted: "Task 已删除",
|
|
341
|
+
to_validate: "Task 待验证"
|
|
41
342
|
};
|
|
42
343
|
var SPINNER_EMOJIS = ["⏳", "\uD83D\uDD04", "\uD83D\uDD03", "⌛", "⏰", "\uD83D\uDD01"];
|
|
43
344
|
var PROGRESS_BAR_CELLS = 20;
|
|
@@ -412,6 +713,7 @@ function buildTaskCard(opts) {
|
|
|
412
713
|
const elements = [];
|
|
413
714
|
const hasGroup = !!(opts.meta.perTaskChatId && opts.meta.perTaskChatId.length > 0);
|
|
414
715
|
const taskIdForButton = opts.meta.id !== undefined ? String(opts.meta.id) : "";
|
|
716
|
+
const sessionIdForButton = typeof opts.meta.sessionId === "string" && opts.meta.sessionId.trim() ? opts.meta.sessionId : undefined;
|
|
415
717
|
elements.push({
|
|
416
718
|
tag: "button",
|
|
417
719
|
text: {
|
|
@@ -421,9 +723,22 @@ function buildTaskCard(opts) {
|
|
|
421
723
|
type: hasGroup ? "danger" : "primary",
|
|
422
724
|
value: {
|
|
423
725
|
action: hasGroup ? "disband_group" : "create_group",
|
|
424
|
-
taskId: taskIdForButton
|
|
726
|
+
taskId: taskIdForButton,
|
|
727
|
+
...sessionIdForButton ? { sessionId: sessionIdForButton } : {}
|
|
425
728
|
}
|
|
426
729
|
});
|
|
730
|
+
if (taskIdForButton) {
|
|
731
|
+
elements.push({
|
|
732
|
+
tag: "button",
|
|
733
|
+
text: { tag: "plain_text", content: "\uD83D\uDCAC 会话查看" },
|
|
734
|
+
type: "default",
|
|
735
|
+
value: {
|
|
736
|
+
action: "refresh_activity",
|
|
737
|
+
taskId: taskIdForButton,
|
|
738
|
+
...sessionIdForButton ? { sessionId: sessionIdForButton } : {}
|
|
739
|
+
}
|
|
740
|
+
});
|
|
741
|
+
}
|
|
427
742
|
if (hasGroup) {
|
|
428
743
|
const link = buildChatAppLink(opts.meta.perTaskChatId);
|
|
429
744
|
const label = opts.meta.perTaskChatName ? `\uD83D\uDCE8 进入专属群:${sanitizeInlineText(opts.meta.perTaskChatName, 60)}` : "\uD83D\uDCE8 进入专属群";
|
|
@@ -443,6 +758,21 @@ function buildTaskCard(opts) {
|
|
|
443
758
|
}));
|
|
444
759
|
appendHr(elements);
|
|
445
760
|
}
|
|
761
|
+
if (opts.activity !== undefined) {
|
|
762
|
+
elements.push(buildCollapsiblePanel({
|
|
763
|
+
title: "⚡ 子会话活性",
|
|
764
|
+
elementId: "task_activity",
|
|
765
|
+
expanded: true,
|
|
766
|
+
elements: [
|
|
767
|
+
{
|
|
768
|
+
tag: "markdown",
|
|
769
|
+
content: formatActivityLines(opts.activity ?? undefined, opts.activityNow ?? Date.now(), opts.activityTerminal ?? false).join(`
|
|
770
|
+
`)
|
|
771
|
+
}
|
|
772
|
+
]
|
|
773
|
+
}));
|
|
774
|
+
appendHr(elements);
|
|
775
|
+
}
|
|
446
776
|
const timeline = buildTimelineElements(milestones, processSteps);
|
|
447
777
|
if (timeline.elements.length > 0) {
|
|
448
778
|
elements.push(buildCollapsiblePanel({
|
|
@@ -476,6 +806,200 @@ function buildTaskCard(opts) {
|
|
|
476
806
|
body: { elements }
|
|
477
807
|
};
|
|
478
808
|
}
|
|
809
|
+
function buildSessionCard(opts) {
|
|
810
|
+
const sessionId = opts.sessionId;
|
|
811
|
+
const updateCount = opts.updateCount ?? 1;
|
|
812
|
+
const spinner = SPINNER_EMOJIS[updateCount % SPINNER_EMOJIS.length];
|
|
813
|
+
const elements = [];
|
|
814
|
+
const taskIdNum = opts.task?.id;
|
|
815
|
+
const hasTaskId = typeof taskIdNum === "number" && taskIdNum > 0;
|
|
816
|
+
const hasGroup = !!(opts.perTaskChatId && opts.perTaskChatId.length > 0);
|
|
817
|
+
elements.push({
|
|
818
|
+
tag: "button",
|
|
819
|
+
text: {
|
|
820
|
+
tag: "plain_text",
|
|
821
|
+
content: hasGroup ? "解散该群" : hasTaskId ? "为这个任务建群" : "为本会话建群"
|
|
822
|
+
},
|
|
823
|
+
type: hasGroup ? "danger" : "primary",
|
|
824
|
+
value: {
|
|
825
|
+
action: hasGroup ? "disband_group" : "create_group",
|
|
826
|
+
sessionId,
|
|
827
|
+
...hasTaskId ? { taskId: String(taskIdNum) } : {}
|
|
828
|
+
}
|
|
829
|
+
});
|
|
830
|
+
if (hasGroup) {
|
|
831
|
+
elements.push({
|
|
832
|
+
tag: "markdown",
|
|
833
|
+
content: `[\uD83D\uDCE8 进入专属群](${buildChatAppLink(opts.perTaskChatId)})`
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
elements.push({
|
|
837
|
+
tag: "button",
|
|
838
|
+
text: { tag: "plain_text", content: "\uD83D\uDCAC 会话查看" },
|
|
839
|
+
type: "default",
|
|
840
|
+
value: {
|
|
841
|
+
action: "refresh_activity",
|
|
842
|
+
sessionId,
|
|
843
|
+
...hasTaskId ? { taskId: String(taskIdNum) } : {}
|
|
844
|
+
}
|
|
845
|
+
});
|
|
846
|
+
const infoLines = [];
|
|
847
|
+
infoLines.push(`- **\uD83C\uDD94 会话 ID**:${sanitizeInlineText(sessionId, 120)}`);
|
|
848
|
+
if (opts.title)
|
|
849
|
+
infoLines.push(`- **\uD83D\uDCDD 标题**:${sanitizeInlineText(opts.title, 120)}`);
|
|
850
|
+
if (opts.agentType) {
|
|
851
|
+
infoLines.push(`- **\uD83E\uDD16 执行 Agent**:${sanitizeInlineText(opts.agentType, 60)}`);
|
|
852
|
+
}
|
|
853
|
+
if (opts.startedAt) {
|
|
854
|
+
infoLines.push(`- **\uD83D\uDD50 开始时间**:${formatDateTimeForDisplay(opts.startedAt)}`);
|
|
855
|
+
}
|
|
856
|
+
if (opts.elapsedText)
|
|
857
|
+
infoLines.push(`- **⏳ 已运行**:${opts.elapsedText}`);
|
|
858
|
+
if (infoLines.length > 0) {
|
|
859
|
+
elements.push(buildCollapsiblePanel({
|
|
860
|
+
title: "\uD83D\uDCCB 会话详情",
|
|
861
|
+
elementId: "session_detail",
|
|
862
|
+
elements: [{ tag: "markdown", content: infoLines.join(`
|
|
863
|
+
`) }]
|
|
864
|
+
}));
|
|
865
|
+
appendHr(elements);
|
|
866
|
+
}
|
|
867
|
+
const taskInfo = opts.task;
|
|
868
|
+
if (taskInfo) {
|
|
869
|
+
const taskLines = [];
|
|
870
|
+
taskLines.push(`- **\uD83C\uDD94 任务 ID**:#${taskInfo.id}`);
|
|
871
|
+
if (taskInfo.title) {
|
|
872
|
+
taskLines.push(`- **\uD83D\uDCCC 标题**:${sanitizeInlineText(taskInfo.title, 120)}`);
|
|
873
|
+
}
|
|
874
|
+
if (taskInfo.status) {
|
|
875
|
+
taskLines.push(`- **\uD83D\uDEA6 状态**:${sanitizeInlineText(taskInfo.status, 40)}`);
|
|
876
|
+
}
|
|
877
|
+
if (typeof taskInfo.progress === "number") {
|
|
878
|
+
taskLines.push(`- **\uD83D\uDCCA 进度**:${renderProgressBar(taskInfo.progress)}`);
|
|
879
|
+
}
|
|
880
|
+
if (taskInfo.currentStatus) {
|
|
881
|
+
taskLines.push(`- **\uD83D\uDCDD 当前状态**:${sanitizeInlineText(taskInfo.currentStatus, 200)}`);
|
|
882
|
+
}
|
|
883
|
+
if (taskInfo.priority) {
|
|
884
|
+
taskLines.push(`- **\uD83D\uDD25 优先级**:${sanitizeInlineText(taskInfo.priority, 20)}`);
|
|
885
|
+
}
|
|
886
|
+
if (taskInfo.parentTaskId !== undefined) {
|
|
887
|
+
taskLines.push(`- **\uD83E\uDDE9 父任务**:#${taskInfo.parentTaskId}`);
|
|
888
|
+
}
|
|
889
|
+
if (taskInfo.goals) {
|
|
890
|
+
taskLines.push(`- **\uD83C\uDFAF 目标**:${sanitizeInlineText(taskInfo.goals, 200)}`);
|
|
891
|
+
}
|
|
892
|
+
if (taskInfo.createdAt) {
|
|
893
|
+
taskLines.push(`- **\uD83D\uDD50 创建时间**:${formatDateTimeForDisplay(taskInfo.createdAt)}`);
|
|
894
|
+
}
|
|
895
|
+
if (taskInfo.updatedAt) {
|
|
896
|
+
taskLines.push(`- **\uD83D\uDD04 更新时间**:${formatDateTimeForDisplay(taskInfo.updatedAt)}`);
|
|
897
|
+
}
|
|
898
|
+
elements.push(buildCollapsiblePanel({
|
|
899
|
+
title: "\uD83D\uDCCB 任务信息",
|
|
900
|
+
elementId: "task_detail",
|
|
901
|
+
elements: [{ tag: "markdown", content: taskLines.join(`
|
|
902
|
+
`) }]
|
|
903
|
+
}));
|
|
904
|
+
appendHr(elements);
|
|
905
|
+
if (taskInfo.milestones && taskInfo.milestones.length > 0) {
|
|
906
|
+
elements.push(buildCollapsiblePanel({
|
|
907
|
+
title: `\uD83D\uDCCC 操作记录(${taskInfo.milestones.length})`,
|
|
908
|
+
elementId: "task_timeline",
|
|
909
|
+
expanded: false,
|
|
910
|
+
elements: [
|
|
911
|
+
{ tag: "markdown", content: renderMilestones(taskInfo.milestones) }
|
|
912
|
+
]
|
|
913
|
+
}));
|
|
914
|
+
appendHr(elements);
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
if (opts.activity !== undefined) {
|
|
918
|
+
elements.push(buildCollapsiblePanel({
|
|
919
|
+
title: "⚡ 子会话活性",
|
|
920
|
+
elementId: "task_activity",
|
|
921
|
+
expanded: true,
|
|
922
|
+
elements: [
|
|
923
|
+
{
|
|
924
|
+
tag: "markdown",
|
|
925
|
+
content: formatActivityLines(opts.activity ?? undefined, opts.activityNow ?? Date.now(), isSessionLifecycleTerminal(opts.lifecycle)).join(`
|
|
926
|
+
`)
|
|
927
|
+
}
|
|
928
|
+
]
|
|
929
|
+
}));
|
|
930
|
+
appendHr(elements);
|
|
931
|
+
}
|
|
932
|
+
if (opts.recentMessages !== undefined) {
|
|
933
|
+
elements.push(buildCollapsiblePanel({
|
|
934
|
+
title: "\uD83D\uDD27 最近工具调用",
|
|
935
|
+
elementId: "session_recent_messages",
|
|
936
|
+
expanded: true,
|
|
937
|
+
elements: [
|
|
938
|
+
{
|
|
939
|
+
tag: "markdown",
|
|
940
|
+
content: formatRecentToolCallLines(opts.recentMessages).join(`
|
|
941
|
+
`)
|
|
942
|
+
}
|
|
943
|
+
]
|
|
944
|
+
}));
|
|
945
|
+
appendHr(elements);
|
|
946
|
+
}
|
|
947
|
+
const milestones = opts.milestones ?? [];
|
|
948
|
+
if (milestones.length > 0) {
|
|
949
|
+
elements.push(buildCollapsiblePanel({
|
|
950
|
+
title: `\uD83D\uDCCC 执行动态(${milestones.length})`,
|
|
951
|
+
elementId: "session_timeline",
|
|
952
|
+
expanded: false,
|
|
953
|
+
elements: [{ tag: "markdown", content: renderMilestones(milestones) }]
|
|
954
|
+
}));
|
|
955
|
+
}
|
|
956
|
+
const titleRaw = opts.title?.trim();
|
|
957
|
+
const headLabel = titleRaw ? truncateHeadTitle(titleRaw) : truncateHeadTitle(sessionId);
|
|
958
|
+
const lifecycle = opts.lifecycle ?? "running";
|
|
959
|
+
const lifecyclePhrase = opts.statusPhrase ?? SESSION_LIFECYCLE_PHRASE[lifecycle];
|
|
960
|
+
const headerTemplate = lifecycle === "running" ? HEADER_TEMPLATE.running : lifecycle === "completed" ? HEADER_TEMPLATE.completed : lifecycle === "stopped" ? HEADER_TEMPLATE.stopped : HEADER_TEMPLATE.failed;
|
|
961
|
+
return {
|
|
962
|
+
schema: "2.0",
|
|
963
|
+
header: {
|
|
964
|
+
title: { tag: "plain_text", content: `\uD83D\uDCCA 子会话实时更新(${headLabel})` },
|
|
965
|
+
subtitle: {
|
|
966
|
+
tag: "plain_text",
|
|
967
|
+
content: `spinner: '${spinner}' · 第 ${updateCount} 次更新 | ${lifecyclePhrase}`
|
|
968
|
+
},
|
|
969
|
+
template: headerTemplate
|
|
970
|
+
},
|
|
971
|
+
body: { elements }
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
function isSessionLifecycleTerminal(lifecycle) {
|
|
975
|
+
return lifecycle !== undefined && lifecycle !== "running";
|
|
976
|
+
}
|
|
977
|
+
function cardStatusToSessionLifecycle(status) {
|
|
978
|
+
switch (status) {
|
|
979
|
+
case "completed":
|
|
980
|
+
return "completed";
|
|
981
|
+
case "failed":
|
|
982
|
+
return "failed";
|
|
983
|
+
case "stopped":
|
|
984
|
+
case "cancelled":
|
|
985
|
+
case "deleted":
|
|
986
|
+
case "paused":
|
|
987
|
+
case "archived":
|
|
988
|
+
case "blocked":
|
|
989
|
+
return "stopped";
|
|
990
|
+
case "timeout":
|
|
991
|
+
return "timeout";
|
|
992
|
+
default:
|
|
993
|
+
return "running";
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
var SESSION_LIFECYCLE_PHRASE = {
|
|
997
|
+
running: "运行中",
|
|
998
|
+
completed: "已完成",
|
|
999
|
+
timeout: "已超时",
|
|
1000
|
+
failed: "已失败",
|
|
1001
|
+
stopped: "已停止"
|
|
1002
|
+
};
|
|
479
1003
|
function buildChatAppLink(chatId, base = DEFAULT_APP_LINK_BASE) {
|
|
480
1004
|
return `${base}/client/chat/open?openChatId=${chatId}`;
|
|
481
1005
|
}
|
|
@@ -626,11 +1150,14 @@ class LarkCardPatchNotifier {
|
|
|
626
1150
|
mutexes = new Map;
|
|
627
1151
|
states = new Map;
|
|
628
1152
|
workflowStates = new Map;
|
|
1153
|
+
sessionStates = new Map;
|
|
1154
|
+
sessionStore;
|
|
629
1155
|
constructor(options = {}) {
|
|
1156
|
+
this.sessionStore = options.sessionCardStore === null ? undefined : options.sessionCardStore ?? getSharedLarkSessionCardStore();
|
|
630
1157
|
this.options = {
|
|
631
1158
|
pinOnStart: true,
|
|
632
|
-
unpinOnFinish:
|
|
633
|
-
...options
|
|
1159
|
+
unpinOnFinish: false,
|
|
1160
|
+
...(({ sessionCardStore: _scs, ...rest }) => rest)(options)
|
|
634
1161
|
};
|
|
635
1162
|
}
|
|
636
1163
|
mutexFor(messageId) {
|
|
@@ -676,7 +1203,7 @@ class LarkCardPatchNotifier {
|
|
|
676
1203
|
pinned = true;
|
|
677
1204
|
} catch (pinErr) {
|
|
678
1205
|
pinError = pinErr.message;
|
|
679
|
-
|
|
1206
|
+
logger2.warn(`Pin failed (non-fatal) for message ${messageId}: ${pinError}`);
|
|
680
1207
|
}
|
|
681
1208
|
}
|
|
682
1209
|
return { messageId, pinned, pinError };
|
|
@@ -684,7 +1211,23 @@ class LarkCardPatchNotifier {
|
|
|
684
1211
|
async updateTask(opts) {
|
|
685
1212
|
await this.mutexFor(opts.messageId).run(async () => {
|
|
686
1213
|
if (this.finalisedCards.has(opts.messageId)) {
|
|
687
|
-
|
|
1214
|
+
logger2.debug(`updateTask: message ${opts.messageId} 已是终态卡片,忽略迟到的更新`);
|
|
1215
|
+
return;
|
|
1216
|
+
}
|
|
1217
|
+
if (this.sessionStates.has(opts.messageId)) {
|
|
1218
|
+
const card2 = this.applyTaskEventToSessionCard(opts.messageId, {
|
|
1219
|
+
...opts.milestones ? { milestones: opts.milestones } : {},
|
|
1220
|
+
...opts.processSteps ? { processSteps: opts.processSteps } : {},
|
|
1221
|
+
...opts.meta ? { meta: opts.meta } : {},
|
|
1222
|
+
...opts.status ? { status: opts.status } : {},
|
|
1223
|
+
...opts.status ? { lifecycle: cardStatusToSessionLifecycle(opts.status) } : {},
|
|
1224
|
+
...opts.progress !== undefined ? { progress: opts.progress } : {}
|
|
1225
|
+
});
|
|
1226
|
+
await this.runLarkCli(this.buildPatchCardArgs({
|
|
1227
|
+
messageId: opts.messageId,
|
|
1228
|
+
profile: opts.profile,
|
|
1229
|
+
card: card2
|
|
1230
|
+
}), "patch");
|
|
688
1231
|
return;
|
|
689
1232
|
}
|
|
690
1233
|
const state = this.states.get(opts.messageId) ?? {
|
|
@@ -769,6 +1312,29 @@ class LarkCardPatchNotifier {
|
|
|
769
1312
|
}
|
|
770
1313
|
async pauseTask(opts) {
|
|
771
1314
|
await this.mutexFor(opts.messageId).run(async () => {
|
|
1315
|
+
if (this.sessionStates.has(opts.messageId)) {
|
|
1316
|
+
const now2 = new Date().toISOString();
|
|
1317
|
+
const pauseMilestone2 = {
|
|
1318
|
+
title: opts.pausedMilestoneTitle ?? "Task 已暂停",
|
|
1319
|
+
timestamp: now2,
|
|
1320
|
+
description: opts.finalStep
|
|
1321
|
+
};
|
|
1322
|
+
const card2 = this.applyTaskEventToSessionCard(opts.messageId, {
|
|
1323
|
+
milestones: [pauseMilestone2],
|
|
1324
|
+
...opts.processSteps ? { processSteps: opts.processSteps } : {},
|
|
1325
|
+
...opts.meta ? { meta: opts.meta } : {},
|
|
1326
|
+
...opts.status ? { status: opts.status } : {},
|
|
1327
|
+
...opts.status ? { lifecycle: cardStatusToSessionLifecycle(opts.status) } : {},
|
|
1328
|
+
...opts.progress !== undefined ? { progress: opts.progress } : {},
|
|
1329
|
+
nowIso: now2
|
|
1330
|
+
});
|
|
1331
|
+
await this.runLarkCli(this.buildPatchCardArgs({
|
|
1332
|
+
messageId: opts.messageId,
|
|
1333
|
+
profile: opts.profile,
|
|
1334
|
+
card: card2
|
|
1335
|
+
}), "patch");
|
|
1336
|
+
return;
|
|
1337
|
+
}
|
|
772
1338
|
const state = this.states.get(opts.messageId);
|
|
773
1339
|
const now = new Date().toISOString();
|
|
774
1340
|
const updateCount = (state?.updateCount ?? 0) + 1;
|
|
@@ -813,7 +1379,7 @@ class LarkCardPatchNotifier {
|
|
|
813
1379
|
profile: opts.profile ?? state?.profile
|
|
814
1380
|
}), "unpin");
|
|
815
1381
|
} catch (unpinErr) {
|
|
816
|
-
|
|
1382
|
+
logger2.warn(`Unpin failed (non-fatal) for ${opts.messageId}: ${unpinErr.message}`);
|
|
817
1383
|
}
|
|
818
1384
|
}
|
|
819
1385
|
}
|
|
@@ -825,6 +1391,30 @@ class LarkCardPatchNotifier {
|
|
|
825
1391
|
}
|
|
826
1392
|
async finishTask(opts) {
|
|
827
1393
|
await this.mutexFor(opts.messageId).run(async () => {
|
|
1394
|
+
if (this.sessionStates.has(opts.messageId)) {
|
|
1395
|
+
const now2 = new Date().toISOString();
|
|
1396
|
+
const finalMilestone2 = {
|
|
1397
|
+
title: FINAL_MILESTONE_TITLE[opts.status] ?? "Task 结束",
|
|
1398
|
+
timestamp: now2,
|
|
1399
|
+
description: opts.finalStep
|
|
1400
|
+
};
|
|
1401
|
+
const card2 = this.applyTaskEventToSessionCard(opts.messageId, {
|
|
1402
|
+
milestones: [finalMilestone2],
|
|
1403
|
+
...opts.processSteps ? { processSteps: opts.processSteps } : {},
|
|
1404
|
+
...opts.meta ? { meta: opts.meta } : {},
|
|
1405
|
+
...opts.status ? { status: opts.status } : {},
|
|
1406
|
+
...opts.status ? { lifecycle: cardStatusToSessionLifecycle(opts.status) } : {},
|
|
1407
|
+
progress: opts.status === "completed" ? 100 : opts.progress,
|
|
1408
|
+
nowIso: now2
|
|
1409
|
+
});
|
|
1410
|
+
await this.runLarkCli(this.buildPatchCardArgs({
|
|
1411
|
+
messageId: opts.messageId,
|
|
1412
|
+
profile: opts.profile,
|
|
1413
|
+
card: card2
|
|
1414
|
+
}), "patch");
|
|
1415
|
+
this.finalisedCards.add(opts.messageId);
|
|
1416
|
+
return;
|
|
1417
|
+
}
|
|
828
1418
|
const state = this.states.get(opts.messageId);
|
|
829
1419
|
const now = new Date().toISOString();
|
|
830
1420
|
const updateCount = (state?.updateCount ?? 0) + 1;
|
|
@@ -859,13 +1449,22 @@ class LarkCardPatchNotifier {
|
|
|
859
1449
|
profile: opts.profile ?? state?.profile
|
|
860
1450
|
}), "unpin");
|
|
861
1451
|
} catch (unpinErr) {
|
|
862
|
-
|
|
1452
|
+
logger2.warn(`Unpin failed (non-fatal) for ${opts.messageId}: ${unpinErr.message}`);
|
|
863
1453
|
}
|
|
864
1454
|
}
|
|
865
1455
|
this.states.delete(opts.messageId);
|
|
866
1456
|
this.mutexes.delete(opts.messageId);
|
|
867
1457
|
}
|
|
868
1458
|
updateMetaAndBuildCard(messageId, meta, opts = {}) {
|
|
1459
|
+
if (this.sessionStates.has(messageId)) {
|
|
1460
|
+
return this.applyTaskEventToSessionCard(messageId, {
|
|
1461
|
+
meta,
|
|
1462
|
+
bumpUpdateCount: false,
|
|
1463
|
+
...opts.clearPerTaskChat ? { clearPerTaskChat: true } : {},
|
|
1464
|
+
...meta.perTaskChatId ? { perTaskChatId: meta.perTaskChatId } : {},
|
|
1465
|
+
...meta.perTaskChatName ? { perTaskChatName: meta.perTaskChatName } : {}
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
869
1468
|
const state = this.states.get(messageId);
|
|
870
1469
|
if (!state)
|
|
871
1470
|
return;
|
|
@@ -884,7 +1483,416 @@ class LarkCardPatchNotifier {
|
|
|
884
1483
|
spinner: SPINNER_EMOJIS[state.spinnerIndex] ?? SPINNER_EMOJIS[0]
|
|
885
1484
|
});
|
|
886
1485
|
}
|
|
1486
|
+
buildCardWithActivity(messageId, activity, opts = {}) {
|
|
1487
|
+
const state = this.states.get(messageId);
|
|
1488
|
+
if (!state)
|
|
1489
|
+
return;
|
|
1490
|
+
return buildTaskCard({
|
|
1491
|
+
status: "running",
|
|
1492
|
+
meta: state.meta,
|
|
1493
|
+
milestones: state.milestones,
|
|
1494
|
+
processSteps: state.processSteps,
|
|
1495
|
+
progress: state.progress,
|
|
1496
|
+
updateCount: state.updateCount,
|
|
1497
|
+
spinner: SPINNER_EMOJIS[state.spinnerIndex] ?? SPINNER_EMOJIS[0],
|
|
1498
|
+
activity,
|
|
1499
|
+
...opts.now !== undefined ? { activityNow: opts.now } : {},
|
|
1500
|
+
...opts.terminal !== undefined ? { activityTerminal: opts.terminal } : {}
|
|
1501
|
+
});
|
|
1502
|
+
}
|
|
1503
|
+
async updateSessionCard(opts) {
|
|
1504
|
+
const rec = this.findSessionCardBySessionId(opts.sessionId);
|
|
1505
|
+
if (!rec)
|
|
1506
|
+
return false;
|
|
1507
|
+
const { messageId, state } = rec;
|
|
1508
|
+
const mergedMilestones = mergeUnique(state.milestones, opts.milestones ?? [], milestoneKey);
|
|
1509
|
+
const updateCount = state.updateCount + 1;
|
|
1510
|
+
const card = buildSessionCard({
|
|
1511
|
+
sessionId: opts.sessionId,
|
|
1512
|
+
title: state.title,
|
|
1513
|
+
statusPhrase: state.statusPhrase,
|
|
1514
|
+
agentType: state.agentType,
|
|
1515
|
+
startedAt: state.startedAt,
|
|
1516
|
+
elapsedText: state.elapsedText,
|
|
1517
|
+
milestones: mergedMilestones,
|
|
1518
|
+
lifecycle: opts.lifecycle,
|
|
1519
|
+
updateCount,
|
|
1520
|
+
...opts.activity !== undefined ? { activity: opts.activity } : state.activity !== undefined ? { activity: state.activity } : {},
|
|
1521
|
+
...opts.task !== undefined ? { task: opts.task } : state.task !== undefined ? { task: state.task } : {},
|
|
1522
|
+
...opts.recentMessages !== undefined ? { recentMessages: opts.recentMessages } : state.recentMessages !== undefined ? { recentMessages: state.recentMessages } : {},
|
|
1523
|
+
...opts.perTaskChatId ?? state.perTaskChatId ? { perTaskChatId: opts.perTaskChatId ?? state.perTaskChatId } : {},
|
|
1524
|
+
...opts.perTaskChatName ?? state.perTaskChatName ? { perTaskChatName: opts.perTaskChatName ?? state.perTaskChatName } : {}
|
|
1525
|
+
});
|
|
1526
|
+
await this.runLarkCli(this.buildPatchCardArgs({
|
|
1527
|
+
messageId,
|
|
1528
|
+
profile: opts.profile ?? state.profile,
|
|
1529
|
+
card
|
|
1530
|
+
}), "patch");
|
|
1531
|
+
this.sessionStates.set(messageId, {
|
|
1532
|
+
...state,
|
|
1533
|
+
milestones: mergedMilestones,
|
|
1534
|
+
updateCount,
|
|
1535
|
+
lifecycle: opts.lifecycle,
|
|
1536
|
+
...opts.activity !== undefined ? { activity: opts.activity } : {},
|
|
1537
|
+
...opts.task !== undefined ? { task: opts.task } : {},
|
|
1538
|
+
...opts.perTaskChatId ? { perTaskChatId: opts.perTaskChatId } : {},
|
|
1539
|
+
...opts.perTaskChatName ? { perTaskChatName: opts.perTaskChatName } : {}
|
|
1540
|
+
});
|
|
1541
|
+
this.sessionCardIds.set(opts.sessionId, messageId);
|
|
1542
|
+
if (typeof opts.task?.id === "number") {
|
|
1543
|
+
this.taskToSessionId.set(opts.task.id, opts.sessionId);
|
|
1544
|
+
}
|
|
1545
|
+
return true;
|
|
1546
|
+
}
|
|
1547
|
+
sessionCardIds = new Map;
|
|
1548
|
+
taskToSessionId = new Map;
|
|
1549
|
+
findSessionCardBySessionId(sessionId) {
|
|
1550
|
+
const messageId = this.sessionCardIds.get(sessionId);
|
|
1551
|
+
if (!messageId)
|
|
1552
|
+
return;
|
|
1553
|
+
const state = this.sessionStates.get(messageId);
|
|
1554
|
+
if (!state)
|
|
1555
|
+
return;
|
|
1556
|
+
return { messageId, state };
|
|
1557
|
+
}
|
|
1558
|
+
isSessionCardMessage(messageId) {
|
|
1559
|
+
return this.sessionStates.has(messageId);
|
|
1560
|
+
}
|
|
1561
|
+
applyTaskEventToSessionCard(messageId, delta) {
|
|
1562
|
+
const state = this.sessionStates.get(messageId);
|
|
1563
|
+
if (!state) {
|
|
1564
|
+
throw new Error(`applyTaskEventToSessionCard: ${messageId} 不是 session 卡(调用方应先 isSessionCardMessage)`);
|
|
1565
|
+
}
|
|
1566
|
+
const nowIso = delta.nowIso ?? new Date().toISOString();
|
|
1567
|
+
const stepsAsMilestones = (delta.processSteps ?? []).filter((s) => typeof s.title === "string" && s.title.trim() !== "").map((s) => ({
|
|
1568
|
+
title: s.title,
|
|
1569
|
+
...s.timestamp ? { timestamp: s.timestamp } : {},
|
|
1570
|
+
...s.description ? { description: s.description } : {}
|
|
1571
|
+
}));
|
|
1572
|
+
const mergedMilestones = mergeUnique(state.milestones ?? [], [...delta.milestones ?? [], ...stepsAsMilestones], milestoneKey);
|
|
1573
|
+
const prevTask = state.task;
|
|
1574
|
+
const metaId = delta.meta?.id;
|
|
1575
|
+
const metaIdNum = typeof metaId === "number" ? metaId : typeof metaId === "string" && metaId.trim() !== "" ? Number(metaId) : undefined;
|
|
1576
|
+
const hasTaskDelta = delta.meta !== undefined || delta.status !== undefined || delta.progress !== undefined;
|
|
1577
|
+
const hasValidTaskId = typeof metaIdNum === "number" && Number.isFinite(metaIdNum) && metaIdNum > 0;
|
|
1578
|
+
const shouldRenderTaskPanel = hasValidTaskId || prevTask !== undefined;
|
|
1579
|
+
const nextTask = hasTaskDelta && shouldRenderTaskPanel ? {
|
|
1580
|
+
id: typeof metaIdNum === "number" && Number.isFinite(metaIdNum) ? metaIdNum : prevTask?.id ?? 0,
|
|
1581
|
+
...delta.meta?.title ?? prevTask?.title ? { title: delta.meta?.title ?? prevTask?.title } : {},
|
|
1582
|
+
...delta.status ?? prevTask?.status ? { status: delta.status ?? prevTask?.status } : {},
|
|
1583
|
+
...delta.progress !== undefined || prevTask?.progress !== undefined ? { progress: delta.progress ?? prevTask?.progress } : {},
|
|
1584
|
+
...delta.meta?.currentStatus ?? prevTask?.currentStatus ? { currentStatus: delta.meta?.currentStatus ?? prevTask?.currentStatus } : {},
|
|
1585
|
+
...delta.meta?.priority ?? prevTask?.priority ? { priority: delta.meta?.priority ?? prevTask?.priority } : {},
|
|
1586
|
+
...delta.meta?.parentTaskId !== undefined || prevTask?.parentTaskId !== undefined ? { parentTaskId: delta.meta?.parentTaskId ?? prevTask?.parentTaskId } : {},
|
|
1587
|
+
...delta.meta?.goals ?? prevTask?.goals ? { goals: delta.meta?.goals ?? prevTask?.goals } : {},
|
|
1588
|
+
...prevTask?.createdAt ? { createdAt: prevTask.createdAt } : {},
|
|
1589
|
+
...prevTask?.updatedAt ? { updatedAt: prevTask.updatedAt } : {},
|
|
1590
|
+
...prevTask?.milestones ? { milestones: prevTask.milestones } : {}
|
|
1591
|
+
} : prevTask;
|
|
1592
|
+
const perTaskChatId = delta.clearPerTaskChat ? undefined : delta.perTaskChatId ?? state.perTaskChatId;
|
|
1593
|
+
const perTaskChatName = delta.clearPerTaskChat ? undefined : delta.perTaskChatName ?? state.perTaskChatName;
|
|
1594
|
+
const lifecycle = delta.lifecycle ?? state.lifecycle ?? "running";
|
|
1595
|
+
const bump = delta.bumpUpdateCount !== false;
|
|
1596
|
+
const updateCount = bump ? (state.updateCount ?? 1) + 1 : state.updateCount ?? 1;
|
|
1597
|
+
const card = buildSessionCard({
|
|
1598
|
+
sessionId: state.sessionId ?? "",
|
|
1599
|
+
title: state.title,
|
|
1600
|
+
statusPhrase: state.statusPhrase,
|
|
1601
|
+
agentType: state.agentType,
|
|
1602
|
+
startedAt: state.startedAt,
|
|
1603
|
+
elapsedText: state.elapsedText,
|
|
1604
|
+
milestones: mergedMilestones,
|
|
1605
|
+
lifecycle,
|
|
1606
|
+
updateCount,
|
|
1607
|
+
...delta.activity !== undefined ? { activity: delta.activity } : state.activity !== undefined ? { activity: state.activity } : {},
|
|
1608
|
+
...state.recentMessages !== undefined ? { recentMessages: state.recentMessages } : {},
|
|
1609
|
+
...nextTask !== undefined ? { task: nextTask } : {},
|
|
1610
|
+
...perTaskChatId ? { perTaskChatId } : {},
|
|
1611
|
+
...perTaskChatName ? { perTaskChatName } : {}
|
|
1612
|
+
});
|
|
1613
|
+
this.sessionStates.set(messageId, {
|
|
1614
|
+
...state,
|
|
1615
|
+
milestones: mergedMilestones,
|
|
1616
|
+
updateCount,
|
|
1617
|
+
lifecycle,
|
|
1618
|
+
...nextTask !== undefined ? { task: nextTask } : {},
|
|
1619
|
+
...perTaskChatId ? { perTaskChatId } : { perTaskChatId: undefined },
|
|
1620
|
+
...perTaskChatName ? { perTaskChatName } : { perTaskChatName: undefined },
|
|
1621
|
+
...delta.activity !== undefined ? { activity: delta.activity } : {}
|
|
1622
|
+
});
|
|
1623
|
+
return card;
|
|
1624
|
+
}
|
|
1625
|
+
bindTaskToSession(taskId, sessionId) {
|
|
1626
|
+
if (!Number.isFinite(taskId) || taskId <= 0)
|
|
1627
|
+
return;
|
|
1628
|
+
if (typeof sessionId !== "string" || !sessionId.trim())
|
|
1629
|
+
return;
|
|
1630
|
+
this.taskToSessionId.set(taskId, sessionId);
|
|
1631
|
+
}
|
|
1632
|
+
adoptSessionCard(sessionId, messageId, state) {
|
|
1633
|
+
if (!sessionId || !messageId)
|
|
1634
|
+
return;
|
|
1635
|
+
this.sessionCardIds.set(sessionId, messageId);
|
|
1636
|
+
this.rememberSessionCard(messageId, {
|
|
1637
|
+
sessionId,
|
|
1638
|
+
...state ?? {}
|
|
1639
|
+
});
|
|
1640
|
+
}
|
|
1641
|
+
persistSessionCardRecord(sessionId, messageId, chatId, profile) {
|
|
1642
|
+
if (!this.sessionStore)
|
|
1643
|
+
return;
|
|
1644
|
+
try {
|
|
1645
|
+
const now = Date.now();
|
|
1646
|
+
const existing = this.sessionStore.get(sessionId);
|
|
1647
|
+
this.sessionStore.upsert({
|
|
1648
|
+
sessionId,
|
|
1649
|
+
messageId,
|
|
1650
|
+
chatId,
|
|
1651
|
+
...profile ?? existing?.profile ? { profile: profile ?? existing?.profile } : {},
|
|
1652
|
+
createdAt: existing?.createdAt ?? now,
|
|
1653
|
+
updatedAt: now
|
|
1654
|
+
});
|
|
1655
|
+
} catch (err) {
|
|
1656
|
+
logger2.warn(`persistSessionCardRecord failed for ${sessionId}: ${err.message}`);
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
restoreSessionCardsFromStore() {
|
|
1660
|
+
if (!this.sessionStore)
|
|
1661
|
+
return 0;
|
|
1662
|
+
let n = 0;
|
|
1663
|
+
try {
|
|
1664
|
+
for (const rec of this.sessionStore.list()) {
|
|
1665
|
+
if (!rec.sessionId || !rec.messageId)
|
|
1666
|
+
continue;
|
|
1667
|
+
if (this.sessionCardIds.has(rec.sessionId))
|
|
1668
|
+
continue;
|
|
1669
|
+
this.sessionCardIds.set(rec.sessionId, rec.messageId);
|
|
1670
|
+
if (!this.sessionStates.has(rec.messageId)) {
|
|
1671
|
+
this.sessionStates.set(rec.messageId, {
|
|
1672
|
+
...rec.profile ? { profile: rec.profile } : {},
|
|
1673
|
+
sessionId: rec.sessionId,
|
|
1674
|
+
milestones: [],
|
|
1675
|
+
updateCount: 1
|
|
1676
|
+
});
|
|
1677
|
+
}
|
|
1678
|
+
n += 1;
|
|
1679
|
+
}
|
|
1680
|
+
} catch (err) {
|
|
1681
|
+
logger2.warn(`restoreSessionCardsFromStore failed: ${err.message}`);
|
|
1682
|
+
}
|
|
1683
|
+
if (n > 0) {
|
|
1684
|
+
logger2.info(`restoreSessionCardsFromStore: 回灌 ${n} 张 session 卡`);
|
|
1685
|
+
}
|
|
1686
|
+
return n;
|
|
1687
|
+
}
|
|
1688
|
+
applySessionGroupChange(messageId, opts) {
|
|
1689
|
+
const state = this.sessionStates.get(messageId);
|
|
1690
|
+
if (!state)
|
|
1691
|
+
return;
|
|
1692
|
+
const chatId = opts.perTaskChatId?.trim();
|
|
1693
|
+
if (chatId) {
|
|
1694
|
+
state.perTaskChatId = chatId;
|
|
1695
|
+
if (opts.perTaskChatName)
|
|
1696
|
+
state.perTaskChatName = opts.perTaskChatName;
|
|
1697
|
+
} else {
|
|
1698
|
+
delete state.perTaskChatId;
|
|
1699
|
+
delete state.perTaskChatName;
|
|
1700
|
+
}
|
|
1701
|
+
return buildSessionCard({
|
|
1702
|
+
sessionId: opts.sessionId,
|
|
1703
|
+
title: state.title,
|
|
1704
|
+
statusPhrase: state.statusPhrase,
|
|
1705
|
+
agentType: state.agentType,
|
|
1706
|
+
startedAt: state.startedAt,
|
|
1707
|
+
elapsedText: state.elapsedText,
|
|
1708
|
+
milestones: state.milestones,
|
|
1709
|
+
updateCount: state.updateCount,
|
|
1710
|
+
lifecycle: state.lifecycle,
|
|
1711
|
+
...state.activity !== undefined ? { activity: state.activity } : {},
|
|
1712
|
+
...state.recentMessages !== undefined ? { recentMessages: state.recentMessages } : {},
|
|
1713
|
+
...state.task !== undefined ? { task: state.task } : {},
|
|
1714
|
+
...state.perTaskChatId ? { perTaskChatId: state.perTaskChatId } : {},
|
|
1715
|
+
...state.perTaskChatName ? { perTaskChatName: state.perTaskChatName } : {}
|
|
1716
|
+
});
|
|
1717
|
+
}
|
|
1718
|
+
getSessionIdByTask(taskId) {
|
|
1719
|
+
if (!Number.isFinite(taskId))
|
|
1720
|
+
return;
|
|
1721
|
+
return this.taskToSessionId.get(taskId);
|
|
1722
|
+
}
|
|
1723
|
+
getSessionCardMessageId(sessionId) {
|
|
1724
|
+
return this.sessionCardIds.get(sessionId);
|
|
1725
|
+
}
|
|
1726
|
+
getSessionCardState(sessionId) {
|
|
1727
|
+
const messageId = this.sessionCardIds.get(sessionId);
|
|
1728
|
+
if (!messageId)
|
|
1729
|
+
return;
|
|
1730
|
+
return this.sessionStates.get(messageId);
|
|
1731
|
+
}
|
|
1732
|
+
async syncGroupCardFromOrigin(originSessionId, opts, findGroupSession) {
|
|
1733
|
+
if (!findGroupSession)
|
|
1734
|
+
return false;
|
|
1735
|
+
let chatId;
|
|
1736
|
+
try {
|
|
1737
|
+
const group = await findGroupSession(originSessionId);
|
|
1738
|
+
chatId = group?.chatId;
|
|
1739
|
+
} catch (err) {
|
|
1740
|
+
logger2.warn(`syncGroupCardFromOrigin: findGroupChatForSession(${originSessionId}) 失败(跳过双写): ` + `${err.message}`);
|
|
1741
|
+
return false;
|
|
1742
|
+
}
|
|
1743
|
+
if (!chatId || chatId === originSessionId)
|
|
1744
|
+
return false;
|
|
1745
|
+
try {
|
|
1746
|
+
await this.upsertSessionCard({
|
|
1747
|
+
chatId,
|
|
1748
|
+
sessionId: chatId,
|
|
1749
|
+
lifecycle: opts.lifecycle ?? "running",
|
|
1750
|
+
...opts.title ? { title: opts.title } : {},
|
|
1751
|
+
...opts.milestones ? { milestones: opts.milestones } : {}
|
|
1752
|
+
});
|
|
1753
|
+
return true;
|
|
1754
|
+
} catch (err) {
|
|
1755
|
+
logger2.warn(`syncGroupCardFromOrigin: 群卡同步失败(chatId=${chatId}): ` + `${err.message}`);
|
|
1756
|
+
return false;
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
async upsertSessionCard(opts) {
|
|
1760
|
+
const mutex = this.sessionUpsertMutexes.get(opts.sessionId) ?? new MutexImpl;
|
|
1761
|
+
this.sessionUpsertMutexes.set(opts.sessionId, mutex);
|
|
1762
|
+
const result = await mutex.run(async () => {
|
|
1763
|
+
const patched = await this.updateSessionCard(opts);
|
|
1764
|
+
if (patched) {
|
|
1765
|
+
const messageId = this.sessionCardIds.get(opts.sessionId);
|
|
1766
|
+
return { messageId, created: false };
|
|
1767
|
+
}
|
|
1768
|
+
const res = await this.startSessionCard(opts);
|
|
1769
|
+
return { messageId: res.messageId, created: true };
|
|
1770
|
+
});
|
|
1771
|
+
if (opts.lifecycle !== "running") {
|
|
1772
|
+
this.sessionUpsertMutexes.delete(opts.sessionId);
|
|
1773
|
+
}
|
|
1774
|
+
return result;
|
|
1775
|
+
}
|
|
1776
|
+
sessionUpsertMutexes = new Map;
|
|
1777
|
+
async startSessionCard(opts) {
|
|
1778
|
+
const card = buildSessionCard({
|
|
1779
|
+
sessionId: opts.sessionId,
|
|
1780
|
+
title: opts.title,
|
|
1781
|
+
statusPhrase: opts.statusPhrase,
|
|
1782
|
+
agentType: opts.agentType,
|
|
1783
|
+
startedAt: opts.startedAt,
|
|
1784
|
+
elapsedText: opts.elapsedText,
|
|
1785
|
+
milestones: opts.milestones,
|
|
1786
|
+
lifecycle: opts.lifecycle,
|
|
1787
|
+
updateCount: 1,
|
|
1788
|
+
...opts.activity !== undefined ? { activity: opts.activity } : {},
|
|
1789
|
+
...opts.task !== undefined ? { task: opts.task } : {},
|
|
1790
|
+
...opts.perTaskChatId ? { perTaskChatId: opts.perTaskChatId } : {},
|
|
1791
|
+
...opts.perTaskChatName ? { perTaskChatName: opts.perTaskChatName } : {}
|
|
1792
|
+
});
|
|
1793
|
+
const stdout = await this.runLarkCli(this.buildSendCardArgs({ chatId: opts.chatId, profile: opts.profile, card }), "send");
|
|
1794
|
+
const messageId = this.extractMessageId(stdout);
|
|
1795
|
+
if (!messageId) {
|
|
1796
|
+
throw new Error(`lark-cli +messages-send did not return message_id: ${stdout.slice(0, 500)}`);
|
|
1797
|
+
}
|
|
1798
|
+
this.sessionCardIds.set(opts.sessionId, messageId);
|
|
1799
|
+
if (typeof opts.task?.id === "number" && opts.task.id > 0) {
|
|
1800
|
+
this.taskToSessionId.set(opts.task.id, opts.sessionId);
|
|
1801
|
+
}
|
|
1802
|
+
this.rememberSessionCard(messageId, {
|
|
1803
|
+
profile: opts.profile,
|
|
1804
|
+
sessionId: opts.sessionId,
|
|
1805
|
+
title: opts.title,
|
|
1806
|
+
statusPhrase: opts.statusPhrase,
|
|
1807
|
+
agentType: opts.agentType,
|
|
1808
|
+
startedAt: opts.startedAt,
|
|
1809
|
+
elapsedText: opts.elapsedText,
|
|
1810
|
+
milestones: opts.milestones ?? [],
|
|
1811
|
+
updateCount: 1,
|
|
1812
|
+
lifecycle: opts.lifecycle,
|
|
1813
|
+
...opts.activity !== undefined ? { activity: opts.activity } : {},
|
|
1814
|
+
...opts.task !== undefined ? { task: opts.task } : {},
|
|
1815
|
+
...opts.perTaskChatId ? { perTaskChatId: opts.perTaskChatId } : {},
|
|
1816
|
+
...opts.perTaskChatName ? { perTaskChatName: opts.perTaskChatName } : {}
|
|
1817
|
+
});
|
|
1818
|
+
let pinned = false;
|
|
1819
|
+
let pinError;
|
|
1820
|
+
if (this.options.pinOnStart) {
|
|
1821
|
+
try {
|
|
1822
|
+
await this.pinMessage(messageId, opts.profile);
|
|
1823
|
+
pinned = true;
|
|
1824
|
+
} catch (err) {
|
|
1825
|
+
pinError = err.message;
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
this.persistSessionCardRecord(opts.sessionId, messageId, opts.chatId, opts.profile);
|
|
1829
|
+
return { messageId, pinned, ...pinError ? { pinError } : {} };
|
|
1830
|
+
}
|
|
1831
|
+
buildSessionCardWithActivity(messageId, sessionId, activity, opts = {}) {
|
|
1832
|
+
const state = this.sessionStates.get(messageId);
|
|
1833
|
+
if (!state)
|
|
1834
|
+
return;
|
|
1835
|
+
const card = buildSessionCard({
|
|
1836
|
+
sessionId,
|
|
1837
|
+
title: state.title,
|
|
1838
|
+
statusPhrase: state.statusPhrase,
|
|
1839
|
+
agentType: state.agentType,
|
|
1840
|
+
startedAt: state.startedAt,
|
|
1841
|
+
elapsedText: state.elapsedText,
|
|
1842
|
+
milestones: state.milestones,
|
|
1843
|
+
updateCount: state.updateCount,
|
|
1844
|
+
activity,
|
|
1845
|
+
...opts.lifecycle !== undefined ? { lifecycle: opts.lifecycle } : state.lifecycle !== undefined ? { lifecycle: state.lifecycle } : {},
|
|
1846
|
+
...opts.task !== undefined ? { task: opts.task } : state.task !== undefined ? { task: state.task } : {},
|
|
1847
|
+
...state.perTaskChatId ? { perTaskChatId: state.perTaskChatId } : {},
|
|
1848
|
+
...state.perTaskChatName ? { perTaskChatName: state.perTaskChatName } : {},
|
|
1849
|
+
...opts.recentMessages !== undefined ? { recentMessages: opts.recentMessages } : state.recentMessages !== undefined ? { recentMessages: state.recentMessages } : {},
|
|
1850
|
+
...opts.now !== undefined ? { activityNow: opts.now } : {}
|
|
1851
|
+
});
|
|
1852
|
+
if (opts.task !== undefined) {
|
|
1853
|
+
this.rememberSessionCard(messageId, { task: opts.task });
|
|
1854
|
+
if (typeof opts.task.id === "number" && opts.task.id > 0) {
|
|
1855
|
+
this.taskToSessionId.set(opts.task.id, sessionId);
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
if (opts.recentMessages !== undefined) {
|
|
1859
|
+
this.rememberSessionCard(messageId, {
|
|
1860
|
+
recentMessages: opts.recentMessages
|
|
1861
|
+
});
|
|
1862
|
+
}
|
|
1863
|
+
if (opts.lifecycle !== undefined) {
|
|
1864
|
+
this.rememberSessionCard(messageId, { lifecycle: opts.lifecycle });
|
|
1865
|
+
}
|
|
1866
|
+
if (activity !== undefined) {
|
|
1867
|
+
this.rememberSessionCard(messageId, { activity });
|
|
1868
|
+
}
|
|
1869
|
+
return card;
|
|
1870
|
+
}
|
|
1871
|
+
rememberSessionCard(messageId, state) {
|
|
1872
|
+
const prev = this.sessionStates.get(messageId);
|
|
1873
|
+
this.sessionStates.set(messageId, {
|
|
1874
|
+
title: state.title ?? prev?.title,
|
|
1875
|
+
statusPhrase: state.statusPhrase ?? prev?.statusPhrase,
|
|
1876
|
+
agentType: state.agentType ?? prev?.agentType,
|
|
1877
|
+
startedAt: state.startedAt ?? prev?.startedAt,
|
|
1878
|
+
elapsedText: state.elapsedText ?? prev?.elapsedText,
|
|
1879
|
+
milestones: state.milestones ?? prev?.milestones ?? [],
|
|
1880
|
+
updateCount: state.updateCount ?? prev?.updateCount ?? 1,
|
|
1881
|
+
lifecycle: state.lifecycle ?? prev?.lifecycle,
|
|
1882
|
+
profile: state.profile ?? prev?.profile,
|
|
1883
|
+
sessionId: state.sessionId ?? prev?.sessionId,
|
|
1884
|
+
activity: state.activity !== undefined ? state.activity : prev?.activity,
|
|
1885
|
+
recentMessages: state.recentMessages !== undefined ? state.recentMessages : prev?.recentMessages,
|
|
1886
|
+
task: state.task ?? prev?.task,
|
|
1887
|
+
perTaskChatId: state.perTaskChatId ?? prev?.perTaskChatId,
|
|
1888
|
+
perTaskChatName: state.perTaskChatName ?? prev?.perTaskChatName
|
|
1889
|
+
});
|
|
1890
|
+
}
|
|
887
1891
|
finalisedCards = new Set;
|
|
1892
|
+
unfinaliseCard(messageId) {
|
|
1893
|
+
this.finalisedCards.delete(messageId);
|
|
1894
|
+
}
|
|
1895
|
+
testRunner;
|
|
888
1896
|
trackedCardCount() {
|
|
889
1897
|
return this.states.size;
|
|
890
1898
|
}
|
|
@@ -932,7 +1940,7 @@ class LarkCardPatchNotifier {
|
|
|
932
1940
|
pinned = true;
|
|
933
1941
|
} catch (pinErr) {
|
|
934
1942
|
pinError = pinErr.message;
|
|
935
|
-
|
|
1943
|
+
logger2.warn(`Pin failed (non-fatal) for workflow message ${messageId}: ${pinError}`);
|
|
936
1944
|
}
|
|
937
1945
|
}
|
|
938
1946
|
return { messageId, pinned, pinError };
|
|
@@ -940,7 +1948,7 @@ class LarkCardPatchNotifier {
|
|
|
940
1948
|
async updateWorkflow(opts) {
|
|
941
1949
|
await this.mutexFor(opts.messageId).run(async () => {
|
|
942
1950
|
if (this.finalisedCards.has(opts.messageId)) {
|
|
943
|
-
|
|
1951
|
+
logger2.debug(`updateWorkflow: message ${opts.messageId} 已是终态卡片,忽略迟到的更新`);
|
|
944
1952
|
return;
|
|
945
1953
|
}
|
|
946
1954
|
const state = this.workflowStates.get(opts.messageId) ?? {
|
|
@@ -1045,7 +2053,7 @@ class LarkCardPatchNotifier {
|
|
|
1045
2053
|
profile: opts.profile ?? state?.profile
|
|
1046
2054
|
}), "unpin");
|
|
1047
2055
|
} catch (unpinErr) {
|
|
1048
|
-
|
|
2056
|
+
logger2.warn(`Unpin failed (non-fatal) for workflow ${opts.messageId}: ${unpinErr.message}`);
|
|
1049
2057
|
}
|
|
1050
2058
|
}
|
|
1051
2059
|
this.workflowStates.delete(opts.messageId);
|
|
@@ -1119,6 +2127,9 @@ class LarkCardPatchNotifier {
|
|
|
1119
2127
|
return args;
|
|
1120
2128
|
}
|
|
1121
2129
|
runLarkCli(argv, op) {
|
|
2130
|
+
if (this.testRunner) {
|
|
2131
|
+
return this.testRunner(argv, op);
|
|
2132
|
+
}
|
|
1122
2133
|
return new Promise((resolve, reject) => {
|
|
1123
2134
|
if (process.env.ROY_HOOK_DEBUG === "1") {
|
|
1124
2135
|
console.error(`[DEBUG LarkCardPatchNotifier.runLarkCli] op=${op} args=${JSON.stringify(argv).slice(0, 300)}`);
|
|
@@ -1362,5 +2373,17 @@ function sanitize(text) {
|
|
|
1362
2373
|
return trimmed;
|
|
1363
2374
|
return `${trimmed.slice(0, 500)}…`;
|
|
1364
2375
|
}
|
|
2376
|
+
var sharedNotifier;
|
|
2377
|
+
function getSharedLarkCardNotifier() {
|
|
2378
|
+
if (!sharedNotifier)
|
|
2379
|
+
sharedNotifier = new LarkCardPatchNotifier;
|
|
2380
|
+
return sharedNotifier;
|
|
2381
|
+
}
|
|
2382
|
+
function __resetSharedLarkCardNotifierForTest() {
|
|
2383
|
+
sharedNotifier = undefined;
|
|
2384
|
+
}
|
|
2385
|
+
function hasSharedLarkCardNotifier() {
|
|
2386
|
+
return sharedNotifier !== undefined;
|
|
2387
|
+
}
|
|
1365
2388
|
|
|
1366
|
-
export { formatTimestampForDisplay, sanitizeInlineText, HEAD_TITLE_MAX_WIDTH, truncateHeadTitle, formatDateTimeForDisplay, renderProgressBar, resolveTaskTitleForDisplay, humanizeValue, isTerminalStatusForTimeline, isTerminalStatusForWorkflowTimeline, buildCollapsiblePanel, renderTaskInfoLines, renderContextAsLines, renderMilestones, renderProcessSteps, partitionProcessSteps, buildTaskCard, buildChatAppLink, DEFAULT_APP_LINK_BASE, formatDurationMs, renderWorkflowInfoLines, buildWorkflowCard, LarkCardPatchNotifier };
|
|
2389
|
+
export { MemoryLarkCardStateStore, SqliteLarkCardStateStore, getDefaultLarkCardDbPath, createLarkCardStateStore, getSharedLarkCardStateStore, formatTimestampForDisplay, sanitizeInlineText, HEAD_TITLE_MAX_WIDTH, truncateHeadTitle, formatDateTimeForDisplay, renderProgressBar, resolveTaskTitleForDisplay, humanizeValue, isTerminalStatusForTimeline, isTerminalStatusForWorkflowTimeline, buildCollapsiblePanel, renderTaskInfoLines, renderContextAsLines, renderMilestones, renderProcessSteps, partitionProcessSteps, buildTaskCard, buildSessionCard, buildChatAppLink, DEFAULT_APP_LINK_BASE, formatDurationMs, renderWorkflowInfoLines, buildWorkflowCard, LarkCardPatchNotifier, getSharedLarkCardNotifier, __resetSharedLarkCardNotifierForTest, hasSharedLarkCardNotifier };
|