@ai-setting/roy-agent-core 1.7.56 → 1.7.58
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/index.js +8 -8
- package/dist/env/agent/agent-component.d.ts +11 -0
- package/dist/env/agent/index.js +14 -14
- package/dist/env/commands/index.js +8 -8
- package/dist/env/context/index.js +4 -4
- package/dist/env/debug/index.js +8 -8
- package/dist/env/error-reply.d.ts +4 -3
- package/dist/env/event-source/event-source-handlers.d.ts +28 -0
- package/dist/env/event-source/index.js +18 -17
- package/dist/env/hook/index.js +6 -6
- package/dist/env/index.js +44 -43
- package/dist/env/llm/index.js +9 -9
- package/dist/env/log-trace/index.js +8 -8
- package/dist/env/log-trace/opentelemetry/tracer-provider.d.ts +86 -1
- package/dist/env/mcp/index.js +9 -9
- package/dist/env/mcp/tool/index.js +2 -2
- package/dist/env/memory/index.js +9 -9
- package/dist/env/memory/plugin/index.js +2 -2
- package/dist/env/plugin/index.js +11 -9
- package/dist/env/plugin/lark-cli-notification-channel.d.ts +11 -2
- package/dist/env/prompt/index.js +8 -8
- package/dist/env/session/index.js +11 -11
- package/dist/env/session/storage/index.js +5 -5
- package/dist/env/skill/index.js +8 -8
- package/dist/env/task/delegate/delegate-tool.d.ts +26 -0
- package/dist/env/task/delegate/index.js +9 -9
- package/dist/env/task/index.js +18 -17
- package/dist/env/task/plugins/index.js +11 -10
- package/dist/env/task/plugins/lark-card-patch-notifier.d.ts +109 -2
- package/dist/env/task/plugins/lark-card-state-store.d.ts +137 -0
- package/dist/env/task/plugins/lark-cli-task-notify-plugin.d.ts +154 -2
- package/dist/env/task/storage/index.js +4 -3
- package/dist/env/task/tools/index.js +4 -4
- package/dist/env/tool/built-in/index.js +4 -4
- package/dist/env/tool/index.js +11 -11
- package/dist/env/workflow/engine/index.js +13 -13
- package/dist/env/workflow/hooks/index.js +8 -8
- package/dist/env/workflow/index.js +23 -23
- package/dist/env/workflow/nodes/index.js +3 -3
- package/dist/env/workflow/plugins/index.js +9 -9
- package/dist/env/workflow/service/index.js +3 -3
- package/dist/env/workflow/storage/index.js +4 -4
- package/dist/env/workflow/tools/index.js +15 -15
- package/dist/env/workflow/utils/index.js +5 -5
- package/dist/index.js +58 -57
- package/dist/shared/@ai-setting/{roy-agent-core-0b3fdnn3.js → roy-agent-core-029r8kdw.js} +4 -4
- package/dist/shared/@ai-setting/{roy-agent-core-nra8vfrs.js → roy-agent-core-08njdcpj.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-40xzbjtm.js → roy-agent-core-0kn3zt1t.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-nhk0dsxr.js → roy-agent-core-0yn7a78e.js} +14 -14
- package/dist/shared/@ai-setting/{roy-agent-core-tbrn9wdm.js → roy-agent-core-14bq77wr.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-qyqnmz8c.js → roy-agent-core-20m8je6e.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-zmeka63k.js → roy-agent-core-2ctyjy62.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-heft3j4c.js → roy-agent-core-2fk8c9ax.js} +3 -3
- package/dist/shared/@ai-setting/{roy-agent-core-8cgtwytv.js → roy-agent-core-4096f575.js} +4 -4
- package/dist/shared/@ai-setting/{roy-agent-core-yg247mk4.js → roy-agent-core-47s81t6g.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-q7zksbw0.js → roy-agent-core-5f7myqnb.js} +5 -5
- package/dist/shared/@ai-setting/{roy-agent-core-vmg30n5x.js → roy-agent-core-6bradb0j.js} +15 -10
- package/dist/shared/@ai-setting/{roy-agent-core-zjttt2y4.js → roy-agent-core-7nb23tdd.js} +1 -1
- package/dist/shared/@ai-setting/roy-agent-core-7q4wdze2.js +7 -0
- package/dist/shared/@ai-setting/{roy-agent-core-d4jpn06f.js → roy-agent-core-84rs0c8d.js} +7 -7
- package/dist/shared/@ai-setting/{roy-agent-core-c6at31ra.js → roy-agent-core-84xtww7d.js} +3 -3
- package/dist/shared/@ai-setting/{roy-agent-core-202v00x4.js → roy-agent-core-89sxsrc7.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-ezsyyjxw.js → roy-agent-core-8bngppw0.js} +580 -83
- package/dist/shared/@ai-setting/{roy-agent-core-b599jgyd.js → roy-agent-core-8p63s836.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-e0wbq0qq.js → roy-agent-core-991pk4ss.js} +11 -11
- package/dist/shared/@ai-setting/{roy-agent-core-5rxs0ra3.js → roy-agent-core-9zhkdg6w.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-gn8f4rhs.js → roy-agent-core-baaa4wtp.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-nntphgww.js → roy-agent-core-c36335nw.js} +146 -8
- package/dist/shared/@ai-setting/{roy-agent-core-tc7gw38m.js → roy-agent-core-c7w2h47a.js} +3 -3
- package/dist/shared/@ai-setting/{roy-agent-core-j5c3chtn.js → roy-agent-core-cyefe8z5.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-n3b7ztms.js → roy-agent-core-d75t8gea.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-yv9x4wmg.js → roy-agent-core-e1w17tht.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-f8sp1txg.js → roy-agent-core-e250355z.js} +3 -3
- package/dist/shared/@ai-setting/{roy-agent-core-9nv586rw.js → roy-agent-core-eanq305k.js} +22 -16
- package/dist/shared/@ai-setting/{roy-agent-core-6qgq7h1g.js → roy-agent-core-em4hks9t.js} +4 -4
- package/dist/shared/@ai-setting/{roy-agent-core-0bmk44ye.js → roy-agent-core-en2xqxs9.js} +5 -5
- package/dist/shared/@ai-setting/{roy-agent-core-3kz6934b.js → roy-agent-core-fbjd7bt6.js} +3 -7
- package/dist/shared/@ai-setting/{roy-agent-core-98aa9r0x.js → roy-agent-core-fw6k4w1h.js} +6 -6
- package/dist/shared/@ai-setting/{roy-agent-core-2044fbsd.js → roy-agent-core-fy4mcj6x.js} +40 -47
- package/dist/shared/@ai-setting/{roy-agent-core-ns3pbyz4.js → roy-agent-core-ge87xbas.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-r9qe0ghe.js → roy-agent-core-geh6j7bw.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-wafk25ff.js → roy-agent-core-gksw1gjb.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-3dkzqqsd.js → roy-agent-core-hefarcp0.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-5gw6w424.js → roy-agent-core-hs41gx9w.js} +5 -5
- package/dist/shared/@ai-setting/{roy-agent-core-d14h726p.js → roy-agent-core-jjhw9am6.js} +4 -4
- package/dist/shared/@ai-setting/{roy-agent-core-5psjwd08.js → roy-agent-core-jjxdmedn.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-bwzy00t2.js → roy-agent-core-kq9pz2a7.js} +4 -4
- package/dist/shared/@ai-setting/{roy-agent-core-8t7wny6v.js → roy-agent-core-m68z3pw1.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-16t0zfbk.js → roy-agent-core-m97jn2ra.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-kzg1jwt8.js → roy-agent-core-n0p0hwgd.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-xcq04fq0.js → roy-agent-core-psg6f1v6.js} +6 -6
- package/dist/shared/@ai-setting/{roy-agent-core-4zy2v3br.js → roy-agent-core-q4gdfypk.js} +3 -3
- package/dist/shared/@ai-setting/{roy-agent-core-m8n0dffe.js → roy-agent-core-rcgvmtms.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-8seq65bp.js → roy-agent-core-rt115qfc.js} +44 -1
- package/dist/shared/@ai-setting/{roy-agent-core-jszgaevt.js → roy-agent-core-syyw58p9.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-3mc6vmvj.js → roy-agent-core-t4x089js.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-qjjf4tjb.js → roy-agent-core-t64nmayv.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-833t16n1.js → roy-agent-core-txwptxk1.js} +3 -3
- package/dist/shared/@ai-setting/{roy-agent-core-w7hnjhvx.js → roy-agent-core-tze5596n.js} +3 -3
- package/dist/shared/@ai-setting/{roy-agent-core-pjxa78mp.js → roy-agent-core-vath15kt.js} +6 -6
- package/dist/shared/@ai-setting/{roy-agent-core-e677am8e.js → roy-agent-core-vgdhxbx3.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-pemxr5n4.js → roy-agent-core-vh0qzb24.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-v2188rnk.js → roy-agent-core-w93z6a42.js} +8 -8
- package/dist/shared/@ai-setting/{roy-agent-core-97eyghsp.js → roy-agent-core-ygn5tzt1.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-1pnfkspm.js → roy-agent-core-yphwdm9x.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-gngjkw3b.js → roy-agent-core-ytd5eztz.js} +1 -1
- package/dist/utils/temp-file-manager/index.js +2 -2
- package/package.json +1 -1
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createCompatibleDatabase,
|
|
3
|
+
init_sqlite_task_store
|
|
4
|
+
} from "./roy-agent-core-fbjd7bt6.js";
|
|
1
5
|
import {
|
|
2
6
|
getSharedEventStore
|
|
3
|
-
} from "./roy-agent-core-
|
|
7
|
+
} from "./roy-agent-core-2ctyjy62.js";
|
|
4
8
|
import {
|
|
5
9
|
TaskHookPoints
|
|
6
10
|
} from "./roy-agent-core-1pg0fepg.js";
|
|
@@ -10,31 +14,31 @@ import {
|
|
|
10
14
|
import {
|
|
11
15
|
LarkCardPatchNotifier,
|
|
12
16
|
humanizeValue
|
|
13
|
-
} from "./roy-agent-core-
|
|
17
|
+
} from "./roy-agent-core-c36335nw.js";
|
|
14
18
|
import {
|
|
15
19
|
validateWorkflowDefinition
|
|
16
|
-
} from "./roy-agent-core-
|
|
20
|
+
} from "./roy-agent-core-89sxsrc7.js";
|
|
17
21
|
import {
|
|
18
22
|
enqueueToAddFakeUserMessage
|
|
19
|
-
} from "./roy-agent-core-
|
|
23
|
+
} from "./roy-agent-core-gksw1gjb.js";
|
|
20
24
|
import {
|
|
21
25
|
BasePlugin
|
|
22
26
|
} from "./roy-agent-core-az13yzmc.js";
|
|
23
27
|
import {
|
|
24
28
|
init_context
|
|
25
|
-
} from "./roy-agent-core-
|
|
29
|
+
} from "./roy-agent-core-m97jn2ra.js";
|
|
26
30
|
import {
|
|
27
31
|
getEnvContextOrEmpty
|
|
28
|
-
} from "./roy-agent-core-
|
|
32
|
+
} from "./roy-agent-core-syyw58p9.js";
|
|
29
33
|
import {
|
|
30
34
|
TracedAs,
|
|
31
35
|
init_decorator,
|
|
32
36
|
wrapFunction
|
|
33
|
-
} from "./roy-agent-core-
|
|
37
|
+
} from "./roy-agent-core-8p63s836.js";
|
|
34
38
|
import {
|
|
35
39
|
createLogger,
|
|
36
40
|
init_logger
|
|
37
|
-
} from "./roy-agent-core-
|
|
41
|
+
} from "./roy-agent-core-rt115qfc.js";
|
|
38
42
|
import {
|
|
39
43
|
__legacyDecorateClassTS,
|
|
40
44
|
__require
|
|
@@ -299,11 +303,11 @@ ${prompt}`;
|
|
|
299
303
|
}
|
|
300
304
|
if (!this._workflowRepo) {
|
|
301
305
|
try {
|
|
302
|
-
const sqlite = await import("./roy-agent-core-
|
|
306
|
+
const sqlite = await import("./roy-agent-core-4096f575.js");
|
|
303
307
|
this.ensureDataDir();
|
|
304
308
|
const db = sqlite.getDatabase();
|
|
305
309
|
sqlite.initializeTables();
|
|
306
|
-
const { WorkflowRepository } = await import("./roy-agent-core-
|
|
310
|
+
const { WorkflowRepository } = await import("./roy-agent-core-jjhw9am6.js");
|
|
307
311
|
this._workflowRepo = new WorkflowRepository(db);
|
|
308
312
|
return this._workflowRepo;
|
|
309
313
|
} catch {
|
|
@@ -377,6 +381,179 @@ init_decorator();
|
|
|
377
381
|
init_logger();
|
|
378
382
|
init_context();
|
|
379
383
|
|
|
384
|
+
// src/env/task/plugins/lark-card-state-store.ts
|
|
385
|
+
init_logger();
|
|
386
|
+
init_sqlite_task_store();
|
|
387
|
+
import { join } from "path";
|
|
388
|
+
var logger3 = createLogger("lark-cli:card-state");
|
|
389
|
+
|
|
390
|
+
class MemoryLarkCardStateStore {
|
|
391
|
+
records = new Map;
|
|
392
|
+
upsert(state) {
|
|
393
|
+
this.records.set(state.taskId, { ...state });
|
|
394
|
+
}
|
|
395
|
+
get(taskId) {
|
|
396
|
+
const r = this.records.get(taskId);
|
|
397
|
+
return r ? { ...r } : undefined;
|
|
398
|
+
}
|
|
399
|
+
list() {
|
|
400
|
+
return [...this.records.values()].map((r) => ({ ...r }));
|
|
401
|
+
}
|
|
402
|
+
markPinned(taskId, pinned) {
|
|
403
|
+
const r = this.records.get(taskId);
|
|
404
|
+
if (!r)
|
|
405
|
+
return;
|
|
406
|
+
r.pinned = pinned;
|
|
407
|
+
r.updatedAt = Date.now();
|
|
408
|
+
}
|
|
409
|
+
markPaused(taskId) {
|
|
410
|
+
const r = this.records.get(taskId);
|
|
411
|
+
if (!r)
|
|
412
|
+
return;
|
|
413
|
+
r.status = "paused";
|
|
414
|
+
r.updatedAt = Date.now();
|
|
415
|
+
}
|
|
416
|
+
markReopened(taskId) {
|
|
417
|
+
const r = this.records.get(taskId);
|
|
418
|
+
if (!r)
|
|
419
|
+
return;
|
|
420
|
+
r.status = "open";
|
|
421
|
+
delete r.closedAt;
|
|
422
|
+
r.updatedAt = Date.now();
|
|
423
|
+
}
|
|
424
|
+
markClosed(taskId) {
|
|
425
|
+
const r = this.records.get(taskId);
|
|
426
|
+
if (!r)
|
|
427
|
+
return;
|
|
428
|
+
const now = Date.now();
|
|
429
|
+
r.status = "closed";
|
|
430
|
+
r.closedAt = now;
|
|
431
|
+
r.updatedAt = now;
|
|
432
|
+
}
|
|
433
|
+
delete(taskId) {
|
|
434
|
+
this.records.delete(taskId);
|
|
435
|
+
}
|
|
436
|
+
close() {
|
|
437
|
+
this.records.clear();
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
function rowToState(row) {
|
|
441
|
+
const state = {
|
|
442
|
+
taskId: row.task_id,
|
|
443
|
+
messageId: row.message_id,
|
|
444
|
+
chatId: row.chat_id,
|
|
445
|
+
pinned: row.pinned === 1,
|
|
446
|
+
status: row.status ?? "open",
|
|
447
|
+
createdAt: row.created_at,
|
|
448
|
+
updatedAt: row.updated_at
|
|
449
|
+
};
|
|
450
|
+
if (row.profile)
|
|
451
|
+
state.profile = row.profile;
|
|
452
|
+
if (row.closed_at !== null && row.closed_at !== undefined) {
|
|
453
|
+
state.closedAt = row.closed_at;
|
|
454
|
+
}
|
|
455
|
+
if (row.timeline)
|
|
456
|
+
state.timeline = row.timeline;
|
|
457
|
+
return state;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
class SqliteLarkCardStateStore {
|
|
461
|
+
db;
|
|
462
|
+
constructor(dbPath) {
|
|
463
|
+
if (dbPath !== ":memory:") {
|
|
464
|
+
const { mkdirSync } = __require("fs");
|
|
465
|
+
const dir = __require("path").dirname(dbPath);
|
|
466
|
+
try {
|
|
467
|
+
mkdirSync(dir, { recursive: true });
|
|
468
|
+
} catch {}
|
|
469
|
+
}
|
|
470
|
+
this.db = createCompatibleDatabase(dbPath);
|
|
471
|
+
try {
|
|
472
|
+
this.db.run("PRAGMA journal_mode = WAL");
|
|
473
|
+
this.db.run("PRAGMA busy_timeout = 5000");
|
|
474
|
+
this.db.run("PRAGMA synchronous = NORMAL");
|
|
475
|
+
} catch {}
|
|
476
|
+
this.db.run(`
|
|
477
|
+
CREATE TABLE IF NOT EXISTS lark_card (
|
|
478
|
+
task_id INTEGER PRIMARY KEY,
|
|
479
|
+
message_id TEXT NOT NULL,
|
|
480
|
+
chat_id TEXT NOT NULL,
|
|
481
|
+
profile TEXT,
|
|
482
|
+
pinned INTEGER NOT NULL DEFAULT 0,
|
|
483
|
+
status TEXT NOT NULL DEFAULT 'open',
|
|
484
|
+
created_at INTEGER NOT NULL,
|
|
485
|
+
updated_at INTEGER NOT NULL,
|
|
486
|
+
closed_at INTEGER,
|
|
487
|
+
timeline TEXT
|
|
488
|
+
)
|
|
489
|
+
`);
|
|
490
|
+
try {
|
|
491
|
+
this.db.run("ALTER TABLE lark_card ADD COLUMN timeline TEXT");
|
|
492
|
+
} catch {}
|
|
493
|
+
this.db.run("CREATE INDEX IF NOT EXISTS idx_lark_card_status ON lark_card(status)");
|
|
494
|
+
}
|
|
495
|
+
upsert(state) {
|
|
496
|
+
this.db.prepare(`INSERT INTO lark_card
|
|
497
|
+
(task_id, message_id, chat_id, profile, pinned, status, created_at, updated_at, closed_at, timeline)
|
|
498
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
499
|
+
ON CONFLICT(task_id) DO UPDATE SET
|
|
500
|
+
message_id = excluded.message_id,
|
|
501
|
+
chat_id = excluded.chat_id,
|
|
502
|
+
profile = excluded.profile,
|
|
503
|
+
pinned = excluded.pinned,
|
|
504
|
+
status = excluded.status,
|
|
505
|
+
updated_at = excluded.updated_at,
|
|
506
|
+
closed_at = excluded.closed_at,
|
|
507
|
+
timeline = excluded.timeline`).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);
|
|
508
|
+
}
|
|
509
|
+
get(taskId) {
|
|
510
|
+
const row = this.db.prepare("SELECT * FROM lark_card WHERE task_id = ?").get(taskId);
|
|
511
|
+
return row ? rowToState(row) : undefined;
|
|
512
|
+
}
|
|
513
|
+
list() {
|
|
514
|
+
const rows = this.db.prepare("SELECT * FROM lark_card ORDER BY task_id ASC").all();
|
|
515
|
+
return rows.map(rowToState);
|
|
516
|
+
}
|
|
517
|
+
markPinned(taskId, pinned) {
|
|
518
|
+
this.db.prepare("UPDATE lark_card SET pinned = ?, updated_at = ? WHERE task_id = ?").run(pinned ? 1 : 0, Date.now(), taskId);
|
|
519
|
+
}
|
|
520
|
+
markPaused(taskId) {
|
|
521
|
+
this.db.prepare("UPDATE lark_card SET status = 'paused', updated_at = ? WHERE task_id = ?").run(Date.now(), taskId);
|
|
522
|
+
}
|
|
523
|
+
markReopened(taskId) {
|
|
524
|
+
this.db.prepare("UPDATE lark_card SET status = 'open', closed_at = NULL, updated_at = ? WHERE task_id = ?").run(Date.now(), taskId);
|
|
525
|
+
}
|
|
526
|
+
markClosed(taskId) {
|
|
527
|
+
const now = Date.now();
|
|
528
|
+
this.db.prepare("UPDATE lark_card SET status = 'closed', closed_at = ?, updated_at = ? WHERE task_id = ?").run(now, now, taskId);
|
|
529
|
+
}
|
|
530
|
+
delete(taskId) {
|
|
531
|
+
this.db.prepare("DELETE FROM lark_card WHERE task_id = ?").run(taskId);
|
|
532
|
+
}
|
|
533
|
+
close() {
|
|
534
|
+
try {
|
|
535
|
+
this.db.close?.();
|
|
536
|
+
} catch {}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
function getDefaultLarkCardDbPath() {
|
|
540
|
+
const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
|
|
541
|
+
return join(home, ".local", "share", "roy-agent", "lark-cards.db");
|
|
542
|
+
}
|
|
543
|
+
function createLarkCardStateStore(dbPath) {
|
|
544
|
+
const isTestEnv = "BUN_TEST_WORKER_ID" in process.env;
|
|
545
|
+
if (!dbPath && !process.env.ROY_AGENT_LARK_CARD_DB && isTestEnv) {
|
|
546
|
+
return new MemoryLarkCardStateStore;
|
|
547
|
+
}
|
|
548
|
+
const path = dbPath ?? process.env.ROY_AGENT_LARK_CARD_DB ?? getDefaultLarkCardDbPath();
|
|
549
|
+
try {
|
|
550
|
+
return new SqliteLarkCardStateStore(path);
|
|
551
|
+
} catch (err) {
|
|
552
|
+
logger3.warn(`LarkCardStateStore: sqlite unavailable at ${path} (${err.message}) ` + `→ falling back to in-memory (卡片仍可发,但重启后无法 patch 旧卡)`);
|
|
553
|
+
return new MemoryLarkCardStateStore;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
380
557
|
// src/env/task/plugins/card-chat-routing.ts
|
|
381
558
|
var CTX_FIELD_LARK_PER_TASK_CHAT_ID = "larkPerTaskChatId";
|
|
382
559
|
function extractPerTaskChatId(contextStr) {
|
|
@@ -454,7 +631,7 @@ function decideCardChatTarget(input) {
|
|
|
454
631
|
}
|
|
455
632
|
|
|
456
633
|
// src/env/task/plugins/lark-cli-task-notify-plugin.ts
|
|
457
|
-
var
|
|
634
|
+
var logger4 = createLogger("lark-cli:task-notify");
|
|
458
635
|
var CTX_FIELD_CHAT_ID = "larkPerTaskChatId";
|
|
459
636
|
var CTX_FIELD_CHAT_PROFILE = "larkPerTaskChatProfile";
|
|
460
637
|
function parseLarkPerTaskChatId(ctxStr) {
|
|
@@ -479,6 +656,23 @@ function parseLarkPerTaskChatProfile(ctxStr) {
|
|
|
479
656
|
return;
|
|
480
657
|
}
|
|
481
658
|
}
|
|
659
|
+
function isTerminalTaskStatus(status) {
|
|
660
|
+
return status === "completed" || status === "cancelled" || status === "failed" || status === "timeout" || status === "archived";
|
|
661
|
+
}
|
|
662
|
+
function mapTaskStatusToCardStatus(taskStatus) {
|
|
663
|
+
switch (taskStatus) {
|
|
664
|
+
case "cancelled":
|
|
665
|
+
return "cancelled";
|
|
666
|
+
case "paused":
|
|
667
|
+
case "archived":
|
|
668
|
+
return "stopped";
|
|
669
|
+
case "failed":
|
|
670
|
+
case "timeout":
|
|
671
|
+
return "failed";
|
|
672
|
+
default:
|
|
673
|
+
return "completed";
|
|
674
|
+
}
|
|
675
|
+
}
|
|
482
676
|
var NotifyType;
|
|
483
677
|
((NotifyType2) => {
|
|
484
678
|
NotifyType2["TASK_CREATED"] = "task_created";
|
|
@@ -497,6 +691,8 @@ class LarkCliTaskNotifyHook {
|
|
|
497
691
|
config;
|
|
498
692
|
cardNotifier;
|
|
499
693
|
cardMessageIds = new Map;
|
|
694
|
+
cardStateStore;
|
|
695
|
+
restoredTaskIds = new Set;
|
|
500
696
|
lastNotifyTimestamps = new Map;
|
|
501
697
|
cardRoutingPorts;
|
|
502
698
|
static CARD_START_FAILED_SENTINEL = "__card_start_failed__";
|
|
@@ -520,11 +716,12 @@ class LarkCliTaskNotifyHook {
|
|
|
520
716
|
};
|
|
521
717
|
if (this.config.cardMode !== false) {
|
|
522
718
|
this.cardNotifier = config.cardNotifier ?? new LarkCardPatchNotifier;
|
|
719
|
+
this.cardStateStore = config.cardStateStore ?? createLarkCardStateStore();
|
|
523
720
|
}
|
|
524
721
|
}
|
|
525
722
|
setCardRoutingPorts(ports) {
|
|
526
723
|
this.cardRoutingPorts = ports;
|
|
527
|
-
|
|
724
|
+
logger4.debug(`CardRoutingPorts injected: getTask=${typeof ports.getTask}`);
|
|
528
725
|
}
|
|
529
726
|
hasCardRoutingPorts() {
|
|
530
727
|
return this.cardRoutingPorts !== undefined;
|
|
@@ -537,7 +734,7 @@ class LarkCliTaskNotifyHook {
|
|
|
537
734
|
if (this.pluginName && this.sourceId) {
|
|
538
735
|
const key = `${this.sourceId}:${this.pluginName}`;
|
|
539
736
|
if (env.pluginEnabled && env.pluginEnabled[key] !== true) {
|
|
540
|
-
|
|
737
|
+
logger4.debug(`Plugin not enabled for source: ${key}`);
|
|
541
738
|
return;
|
|
542
739
|
}
|
|
543
740
|
}
|
|
@@ -554,6 +751,9 @@ class LarkCliTaskNotifyHook {
|
|
|
554
751
|
case TaskHookPoints.OPERATION_AFTER_CREATE:
|
|
555
752
|
await this.onAfterOperationCreate(ctx);
|
|
556
753
|
break;
|
|
754
|
+
case TaskHookPoints.AFTER_DELETE:
|
|
755
|
+
await this.onAfterDelete(ctx);
|
|
756
|
+
break;
|
|
557
757
|
}
|
|
558
758
|
}
|
|
559
759
|
async onAfterCreate(ctx) {
|
|
@@ -569,13 +769,19 @@ class LarkCliTaskNotifyHook {
|
|
|
569
769
|
if (!data?.task)
|
|
570
770
|
return;
|
|
571
771
|
const { task, changes } = data;
|
|
772
|
+
const terminalCardStatus = this.cardStatusOf(task, changes);
|
|
773
|
+
if (terminalCardStatus) {
|
|
774
|
+
const notifyType2 = terminalCardStatus === "completed" || terminalCardStatus === "cancelled" ? "task_completed" /* TASK_COMPLETED */ : "task_updated" /* TASK_UPDATED */;
|
|
775
|
+
if (!this.shouldNotify(notifyType2))
|
|
776
|
+
return;
|
|
777
|
+
if (!this.isCardModeEnabled())
|
|
778
|
+
return;
|
|
779
|
+
await this.sendCardFinish(task);
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
572
782
|
let notifyType;
|
|
573
|
-
if (changes?.status
|
|
574
|
-
notifyType = "task_completed" /* TASK_COMPLETED */;
|
|
575
|
-
} else if (changes?.status) {
|
|
783
|
+
if (changes?.status) {
|
|
576
784
|
notifyType = "task_updated" /* TASK_UPDATED */;
|
|
577
|
-
} else if (task.status === "completed" || task.progress === 100) {
|
|
578
|
-
notifyType = "task_completed" /* TASK_COMPLETED */;
|
|
579
785
|
} else if (changes && Object.keys(changes).length > 0) {
|
|
580
786
|
notifyType = "task_updated" /* TASK_UPDATED */;
|
|
581
787
|
} else {
|
|
@@ -585,11 +791,27 @@ class LarkCliTaskNotifyHook {
|
|
|
585
791
|
return;
|
|
586
792
|
if (!this.isCardModeEnabled())
|
|
587
793
|
return;
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
794
|
+
await this.sendCardUpdate(task, changes);
|
|
795
|
+
}
|
|
796
|
+
cardStatusOf(task, changes) {
|
|
797
|
+
const changedStatus = changes?.status;
|
|
798
|
+
const effective = String(changedStatus ?? task.status ?? "");
|
|
799
|
+
switch (effective) {
|
|
800
|
+
case "completed":
|
|
801
|
+
return "completed";
|
|
802
|
+
case "cancelled":
|
|
803
|
+
return "cancelled";
|
|
804
|
+
case "paused":
|
|
805
|
+
return "stopped";
|
|
806
|
+
case "archived":
|
|
807
|
+
return "stopped";
|
|
808
|
+
case "failed":
|
|
809
|
+
case "timeout":
|
|
810
|
+
return "failed";
|
|
811
|
+
default:
|
|
812
|
+
break;
|
|
592
813
|
}
|
|
814
|
+
return;
|
|
593
815
|
}
|
|
594
816
|
async onAfterComplete(ctx) {
|
|
595
817
|
const data = ctx.data;
|
|
@@ -600,6 +822,52 @@ class LarkCliTaskNotifyHook {
|
|
|
600
822
|
return;
|
|
601
823
|
await this.sendCardFinish(task);
|
|
602
824
|
}
|
|
825
|
+
async onAfterDelete(ctx) {
|
|
826
|
+
const data = ctx.data;
|
|
827
|
+
const taskId = data?.id;
|
|
828
|
+
if (data?.deleted !== true || typeof taskId !== "number")
|
|
829
|
+
return;
|
|
830
|
+
if (!this.shouldNotify("task_completed" /* TASK_COMPLETED */))
|
|
831
|
+
return;
|
|
832
|
+
if (!this.isCardModeEnabled())
|
|
833
|
+
return;
|
|
834
|
+
if (!this.cardNotifier)
|
|
835
|
+
return;
|
|
836
|
+
let record;
|
|
837
|
+
try {
|
|
838
|
+
record = this.cardStateStore?.get(taskId);
|
|
839
|
+
} catch (err) {
|
|
840
|
+
logger4.warn(`onAfterDelete: 读取卡片记录失败 task #${taskId}: ${err.message}`);
|
|
841
|
+
}
|
|
842
|
+
const messageId = record?.messageId || this.cardMessageIds.get(taskId);
|
|
843
|
+
if (!messageId) {
|
|
844
|
+
logger4.debug(`onAfterDelete: task #${taskId} 无卡片记录,skip(不发新卡)`);
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
this.restoreCardState(taskId);
|
|
848
|
+
const profile = record?.profile;
|
|
849
|
+
const chatId = record?.chatId;
|
|
850
|
+
try {
|
|
851
|
+
await this.cardNotifier.finishTask({
|
|
852
|
+
messageId,
|
|
853
|
+
profile,
|
|
854
|
+
chatId,
|
|
855
|
+
status: "deleted",
|
|
856
|
+
finalStep: "任务已取消(删除)"
|
|
857
|
+
});
|
|
858
|
+
} catch (err) {
|
|
859
|
+
logger4.warn(`onAfterDelete: patch 卡片失败 task #${taskId} message=${messageId}: ${err.message}`);
|
|
860
|
+
}
|
|
861
|
+
try {
|
|
862
|
+
await this.cardNotifier.unpinMessage(messageId, profile);
|
|
863
|
+
} catch (err) {
|
|
864
|
+
logger4.warn(`onAfterDelete: unpin 失败 task #${taskId} message=${messageId}: ${err.message}`);
|
|
865
|
+
}
|
|
866
|
+
this.persistClosed(taskId);
|
|
867
|
+
this.persistPinned(taskId, false);
|
|
868
|
+
this.cardMessageIds.delete(taskId);
|
|
869
|
+
logger4.debug(`onAfterDelete: task #${taskId} 卡片已收尾 status=deleted message=${messageId}`);
|
|
870
|
+
}
|
|
603
871
|
async onAfterOperationCreate(ctx) {
|
|
604
872
|
const { operation } = ctx.data;
|
|
605
873
|
if (!operation)
|
|
@@ -610,9 +878,14 @@ class LarkCliTaskNotifyHook {
|
|
|
610
878
|
return;
|
|
611
879
|
if (!this.isCardModeEnabled())
|
|
612
880
|
return;
|
|
881
|
+
const persisted = this.restoreCardState(operation.taskId);
|
|
613
882
|
const messageId = this.cardMessageIds.get(operation.taskId);
|
|
614
|
-
if (!messageId || messageId === LarkCliTaskNotifyHook.CARD_START_FAILED_SENTINEL) {
|
|
615
|
-
|
|
883
|
+
if (!messageId || messageId === LarkCliTaskNotifyHook.CARD_START_FAILED_SENTINEL || messageId === LarkCliTaskNotifyHook.CARD_START_INFLIGHT_SENTINEL) {
|
|
884
|
+
logger4.debug(`onAfterOperationCreate: no usable card for task #${operation.taskId}, skip`);
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
if (persisted && persisted.status !== "open") {
|
|
888
|
+
logger4.debug(`onAfterOperationCreate: task #${operation.taskId} card status=${persisted.status}, skip`);
|
|
616
889
|
return;
|
|
617
890
|
}
|
|
618
891
|
const { milestones, processSteps } = this.deriveTimelineFromOperation(operation);
|
|
@@ -629,12 +902,186 @@ class LarkCliTaskNotifyHook {
|
|
|
629
902
|
processSteps
|
|
630
903
|
});
|
|
631
904
|
} catch (err) {
|
|
632
|
-
|
|
905
|
+
logger4.error(`sendCardOperation failed for task #${operation.taskId}: ${err.message}`);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
restoreCardState(taskId) {
|
|
909
|
+
if (!this.cardStateStore)
|
|
910
|
+
return;
|
|
911
|
+
try {
|
|
912
|
+
const rec = this.cardStateStore.get(taskId);
|
|
913
|
+
if (!rec)
|
|
914
|
+
return;
|
|
915
|
+
if (!this.restoredTaskIds.has(taskId)) {
|
|
916
|
+
this.restoredTaskIds.add(taskId);
|
|
917
|
+
if (rec.status !== "closed" && rec.messageId) {
|
|
918
|
+
this.cardMessageIds.set(taskId, rec.messageId);
|
|
919
|
+
this.hydrateNotifierState(rec);
|
|
920
|
+
logger4.debug(`restoreCardState: task #${taskId} ← 持久层 message ${rec.messageId} ` + `(status=${rec.status}, pinned=${rec.pinned}, timeline=${rec.timeline ? "yes" : "no"})`);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
return rec;
|
|
924
|
+
} catch (err) {
|
|
925
|
+
logger4.warn(`restoreCardState failed for task #${taskId}: ${err.message}`);
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
hydrateNotifierState(rec) {
|
|
930
|
+
if (!this.cardNotifier || !rec.timeline)
|
|
931
|
+
return;
|
|
932
|
+
try {
|
|
933
|
+
const snapshot = JSON.parse(rec.timeline);
|
|
934
|
+
this.cardNotifier.hydrateState?.(rec.messageId, snapshot);
|
|
935
|
+
} catch (err) {
|
|
936
|
+
logger4.warn(`hydrateNotifierState failed for task #${rec.taskId}: ${err.message}`);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
snapshotTimeline(state) {
|
|
940
|
+
if (!this.cardNotifier || !state.messageId)
|
|
941
|
+
return state;
|
|
942
|
+
try {
|
|
943
|
+
const snap = this.cardNotifier.exportState?.(state.messageId);
|
|
944
|
+
if (!snap)
|
|
945
|
+
return state;
|
|
946
|
+
return { ...state, timeline: JSON.stringify(snap) };
|
|
947
|
+
} catch (err) {
|
|
948
|
+
logger4.warn(`snapshotTimeline failed for task #${state.taskId}: ${err.message}`);
|
|
949
|
+
return state;
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
persistCardState(state, includeTimeline = false) {
|
|
953
|
+
if (!this.cardStateStore)
|
|
954
|
+
return;
|
|
955
|
+
try {
|
|
956
|
+
const payload = includeTimeline ? this.snapshotTimeline(state) : state;
|
|
957
|
+
this.cardStateStore.upsert(payload);
|
|
958
|
+
} catch (err) {
|
|
959
|
+
logger4.warn(`persistCardState failed for task #${state.taskId}: ${err.message}`);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
persistPinned(taskId, pinned) {
|
|
963
|
+
if (!this.cardStateStore)
|
|
964
|
+
return;
|
|
965
|
+
try {
|
|
966
|
+
this.cardStateStore.markPinned(taskId, pinned);
|
|
967
|
+
} catch (err) {
|
|
968
|
+
logger4.warn(`persistPinned failed for task #${taskId}: ${err.message}`);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
persistPaused(taskId) {
|
|
972
|
+
if (!this.cardStateStore)
|
|
973
|
+
return;
|
|
974
|
+
try {
|
|
975
|
+
this.cardStateStore.markPaused(taskId);
|
|
976
|
+
} catch (err) {
|
|
977
|
+
logger4.warn(`persistPaused failed for task #${taskId}: ${err.message}`);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
dropStaleMessageId(taskId) {
|
|
981
|
+
if (!this.cardStateStore)
|
|
982
|
+
return;
|
|
983
|
+
try {
|
|
984
|
+
const existing = this.cardStateStore.get(taskId);
|
|
985
|
+
if (!existing)
|
|
986
|
+
return;
|
|
987
|
+
this.cardStateStore.upsert({
|
|
988
|
+
...existing,
|
|
989
|
+
messageId: "",
|
|
990
|
+
pinned: false,
|
|
991
|
+
updatedAt: Date.now()
|
|
992
|
+
});
|
|
993
|
+
} catch (err) {
|
|
994
|
+
logger4.warn(`dropStaleMessageId failed for task #${taskId}: ${err.message}`);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
persistReopened(taskId) {
|
|
998
|
+
if (!this.cardStateStore)
|
|
999
|
+
return;
|
|
1000
|
+
try {
|
|
1001
|
+
this.cardStateStore.markReopened(taskId);
|
|
1002
|
+
} catch (err) {
|
|
1003
|
+
logger4.warn(`persistReopened failed for task #${taskId}: ${err.message}`);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
persistClosed(taskId) {
|
|
1007
|
+
if (!this.cardStateStore)
|
|
1008
|
+
return;
|
|
1009
|
+
try {
|
|
1010
|
+
this.cardStateStore.markClosed(taskId);
|
|
1011
|
+
} catch (err) {
|
|
1012
|
+
logger4.warn(`persistClosed failed for task #${taskId}: ${err.message}`);
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
refreshTimeline(taskId) {
|
|
1016
|
+
if (!this.cardStateStore || !this.cardNotifier)
|
|
1017
|
+
return;
|
|
1018
|
+
try {
|
|
1019
|
+
const rec = this.cardStateStore.get(taskId);
|
|
1020
|
+
if (!rec || !rec.messageId)
|
|
1021
|
+
return;
|
|
1022
|
+
this.cardStateStore.upsert(this.snapshotTimeline(rec));
|
|
1023
|
+
} catch (err) {
|
|
1024
|
+
logger4.warn(`refreshTimeline failed for task #${taskId}: ${err.message}`);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
async repinAfterResume(task, persisted) {
|
|
1028
|
+
if (!this.cardNotifier || typeof this.cardNotifier.pinMessage !== "function") {
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
if (!persisted.messageId)
|
|
1032
|
+
return;
|
|
1033
|
+
if (persisted.pinned)
|
|
1034
|
+
return;
|
|
1035
|
+
const ctx = getEnvContextOrEmpty();
|
|
1036
|
+
const profile = this.resolveProfile(task, ctx);
|
|
1037
|
+
try {
|
|
1038
|
+
await this.cardNotifier.pinMessage(persisted.messageId, profile);
|
|
1039
|
+
this.persistPinned(task.id, true);
|
|
1040
|
+
logger4.debug(`repinAfterResume: task #${task.id} 卡片 ${persisted.messageId} 已重新置顶`);
|
|
1041
|
+
} catch (err) {
|
|
1042
|
+
logger4.warn(`repinAfterResume failed (non-fatal) for task #${task.id}: ${err.message}`);
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
buildCardState(task, messageId, chatId, profile, pinned) {
|
|
1046
|
+
let existing;
|
|
1047
|
+
try {
|
|
1048
|
+
existing = this.cardStateStore?.get(task.id);
|
|
1049
|
+
} catch (err) {
|
|
1050
|
+
logger4.warn(`buildCardState: read existing failed for task #${task.id}: ${err.message}`);
|
|
1051
|
+
}
|
|
1052
|
+
const now = Date.now();
|
|
1053
|
+
return {
|
|
1054
|
+
taskId: task.id,
|
|
1055
|
+
messageId,
|
|
1056
|
+
chatId,
|
|
1057
|
+
profile,
|
|
1058
|
+
pinned,
|
|
1059
|
+
status: "open",
|
|
1060
|
+
createdAt: existing?.createdAt ?? now,
|
|
1061
|
+
updatedAt: now
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
getCardState(taskId) {
|
|
1065
|
+
if (!this.cardStateStore)
|
|
1066
|
+
return;
|
|
1067
|
+
try {
|
|
1068
|
+
return this.cardStateStore.get(taskId);
|
|
1069
|
+
} catch {
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
listCardStates() {
|
|
1074
|
+
if (!this.cardStateStore)
|
|
1075
|
+
return [];
|
|
1076
|
+
try {
|
|
1077
|
+
return this.cardStateStore.list();
|
|
1078
|
+
} catch {
|
|
1079
|
+
return [];
|
|
633
1080
|
}
|
|
634
1081
|
}
|
|
635
1082
|
isCardModeEnabled() {
|
|
636
1083
|
if (this.config.cardMode === false || !this.cardNotifier) {
|
|
637
|
-
|
|
1084
|
+
logger4.debug("cardMode=false (legacy opt-out), skip task notification (no text fallback)");
|
|
638
1085
|
return false;
|
|
639
1086
|
}
|
|
640
1087
|
return true;
|
|
@@ -696,9 +1143,15 @@ class LarkCliTaskNotifyHook {
|
|
|
696
1143
|
async sendCardStart(task) {
|
|
697
1144
|
if (!this.cardNotifier)
|
|
698
1145
|
return;
|
|
1146
|
+
const persisted = this.restoreCardState(task.id);
|
|
1147
|
+
if (persisted?.status === "closed") {
|
|
1148
|
+
this.cardMessageIds.delete(task.id);
|
|
1149
|
+
} else if (persisted?.status === "paused") {
|
|
1150
|
+
this.persistReopened(task.id);
|
|
1151
|
+
}
|
|
699
1152
|
const claim = this.cardMessageIds.get(task.id);
|
|
700
1153
|
if (claim) {
|
|
701
|
-
|
|
1154
|
+
logger4.debug(`sendCardStart: task #${task.id} 已有首卡(${claim})→ 跳过重复发卡`);
|
|
702
1155
|
return;
|
|
703
1156
|
}
|
|
704
1157
|
this.cardMessageIds.set(task.id, LarkCliTaskNotifyHook.CARD_START_INFLIGHT_SENTINEL);
|
|
@@ -713,7 +1166,7 @@ class LarkCliTaskNotifyHook {
|
|
|
713
1166
|
const profile = target.profile;
|
|
714
1167
|
if (!chatId) {
|
|
715
1168
|
this.cardMessageIds.delete(task.id);
|
|
716
|
-
|
|
1169
|
+
logger4.debug(`sendCardStart: no chatId for task #${task.id}, skip`);
|
|
717
1170
|
return;
|
|
718
1171
|
}
|
|
719
1172
|
try {
|
|
@@ -730,29 +1183,55 @@ class LarkCliTaskNotifyHook {
|
|
|
730
1183
|
]
|
|
731
1184
|
});
|
|
732
1185
|
this.cardMessageIds.set(task.id, messageId);
|
|
733
|
-
|
|
1186
|
+
this.persistCardState(this.buildCardState(task, messageId, chatId, profile, pinned), true);
|
|
1187
|
+
logger4.debug(`sendCardStart: task #${task.id} → message ${messageId} (pinned=${pinned}) ` + `chat=${chatId} source=${target.source} reason=${target.reason}`);
|
|
734
1188
|
} catch (err) {
|
|
735
1189
|
this.cardMessageIds.set(task.id, LarkCliTaskNotifyHook.CARD_START_FAILED_SENTINEL);
|
|
736
|
-
|
|
1190
|
+
logger4.error(`sendCardStart failed for task #${task.id}: ${err.message}`);
|
|
737
1191
|
}
|
|
738
1192
|
}
|
|
739
1193
|
async sendCardUpdate(task, changes) {
|
|
740
1194
|
if (!this.cardNotifier)
|
|
741
1195
|
return;
|
|
1196
|
+
const persisted = this.restoreCardState(task.id);
|
|
1197
|
+
if (persisted?.status === "closed") {
|
|
1198
|
+
const stillTerminal = isTerminalTaskStatus(String(task.status));
|
|
1199
|
+
if (stillTerminal) {
|
|
1200
|
+
logger4.debug(`sendCardUpdate: task #${task.id} 卡片已终结(closed)且任务仍终态 → skip patch`);
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
logger4.info(`sendCardUpdate: task #${task.id} 已 reopen(closed 记录 + 当前 status=${task.status})` + `→ 重新建卡`);
|
|
1204
|
+
this.cardMessageIds.delete(task.id);
|
|
1205
|
+
this.dropStaleMessageId(task.id);
|
|
1206
|
+
}
|
|
1207
|
+
if (persisted?.status === "paused" && String(task.status) !== "paused") {
|
|
1208
|
+
this.persistReopened(task.id);
|
|
1209
|
+
logger4.debug(`sendCardUpdate: task #${task.id} resume(paused → open),复用卡片 ${persisted.messageId}`);
|
|
1210
|
+
await this.repinAfterResume(task, persisted);
|
|
1211
|
+
}
|
|
742
1212
|
let messageId = this.cardMessageIds.get(task.id);
|
|
1213
|
+
if (!messageId && isTerminalTaskStatus(String(task.status))) {
|
|
1214
|
+
logger4.debug(`sendCardUpdate: task #${task.id} 状态=${task.status}(终结/归档)且无卡片 → skip`);
|
|
1215
|
+
return;
|
|
1216
|
+
}
|
|
1217
|
+
if (!messageId) {
|
|
1218
|
+
this.cardMessageIds.set(task.id, LarkCliTaskNotifyHook.CARD_START_INFLIGHT_SENTINEL);
|
|
1219
|
+
}
|
|
743
1220
|
const target = messageId ? undefined : await this.resolveCardTarget(task);
|
|
744
1221
|
const chatId = target?.chatId ?? this.resolveChatId(task, getEnvContextOrEmpty());
|
|
745
1222
|
const profile = target?.profile ?? this.resolveProfile(task, getEnvContextOrEmpty());
|
|
746
1223
|
if (!chatId) {
|
|
747
|
-
|
|
1224
|
+
if (!messageId)
|
|
1225
|
+
this.cardMessageIds.delete(task.id);
|
|
1226
|
+
logger4.debug(`sendCardUpdate: no chatId for task #${task.id}, skip`);
|
|
748
1227
|
return;
|
|
749
1228
|
}
|
|
750
1229
|
if (messageId === LarkCliTaskNotifyHook.CARD_START_FAILED_SENTINEL) {
|
|
751
|
-
|
|
1230
|
+
logger4.debug(`sendCardUpdate: startTask failed previously for task #${task.id}, skip`);
|
|
752
1231
|
return;
|
|
753
1232
|
}
|
|
754
1233
|
if (messageId === LarkCliTaskNotifyHook.CARD_START_INFLIGHT_SENTINEL) {
|
|
755
|
-
|
|
1234
|
+
logger4.debug(`sendCardUpdate: task #${task.id} 首卡正在发送中(in-flight)→ 跳过本次 update`);
|
|
756
1235
|
return;
|
|
757
1236
|
}
|
|
758
1237
|
if (!messageId) {
|
|
@@ -764,9 +1243,10 @@ class LarkCliTaskNotifyHook {
|
|
|
764
1243
|
});
|
|
765
1244
|
messageId = res.messageId;
|
|
766
1245
|
this.cardMessageIds.set(task.id, messageId);
|
|
1246
|
+
this.persistCardState(this.buildCardState(task, messageId, chatId, profile, res.pinned), true);
|
|
767
1247
|
} catch (err) {
|
|
768
1248
|
this.cardMessageIds.set(task.id, LarkCliTaskNotifyHook.CARD_START_FAILED_SENTINEL);
|
|
769
|
-
|
|
1249
|
+
logger4.error(`sendCardUpdate fallback start failed: ${err.message}`);
|
|
770
1250
|
return;
|
|
771
1251
|
}
|
|
772
1252
|
}
|
|
@@ -789,32 +1269,49 @@ class LarkCliTaskNotifyHook {
|
|
|
789
1269
|
milestones: [],
|
|
790
1270
|
processSteps
|
|
791
1271
|
});
|
|
1272
|
+
const current = this.getCardState(task.id);
|
|
1273
|
+
this.persistPinned(task.id, current?.pinned ?? persisted?.pinned ?? true);
|
|
1274
|
+
this.refreshTimeline(task.id);
|
|
792
1275
|
} catch (err) {
|
|
793
|
-
|
|
1276
|
+
logger4.error(`sendCardUpdate failed: ${err.message}`);
|
|
794
1277
|
}
|
|
795
1278
|
}
|
|
796
1279
|
async sendCardFinish(task) {
|
|
797
1280
|
if (!this.cardNotifier)
|
|
798
1281
|
return;
|
|
1282
|
+
this.restoreCardState(task.id);
|
|
799
1283
|
const messageId = this.cardMessageIds.get(task.id);
|
|
800
1284
|
const ctx = getEnvContextOrEmpty();
|
|
801
1285
|
const profile = this.resolveProfile(task, ctx);
|
|
802
1286
|
if (!messageId || messageId === LarkCliTaskNotifyHook.CARD_START_FAILED_SENTINEL) {
|
|
803
|
-
|
|
1287
|
+
logger4.debug(`sendCardFinish: no card messageId for task #${task.id}, skip ` + `(记录缺失 → 不发新卡,保持幂等)`);
|
|
804
1288
|
return;
|
|
805
1289
|
}
|
|
806
|
-
const
|
|
1290
|
+
const rawStatus = String(task.status);
|
|
1291
|
+
const status = mapTaskStatusToCardStatus(rawStatus);
|
|
1292
|
+
const isPaused = rawStatus === "paused" || rawStatus === "archived";
|
|
807
1293
|
try {
|
|
808
|
-
|
|
1294
|
+
const finish = isPaused ? this.cardNotifier.pauseTask.bind(this.cardNotifier) : this.cardNotifier.finishTask.bind(this.cardNotifier);
|
|
1295
|
+
await finish({
|
|
809
1296
|
messageId,
|
|
810
1297
|
profile,
|
|
811
1298
|
status,
|
|
812
1299
|
meta: this.buildTaskMeta(task),
|
|
813
|
-
finalStep: task.current_status || undefined
|
|
1300
|
+
finalStep: task.current_status || undefined,
|
|
1301
|
+
...rawStatus === "archived" ? { pausedMilestoneTitle: "Task 已归档" } : {}
|
|
814
1302
|
});
|
|
815
|
-
|
|
1303
|
+
if (isPaused) {
|
|
1304
|
+
this.persistPaused(task.id);
|
|
1305
|
+
this.persistPinned(task.id, false);
|
|
1306
|
+
this.refreshTimeline(task.id);
|
|
1307
|
+
} else {
|
|
1308
|
+
this.persistClosed(task.id);
|
|
1309
|
+
this.persistPinned(task.id, false);
|
|
1310
|
+
this.cardMessageIds.delete(task.id);
|
|
1311
|
+
}
|
|
1312
|
+
logger4.debug(`sendCardFinish: task #${task.id} → status=${status} ` + `(raw=${rawStatus}) message=${messageId}`);
|
|
816
1313
|
} catch (err) {
|
|
817
|
-
|
|
1314
|
+
logger4.error(`sendCardFinish failed: ${err.message}`);
|
|
818
1315
|
}
|
|
819
1316
|
}
|
|
820
1317
|
resolveChatId(task, env) {
|
|
@@ -891,7 +1388,7 @@ class LarkCliTaskNotifyHook {
|
|
|
891
1388
|
const now = Date.now();
|
|
892
1389
|
const lastTime = this.lastNotifyTimestamps.get(key);
|
|
893
1390
|
if (lastTime && now - lastTime < throttleMs) {
|
|
894
|
-
|
|
1391
|
+
logger4.debug(`[throttle] skip OPERATION_CREATED patch for task #${operation.taskId} (${now - lastTime}ms ago)`);
|
|
895
1392
|
return true;
|
|
896
1393
|
}
|
|
897
1394
|
this.lastNotifyTimestamps.set(key, now);
|
|
@@ -934,7 +1431,7 @@ init_decorator();
|
|
|
934
1431
|
init_logger();
|
|
935
1432
|
init_context();
|
|
936
1433
|
import { spawn } from "child_process";
|
|
937
|
-
var
|
|
1434
|
+
var logger5 = createLogger("lark-cli:per-task-group");
|
|
938
1435
|
function isPluginDebugEnabled() {
|
|
939
1436
|
return process.env.ROY_TASK_NOTIFY_DEBUG === "1" || process.env.ROY_TRACE_DEBUG === "1";
|
|
940
1437
|
}
|
|
@@ -989,7 +1486,7 @@ class PerTaskGroupChatPlugin {
|
|
|
989
1486
|
const renderedName = this.renderTemplate(this.config.nameTemplate, task);
|
|
990
1487
|
const existingChatId = this.getTaskChatId(task);
|
|
991
1488
|
if (existingChatId) {
|
|
992
|
-
|
|
1489
|
+
logger5.debug(`ensureGroupChat[${this.pluginName}]: task #${task.id} 已有专属群 ${existingChatId} → 复用(不重复建群)`);
|
|
993
1490
|
return {
|
|
994
1491
|
chatId: existingChatId,
|
|
995
1492
|
profile: this.parseProfileFromContext(task.context),
|
|
@@ -998,7 +1495,7 @@ class PerTaskGroupChatPlugin {
|
|
|
998
1495
|
}
|
|
999
1496
|
const inflight = this.groupChatInflight.get(task.id);
|
|
1000
1497
|
if (inflight) {
|
|
1001
|
-
|
|
1498
|
+
logger5.debug(`ensureGroupChat[${this.pluginName}]: task #${task.id} 建群已在进行中 → 复用同一 promise`);
|
|
1002
1499
|
return inflight;
|
|
1003
1500
|
}
|
|
1004
1501
|
const pending = this.doEnsureGroupChat(task, renderedName, replyChannelOverride);
|
|
@@ -1012,7 +1509,7 @@ class PerTaskGroupChatPlugin {
|
|
|
1012
1509
|
async doEnsureGroupChat(task, name, replyChannelOverride) {
|
|
1013
1510
|
const replyChannel = replyChannelOverride ?? getEnvContextOrEmpty().replyChannel;
|
|
1014
1511
|
if (!replyChannel?.chatId && this.config.requireReplyChannel) {
|
|
1015
|
-
|
|
1512
|
+
logger5.warn(`ensureGroupChat[${this.pluginName}]: no replyChannel.chatId for task #${task.id} ` + `(requireReplyChannel=true) → 无法建群`);
|
|
1016
1513
|
return;
|
|
1017
1514
|
}
|
|
1018
1515
|
const description = this.renderTemplate(this.config.descriptionTemplate, task);
|
|
@@ -1030,30 +1527,30 @@ class PerTaskGroupChatPlugin {
|
|
|
1030
1527
|
await this.writeChatBinding(task, chatId, profile, "creating");
|
|
1031
1528
|
await this.attachChatIdToTask(task, chatId, profile);
|
|
1032
1529
|
await this.writeChatBinding(task, chatId, profile, "ready");
|
|
1033
|
-
|
|
1530
|
+
logger5.info(`ensureGroupChat[${this.pluginName}]: created group ${chatId} for task #${task.id}`);
|
|
1034
1531
|
return { chatId, profile, name };
|
|
1035
1532
|
} catch (error) {
|
|
1036
|
-
|
|
1533
|
+
logger5.error(`ensureGroupChat[${this.pluginName}]: failed for task #${task.id}: ${error}`);
|
|
1037
1534
|
return;
|
|
1038
1535
|
}
|
|
1039
1536
|
}
|
|
1040
1537
|
setTaskUpdater(updater) {
|
|
1041
1538
|
this.taskUpdater = updater;
|
|
1042
|
-
|
|
1539
|
+
logger5.debug(`TaskUpdater injected for plugin ${this.name} (sourceId=${this.sourceId})`);
|
|
1043
1540
|
}
|
|
1044
1541
|
hasTaskUpdater() {
|
|
1045
1542
|
return this.taskUpdater !== undefined;
|
|
1046
1543
|
}
|
|
1047
1544
|
setTaskGetter(getter) {
|
|
1048
1545
|
this.taskGetter = getter;
|
|
1049
|
-
|
|
1546
|
+
logger5.debug(`TaskGetter injected for plugin ${this.name} (sourceId=${this.sourceId})`);
|
|
1050
1547
|
}
|
|
1051
1548
|
hasTaskGetter() {
|
|
1052
1549
|
return this.taskGetter !== undefined;
|
|
1053
1550
|
}
|
|
1054
1551
|
setSessionComponent(sessionComponent) {
|
|
1055
1552
|
this.sessionComponent = sessionComponent;
|
|
1056
|
-
|
|
1553
|
+
logger5.debug(`SessionComponent injected for plugin ${this.name} (sourceId=${this.sourceId})`);
|
|
1057
1554
|
}
|
|
1058
1555
|
hasSessionComponent() {
|
|
1059
1556
|
return this.sessionComponent !== undefined;
|
|
@@ -1066,7 +1563,7 @@ class PerTaskGroupChatPlugin {
|
|
|
1066
1563
|
if (process.env.ROY_HOOK_DEBUG === "1") {
|
|
1067
1564
|
console.error(`[DEBUG per-task-group-chat.execute] → SKIP (config.enabled=false)`);
|
|
1068
1565
|
}
|
|
1069
|
-
|
|
1566
|
+
logger5.debug(`execute: plugin disabled (pluginName=${this.pluginName})`);
|
|
1070
1567
|
return;
|
|
1071
1568
|
}
|
|
1072
1569
|
if (this.pluginName && this.sourceId) {
|
|
@@ -1079,13 +1576,13 @@ class PerTaskGroupChatPlugin {
|
|
|
1079
1576
|
if (process.env.ROY_HOOK_DEBUG === "1") {
|
|
1080
1577
|
console.error(`[DEBUG per-task-group-chat.execute] → SKIP (plugin NOT enabled for ${key})`);
|
|
1081
1578
|
}
|
|
1082
|
-
|
|
1579
|
+
logger5.debug(`execute[${this.pluginName}]: plugin NOT enabled (key=${key}, ` + `env.pluginEnabled=${JSON.stringify(env.pluginEnabled)}, ` + `hookPoint=${ctx.hookPoint}). ` + `→ skip. 修复:roy-agent eventsource update <id> 必须包含 PerTaskGroupChatPlugin`);
|
|
1083
1580
|
return;
|
|
1084
1581
|
}
|
|
1085
1582
|
const enabledState = env.pluginEnabled ? env.pluginEnabled[key] === true ? "✅ enabled" : "❌ NOT enabled" : "⚠️ env.pluginEnabled 未设置 (env 没创建 / 插件未注册到 eventsource)";
|
|
1086
|
-
|
|
1583
|
+
logger5.debug(`execute[${this.pluginName}]: ${enabledState} (key=${key}, ` + `hookPoint=${ctx.hookPoint}, taskUpdaterInjected=${this.hasTaskUpdater()})`);
|
|
1087
1584
|
} else {
|
|
1088
|
-
|
|
1585
|
+
logger5.debug(`execute[${this.pluginName}]: missing pluginName/sourceId metadata ` + `(pluginName=${this.pluginName}, sourceId=${this.sourceId}), ` + `skipping pluginEnabled check. hookPoint=${ctx.hookPoint}`);
|
|
1089
1586
|
}
|
|
1090
1587
|
if (process.env.ROY_HOOK_DEBUG === "1") {
|
|
1091
1588
|
console.error(`[DEBUG per-task-group-chat.execute] → PASSED pluginEnabled check, will dispatch hookPoint=${ctx.hookPoint}`);
|
|
@@ -1104,13 +1601,13 @@ class PerTaskGroupChatPlugin {
|
|
|
1104
1601
|
await this.onAfterComplete(ctx);
|
|
1105
1602
|
break;
|
|
1106
1603
|
default:
|
|
1107
|
-
|
|
1604
|
+
logger5.debug(`execute: unhandled hookPoint=${ctx.hookPoint}, skip`);
|
|
1108
1605
|
}
|
|
1109
1606
|
}
|
|
1110
1607
|
async onAfterCreate(ctx) {
|
|
1111
1608
|
const data = ctx.data;
|
|
1112
1609
|
if (!data?.task) {
|
|
1113
|
-
|
|
1610
|
+
logger5.debug("onAfterCreate: task is missing, skip");
|
|
1114
1611
|
return;
|
|
1115
1612
|
}
|
|
1116
1613
|
const { task } = data;
|
|
@@ -1121,38 +1618,38 @@ class PerTaskGroupChatPlugin {
|
|
|
1121
1618
|
console.error(`[DEBUG per-task-group-chat.onAfterCreate] env.messageId=${env.messageId}`);
|
|
1122
1619
|
console.error(`[DEBUG per-task-group-chat.onAfterCreate] env.sourceId=${env.sourceId}`);
|
|
1123
1620
|
}
|
|
1124
|
-
|
|
1621
|
+
logger5.debug(`onAfterCreate[${this.pluginName}]: enter task=${task.id} "${task.title}" ` + `parent_task_id=${task.parent_task_id ?? "none"} ` + `requireReplyChannel=${this.config.requireReplyChannel} ` + `disableSubTaskSkip=${this.config.disableSubTaskSkip} ` + `sendWelcomeMessage=${this.config.sendWelcomeMessage} ` + `autoCreateGroup=${this.config.autoCreateGroup}`);
|
|
1125
1622
|
if (!this.config.autoCreateGroup) {
|
|
1126
|
-
|
|
1623
|
+
logger5.debug(`onAfterCreate[${this.pluginName}]: task #${task.id} autoCreateGroup=false ` + `→ skip group chat creation(按需建群:用户在卡片顶部按钮触发)`);
|
|
1127
1624
|
return;
|
|
1128
1625
|
}
|
|
1129
1626
|
const replyChannel = this.getReplyChannelFromCtx(ctx);
|
|
1130
1627
|
if (!replyChannel?.chatId && this.config.requireReplyChannel) {
|
|
1131
|
-
|
|
1628
|
+
logger5.debug(`onAfterCreate[${this.pluginName}]: no replyChannel.chatId for task #${task.id}, skip. ` + `修复:eventsource 收到 im.message.receive_v1 事件时 replyChannel 应有值;` + `或在 plugin config 设 requireReplyChannel=false 强制创建群聊(profile 降级到 fallbackProfile/无)`);
|
|
1132
1629
|
return;
|
|
1133
1630
|
}
|
|
1134
1631
|
if (!replyChannel?.chatId && !this.config.requireReplyChannel) {
|
|
1135
|
-
|
|
1632
|
+
logger5.debug(`onAfterCreate[${this.pluginName}]: no replyChannel but requireReplyChannel=false, ` + `proceeding with profile fallback (fallbackProfile="${this.config.fallbackProfile}")`);
|
|
1136
1633
|
}
|
|
1137
1634
|
if (this.isSubTask(task) && !this.config.disableSubTaskSkip) {
|
|
1138
|
-
|
|
1635
|
+
logger5.debug(`onAfterCreate[${this.pluginName}]: task #${task.id} is sub-task, ` + `skip group chat creation. 关闭方式:config.disableSubTaskSkip=true`);
|
|
1139
1636
|
return;
|
|
1140
1637
|
}
|
|
1141
1638
|
if (this.isSubTask(task) && this.config.disableSubTaskSkip) {
|
|
1142
|
-
|
|
1639
|
+
logger5.debug(`onAfterCreate[${this.pluginName}]: task #${task.id} is sub-task but ` + `disableSubTaskSkip=true, proceeding to create group chat`);
|
|
1143
1640
|
}
|
|
1144
1641
|
try {
|
|
1145
1642
|
const created = await this.ensureGroupChat(task, replyChannel);
|
|
1146
1643
|
if (!created?.chatId) {
|
|
1147
|
-
|
|
1644
|
+
logger5.error(`onAfterCreate[${this.pluginName}]: ensureGroupChat 未返回 chatId for task #${task.id}`);
|
|
1148
1645
|
if (!this.config.fallbackToMain) {
|
|
1149
1646
|
throw new Error(`per-task group chat unavailable for task #${task.id}`);
|
|
1150
1647
|
}
|
|
1151
1648
|
return;
|
|
1152
1649
|
}
|
|
1153
|
-
|
|
1650
|
+
logger5.info(`onAfterCreate[${this.pluginName}]: task #${task.id} → group ${created.chatId} ` + `(initial card owned by LarkCliTaskNotifyHook)`);
|
|
1154
1651
|
} catch (error) {
|
|
1155
|
-
|
|
1652
|
+
logger5.error(`onAfterCreate[${this.pluginName}]: group chat failed for task #${task.id}: ${error}`);
|
|
1156
1653
|
if (!this.config.fallbackToMain)
|
|
1157
1654
|
throw error;
|
|
1158
1655
|
}
|
|
@@ -1160,7 +1657,7 @@ class PerTaskGroupChatPlugin {
|
|
|
1160
1657
|
async writeChatBinding(task, chatId, profile, status, errorMessage) {
|
|
1161
1658
|
if (!this.sessionComponent) {
|
|
1162
1659
|
if (isPluginDebugEnabled()) {
|
|
1163
|
-
|
|
1660
|
+
logger5.debug(`writeChatBinding[${this.pluginName}]: no sessionComponent injected, ` + `skip chat-task binding for chat ${chatId} (status=${status})`);
|
|
1164
1661
|
}
|
|
1165
1662
|
return;
|
|
1166
1663
|
}
|
|
@@ -1173,37 +1670,37 @@ class PerTaskGroupChatPlugin {
|
|
|
1173
1670
|
errorMessage: errorMessage ?? null
|
|
1174
1671
|
});
|
|
1175
1672
|
} catch (bindErr) {
|
|
1176
|
-
|
|
1673
|
+
logger5.warn(`writeChatBinding[${this.pluginName}]: failed to write chat-task binding for ` + `chat ${chatId} / task #${task.id} (status=${status}): ${bindErr}. ` + `群消息 handler 将无法自动注入 parentTaskId。`);
|
|
1177
1674
|
}
|
|
1178
1675
|
}
|
|
1179
1676
|
async onAfterUpdate(ctx) {
|
|
1180
1677
|
const data = ctx.data;
|
|
1181
1678
|
if (!data?.task) {
|
|
1182
|
-
|
|
1679
|
+
logger5.debug("onAfterUpdate: task is missing, skip");
|
|
1183
1680
|
return;
|
|
1184
1681
|
}
|
|
1185
|
-
|
|
1682
|
+
logger5.debug(`onAfterUpdate[${this.pluginName}]: task #${data.task.id} 卡片由 ` + `LarkCliTaskNotifyHook 负责(本插件不再 patch),skip`);
|
|
1186
1683
|
}
|
|
1187
1684
|
async onAfterOperationCreate(ctx) {
|
|
1188
1685
|
const data = ctx.data;
|
|
1189
1686
|
if (!data?.operation) {
|
|
1190
|
-
|
|
1687
|
+
logger5.debug("onAfterOperationCreate: operation is missing, skip");
|
|
1191
1688
|
return;
|
|
1192
1689
|
}
|
|
1193
|
-
|
|
1690
|
+
logger5.debug(`onAfterOperationCreate[${this.pluginName}]: operation #${data.operation.id} ` + `卡片由 LarkCliTaskNotifyHook 负责,skip`);
|
|
1194
1691
|
}
|
|
1195
1692
|
async onAfterComplete(ctx) {
|
|
1196
1693
|
const data = ctx.data;
|
|
1197
1694
|
if (!data?.task) {
|
|
1198
|
-
|
|
1695
|
+
logger5.debug("onAfterComplete: task is missing, skip");
|
|
1199
1696
|
return;
|
|
1200
1697
|
}
|
|
1201
|
-
|
|
1698
|
+
logger5.debug(`onAfterComplete[${this.pluginName}]: task #${data.task.id} 终态卡片由 ` + `LarkCliTaskNotifyHook 负责,skip`);
|
|
1202
1699
|
}
|
|
1203
1700
|
createGroupChat(opts) {
|
|
1204
1701
|
const args = this.buildCreateGroupChatArgs(opts);
|
|
1205
1702
|
if (isPluginDebugEnabled()) {
|
|
1206
|
-
|
|
1703
|
+
logger5.debug(`Creating group chat: lark-cli ${args.join(" ")}`);
|
|
1207
1704
|
}
|
|
1208
1705
|
return new Promise((resolve, reject) => {
|
|
1209
1706
|
const proc = spawn("lark-cli", args, {
|
|
@@ -1278,16 +1775,16 @@ class PerTaskGroupChatPlugin {
|
|
|
1278
1775
|
parsed[CTX_FIELD_CHAT_TASK_ID] = task.id;
|
|
1279
1776
|
const newContext = JSON.stringify(parsed);
|
|
1280
1777
|
if (!this.taskUpdater) {
|
|
1281
|
-
|
|
1778
|
+
logger5.warn(`attachChatIdToTask[${this.pluginName}]: ⚠️ no taskUpdater injected, ` + `chat_id ${chatId} NOT persisted to db for task #${task.id}. ` + `后果:下次 AFTER_UPDATE 从 DB 加载 task 时 getTaskChatId() 返回 undefined,` + `所有 update/complete/operation 通知 silently 丢失。` + `修复:event-source-handlers.ts:registerPluginHooks 应自动注入 setTaskUpdater。`);
|
|
1282
1779
|
task.context = newContext;
|
|
1283
1780
|
return;
|
|
1284
1781
|
}
|
|
1285
1782
|
try {
|
|
1286
1783
|
await this.taskUpdater(task.id, newContext);
|
|
1287
1784
|
task.context = newContext;
|
|
1288
|
-
|
|
1785
|
+
logger5.debug(`attachChatIdToTask[${this.pluginName}]: ✅ persisted chat_id ${chatId} ` + `to task #${task.id} context`);
|
|
1289
1786
|
} catch (error) {
|
|
1290
|
-
|
|
1787
|
+
logger5.error(`Failed to persist chat_id to task #${task.id}: ${error}`);
|
|
1291
1788
|
task.context = newContext;
|
|
1292
1789
|
}
|
|
1293
1790
|
}
|
|
@@ -1382,15 +1879,15 @@ class PerTaskGroupChatPlugin {
|
|
|
1382
1879
|
}
|
|
1383
1880
|
resolveBotAppIds(replyChannel) {
|
|
1384
1881
|
if (this.config.botAppIds.length > 0) {
|
|
1385
|
-
|
|
1882
|
+
logger5.debug(`resolveBotAppIds[${this.pluginName}]: using config.botAppIds=${JSON.stringify(this.config.botAppIds)}`);
|
|
1386
1883
|
return this.config.botAppIds;
|
|
1387
1884
|
}
|
|
1388
1885
|
const appId = replyChannel ? replyChannel.appId : undefined;
|
|
1389
1886
|
if (appId) {
|
|
1390
|
-
|
|
1887
|
+
logger5.debug(`resolveBotAppIds[${this.pluginName}]: using replyChannel.appId=${appId} (auto-detected from event header.app_id)`);
|
|
1391
1888
|
return [appId];
|
|
1392
1889
|
}
|
|
1393
|
-
|
|
1890
|
+
logger5.warn(`resolveBotAppIds[${this.pluginName}]: ⚠️ no botAppIds found, creating group WITHOUT --bots. ` + `Bot will NOT be invited automatically. ` + `可能原因:(1) eventsource 没有收到 im.message.receive_v1 事件(replyChannel.appId 缺失);` + `(2) 配置了 requireReplyChannel=false 模式;` + `(3) buildReplyChannel 没透传 appId(应在 v1.10+ 修复)。` + `修复:手动设置 config.botAppIds: ["cli_xxx"] 或确认 eventsource 处理了 lark event。`);
|
|
1394
1891
|
return [];
|
|
1395
1892
|
}
|
|
1396
1893
|
resolveUserIds(replyChannel) {
|
|
@@ -1400,7 +1897,7 @@ class PerTaskGroupChatPlugin {
|
|
|
1400
1897
|
if (id && id !== "sender" && id.startsWith("ou_")) {
|
|
1401
1898
|
ids.add(id);
|
|
1402
1899
|
} else if (id && id !== "sender") {
|
|
1403
|
-
|
|
1900
|
+
logger5.debug(`resolveUserIds[${this.pluginName}]: skip non-open_id in defaultInviteUserIds: "${id}"`);
|
|
1404
1901
|
}
|
|
1405
1902
|
}
|
|
1406
1903
|
}
|
|
@@ -1423,7 +1920,7 @@ class PerTaskGroupChatPlugin {
|
|
|
1423
1920
|
}
|
|
1424
1921
|
}
|
|
1425
1922
|
if (isPluginDebugEnabled()) {
|
|
1426
|
-
|
|
1923
|
+
logger5.debug(`resolveUserIds[${this.pluginName}]: ` + `defaultInviteUserIds=${JSON.stringify(this.config.defaultInviteUserIds)} ` + `inviteUserIds=${JSON.stringify(this.config.inviteUserIds)} ` + `replyChannel.userId=${replyChannel?.userId ?? "(none)"} ` + `→ final userIds=${JSON.stringify(Array.from(ids))}`);
|
|
1427
1924
|
}
|
|
1428
1925
|
return Array.from(ids);
|
|
1429
1926
|
}
|