@ai-setting/roy-agent-core 1.7.93 → 1.7.94

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.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  builtInHandlers
3
- } from "./roy-agent-core-33n84tf9.js";
3
+ } from "./roy-agent-core-w9qpbpa1.js";
4
4
  import {
5
5
  appendAuditLog,
6
6
  checkSourceCountDrop,
@@ -33,7 +33,7 @@ import {
33
33
  createLarkCardStateStore,
34
34
  getSharedLarkCardNotifier,
35
35
  humanizeValue
36
- } from "./roy-agent-core-0yzxapfa.js";
36
+ } from "./roy-agent-core-stcr4w4f.js";
37
37
  import {
38
38
  RECENT_MESSAGE_LIMIT
39
39
  } from "./roy-agent-core-418zc9ha.js";
@@ -1795,7 +1795,8 @@ var execAsync = promisify(exec);
1795
1795
  var KNOWN_CARD_ACTIONS = new Set([
1796
1796
  "create_group",
1797
1797
  "disband_group",
1798
- "refresh_activity"
1798
+ "refresh_activity",
1799
+ "select_task"
1799
1800
  ]);
1800
1801
  function isCardActionName(v) {
1801
1802
  return typeof v === "string" && KNOWN_CARD_ACTIONS.has(v);
@@ -1803,7 +1804,8 @@ function isCardActionName(v) {
1803
1804
  var ACTION_SUBJECT_FIELD = {
1804
1805
  create_group: "taskId or sessionId",
1805
1806
  disband_group: "taskId or sessionId",
1806
- refresh_activity: "sessionId"
1807
+ refresh_activity: "sessionId",
1808
+ select_task: "taskId or sessionId"
1807
1809
  };
1808
1810
  function validateCardActionValue(raw) {
1809
1811
  const action = raw.action;
@@ -1844,6 +1846,25 @@ function validateCardActionValue(raw) {
1844
1846
  error: `Missing required field: ${requiredField} (action=${action})`
1845
1847
  };
1846
1848
  }
1849
+ if (action === "select_task") {
1850
+ const rawTaskId = raw.taskId;
1851
+ const taskId = typeof rawTaskId === "number" ? rawTaskId : typeof rawTaskId === "string" ? parseInt(rawTaskId, 10) : Number.NaN;
1852
+ if (rawTaskId === undefined || rawTaskId === null || rawTaskId === "") {
1853
+ return {
1854
+ ok: false,
1855
+ action,
1856
+ error: `Missing required field: taskId (action=${action}; sessionId=${sessionId})`
1857
+ };
1858
+ }
1859
+ if (!Number.isFinite(taskId) || Number.isNaN(taskId) || taskId <= 0) {
1860
+ return {
1861
+ ok: false,
1862
+ action,
1863
+ error: `Invalid taskId: ${String(rawTaskId)} (action=${action})`
1864
+ };
1865
+ }
1866
+ return { ok: true, action, sessionId, taskId };
1867
+ }
1847
1868
  return { ok: true, action, sessionId };
1848
1869
  }
1849
1870
  function extractTargetSessionId(context) {
@@ -1923,6 +1944,13 @@ async function handleCardAction(event, ports) {
1923
1944
  if (validation.action === "refresh_activity") {
1924
1945
  return await handleRefreshSessionCard(event, ports);
1925
1946
  }
1947
+ if (validation.action === "select_task") {
1948
+ const sel = validation;
1949
+ return await handleSelectTask(event, ports, {
1950
+ sessionId: sel.sessionId,
1951
+ taskId: sel.taskId
1952
+ });
1953
+ }
1926
1954
  const groupValidation = validation;
1927
1955
  const action = groupValidation.action;
1928
1956
  const taskId = groupValidation.taskId;
@@ -2292,6 +2320,14 @@ function parseTaskIdLoose(raw) {
2292
2320
  async function handleRefreshSessionActivity(event, ports, subject) {
2293
2321
  const action = "refresh_activity";
2294
2322
  const sessionId = subject.sessionId;
2323
+ if (subject.taskId !== undefined && ports.notifier?.isTaskCardMessage?.(event.messageId) && !ports.notifier?.isSessionCardMessage?.(event.messageId)) {
2324
+ logger6.info(`handleRefreshSessionActivity: messageId=${event.messageId} 是 task 卡 ` + `(task #${subject.taskId}),refresh_activity 委托 task 路径(保持卡身份)`);
2325
+ const taskCard = await ports.getTask?.(subject.taskId);
2326
+ if (taskCard) {
2327
+ return await handleRefreshActivity(event, ports, taskCard, subject.taskId);
2328
+ }
2329
+ logger6.warn(`handleRefreshSessionActivity: task #${subject.taskId} 读取失败,` + `refresh_activity 回落 session 路径`);
2330
+ }
2295
2331
  let probe;
2296
2332
  try {
2297
2333
  probe = await ports.loadSessionActivity?.(sessionId);
@@ -2310,13 +2346,16 @@ async function handleRefreshSessionActivity(event, ports, subject) {
2310
2346
  logger6.warn(`handleRefreshSessionActivity: loadSessionMessages failed for ${sessionId}: ` + `${err.message}(降级为不渲染最近消息面板)`);
2311
2347
  recentMessages = undefined;
2312
2348
  }
2349
+ const sessionTaskList = await loadSessionTasksSafe(sessionId, ports);
2350
+ const sessionTasks = sessionTaskList.tasks;
2313
2351
  const snapshot = probe?.activity ?? null;
2314
2352
  const sessionAlive = probe?.activity !== undefined && !probe?.terminal;
2315
2353
  const lifecycle = probe?.lifecycle ? probe.lifecycle : probe?.terminal ? "completed" : sessionAlive ? "running" : taskEnrichment?.lifecycle ?? "running";
2316
2354
  const preserved = ports.notifier?.buildSessionCardWithActivity?.(event.messageId, sessionId, snapshot, {
2317
2355
  lifecycle,
2318
2356
  task: taskEnrichment?.info,
2319
- ...recentMessages !== undefined ? { recentMessages } : {}
2357
+ ...recentMessages !== undefined ? { recentMessages } : {},
2358
+ sessionTasks
2320
2359
  });
2321
2360
  if (preserved) {
2322
2361
  logger6.debug(`handleRefreshSessionActivity: ${sessionId} 活性已刷新 ` + `(messageCount=${snapshot?.messageCount ?? "n/a"}, task=${subject.taskId ?? "none"})`);
@@ -2331,9 +2370,118 @@ async function handleRefreshSessionActivity(event, ports, subject) {
2331
2370
  sessionId,
2332
2371
  activity: snapshot,
2333
2372
  lifecycle,
2373
+ ...sessionTasks.length > 0 ? { tasks: sessionTasks } : {},
2374
+ ...sessionTaskList.total !== undefined ? { taskTotal: sessionTaskList.total } : {},
2334
2375
  ...taskEnrichment?.info ? { task: taskEnrichment.info } : {},
2335
2376
  ...groupChat?.chatId ? { perTaskChatId: groupChat.chatId } : {},
2336
- ...recentMessages !== undefined ? { recentMessages } : {}
2377
+ ...recentMessages !== undefined ? { recentMessages } : {},
2378
+ ...sessionTasks.length > 0 ? { tasks: sessionTasks } : {}
2379
+ })
2380
+ };
2381
+ }
2382
+ function toTaskSummary(raw) {
2383
+ if (!raw || typeof raw !== "object")
2384
+ return;
2385
+ const r = raw;
2386
+ const id = typeof r.id === "number" ? r.id : typeof r.id === "string" ? parseInt(r.id, 10) : Number.NaN;
2387
+ if (!Number.isFinite(id) || id <= 0)
2388
+ return;
2389
+ const currentStatus = typeof r.currentStatus === "string" ? r.currentStatus : typeof r.current_status === "string" ? r.current_status : undefined;
2390
+ const goals = typeof r.goals === "string" ? r.goals : typeof r.goals_and_expected_deliverables === "string" ? r.goals_and_expected_deliverables : undefined;
2391
+ const parentTaskId = typeof r.parentTaskId === "number" ? r.parentTaskId : typeof r.parent_task_id === "number" && r.parent_task_id > 0 ? r.parent_task_id : undefined;
2392
+ const createdAt = typeof r.createdAt === "string" ? r.createdAt : typeof r.created_at === "string" ? r.created_at : undefined;
2393
+ const updatedAt = typeof r.updatedAt === "string" ? r.updatedAt : typeof r.updated_at === "string" ? r.updated_at : undefined;
2394
+ return {
2395
+ id,
2396
+ ...typeof r.title === "string" && r.title ? { title: r.title } : {},
2397
+ ...typeof r.status === "string" && r.status ? { status: r.status } : {},
2398
+ ...typeof r.progress === "number" ? { progress: r.progress } : {},
2399
+ ...currentStatus ? { currentStatus } : {},
2400
+ ...typeof r.priority === "string" && r.priority ? { priority: r.priority } : {},
2401
+ ...parentTaskId !== undefined ? { parentTaskId } : {},
2402
+ ...goals ? { goals } : {},
2403
+ ...createdAt ? { createdAt } : {},
2404
+ ...updatedAt ? { updatedAt } : {}
2405
+ };
2406
+ }
2407
+ async function loadSessionTasksSafe(sessionId, ports) {
2408
+ try {
2409
+ const raw = await ports.loadSessionTasks?.(sessionId);
2410
+ const list = Array.isArray(raw) ? raw : raw?.tasks;
2411
+ if (!Array.isArray(list))
2412
+ return { tasks: [] };
2413
+ const tasks = list.map((t) => toTaskSummary(t)).filter((t) => t !== undefined);
2414
+ const total = !Array.isArray(raw) && typeof raw?.total === "number" ? raw.total : undefined;
2415
+ return { tasks, ...total !== undefined ? { total } : {} };
2416
+ } catch (err) {
2417
+ logger6.warn(`loadSessionTasksSafe: ${sessionId} 读取失败(任务列表面板降级为空): ` + `${err.message}`);
2418
+ return { tasks: [] };
2419
+ }
2420
+ }
2421
+ async function handleSelectTask(event, ports, subject) {
2422
+ const action = "select_task";
2423
+ const { sessionId, taskId } = subject;
2424
+ const taskListResult = await loadSessionTasksSafe(sessionId, ports);
2425
+ const tasks = taskListResult.tasks;
2426
+ if (tasks.length > 0 && !tasks.some((t) => t.id === taskId)) {
2427
+ logger6.warn(`handleSelectTask: task #${taskId} 不属于 ${sessionId}(列表 ${tasks.length} 个)→ 忽略本次切换`);
2428
+ return {
2429
+ ok: false,
2430
+ action,
2431
+ error: `task #${taskId} is not a member of session ${sessionId}`
2432
+ };
2433
+ }
2434
+ let selectedTask;
2435
+ try {
2436
+ const raw = await ports.getTask?.(taskId);
2437
+ selectedTask = toTaskSummary(raw);
2438
+ } catch (err) {
2439
+ logger6.warn(`handleSelectTask: getTask(${taskId}) 失败(降级为不渲染任务详情): ` + `${err.message}`);
2440
+ selectedTask = undefined;
2441
+ }
2442
+ if (!selectedTask) {
2443
+ selectedTask = tasks.find((t) => t.id === taskId);
2444
+ }
2445
+ let milestones;
2446
+ try {
2447
+ const raw = await ports.loadTaskMilestones?.(taskId);
2448
+ milestones = Array.isArray(raw) ? raw : undefined;
2449
+ } catch (err) {
2450
+ logger6.warn(`handleSelectTask: loadTaskMilestones(${taskId}) 失败(里程碑区降级为空): ` + `${err.message}`);
2451
+ milestones = undefined;
2452
+ }
2453
+ let probe;
2454
+ try {
2455
+ probe = await ports.loadSessionActivity?.(sessionId);
2456
+ } catch (err) {
2457
+ logger6.warn(`handleSelectTask: loadSessionActivity(${sessionId}) 失败(沿用上次快照): ` + `${err.message}`);
2458
+ probe = undefined;
2459
+ }
2460
+ const stateActivity = ports.notifier?.getSessionCardState?.(sessionId)?.activity;
2461
+ const activitySnapshot = probe ? probe.activity ?? null : stateActivity ?? null;
2462
+ const patched = ports.notifier?.buildSessionCardWithActivity?.(event.messageId, sessionId, activitySnapshot, {
2463
+ ...probe?.lifecycle ? { lifecycle: probe.lifecycle } : {},
2464
+ sessionTasks: tasks,
2465
+ ...taskListResult.total !== undefined ? { taskTotal: taskListResult.total } : {},
2466
+ ...selectedTask ? { selectedTask } : {},
2467
+ ...milestones !== undefined ? { selectedTaskMilestones: milestones } : {}
2468
+ });
2469
+ if (patched) {
2470
+ logger6.debug(`handleSelectTask: ${sessionId} 切到 task #${taskId}(列表 ${tasks.length} 个任务)`);
2471
+ return { ok: true, action, cardUpdate: patched };
2472
+ }
2473
+ logger6.warn(`handleSelectTask: notifier 无 messageId=${event.messageId} 的状态,fallback 重建 session 卡`);
2474
+ return {
2475
+ ok: true,
2476
+ action,
2477
+ cardUpdate: buildSessionCard({
2478
+ sessionId,
2479
+ tasks,
2480
+ ...taskListResult.total !== undefined ? { taskTotal: taskListResult.total } : {},
2481
+ ...selectedTask ? { selectedTask } : {},
2482
+ ...milestones !== undefined ? { selectedTaskMilestones: milestones } : {},
2483
+ ...probe?.activity !== undefined ? { activity: probe.activity } : {},
2484
+ ...probe?.lifecycle ? { lifecycle: probe.lifecycle } : {}
2337
2485
  })
2338
2486
  };
2339
2487
  }
@@ -2600,6 +2748,7 @@ class LarkCliTaskNotifyHook {
2600
2748
  pluginName;
2601
2749
  sourceId;
2602
2750
  config;
2751
+ cardNotifyConfigReader;
2603
2752
  cardNotifier;
2604
2753
  cardMessageIds = new Map;
2605
2754
  cardStateStore;
@@ -2615,6 +2764,9 @@ class LarkCliTaskNotifyHook {
2615
2764
  this.description = "LarkCli 任务通知 Hook(卡片模式)";
2616
2765
  this.pluginName = config.pluginName;
2617
2766
  this.sourceId = config.sourceId;
2767
+ if (config.cardNotifyConfigReader) {
2768
+ this.cardNotifyConfigReader = config.cardNotifyConfigReader;
2769
+ }
2618
2770
  this.config = {
2619
2771
  enabled: true,
2620
2772
  priority: 5,
@@ -2639,6 +2791,17 @@ class LarkCliTaskNotifyHook {
2639
2791
  hasCardRoutingPorts() {
2640
2792
  return this.cardRoutingPorts !== undefined;
2641
2793
  }
2794
+ currentEmitTaskCard() {
2795
+ if (this.config.emitTaskCard !== undefined) {
2796
+ return this.config.emitTaskCard !== false;
2797
+ }
2798
+ try {
2799
+ const flags = this.cardNotifyConfigReader?.();
2800
+ if (flags)
2801
+ return flags.emitTaskCard !== false;
2802
+ } catch {}
2803
+ return true;
2804
+ }
2642
2805
  async execute(ctx) {
2643
2806
  if (!this.config.enabled) {
2644
2807
  return;
@@ -2676,6 +2839,7 @@ class LarkCliTaskNotifyHook {
2676
2839
  if (!this.isCardModeEnabled())
2677
2840
  return;
2678
2841
  const sessionId = typeof ctxSessionId === "string" && ctxSessionId.trim() ? ctxSessionId.trim() : this.resolveSessionIdForTask(task.id);
2842
+ const emitTaskCard = this.currentEmitTaskCard();
2679
2843
  if (sessionId) {
2680
2844
  const merged = await this.patchSessionCardForTask(task, {
2681
2845
  sessionId,
@@ -2689,8 +2853,9 @@ class LarkCliTaskNotifyHook {
2689
2853
  ]
2690
2854
  });
2691
2855
  if (merged) {
2692
- logger7.debug(`onAfterCreate: task #${task.id} 已渲染进 session 卡 ${sessionId}(单卡语义)`);
2693
- return;
2856
+ logger7.debug(`onAfterCreate: task #${task.id} 已渲染进 session 卡 ${sessionId}` + `(${emitTaskCard ? "并存:继续发任务卡片" : "单卡语义:不再发任务卡片"})`);
2857
+ if (!emitTaskCard)
2858
+ return;
2694
2859
  }
2695
2860
  }
2696
2861
  await this.sendCardStart(task);
@@ -2707,6 +2872,7 @@ class LarkCliTaskNotifyHook {
2707
2872
  return;
2708
2873
  if (!this.isCardModeEnabled())
2709
2874
  return;
2875
+ const emitTaskCardTerminal = this.currentEmitTaskCard();
2710
2876
  const sessionIdTerminal = this.resolveSessionIdForTask(task.id);
2711
2877
  if (sessionIdTerminal) {
2712
2878
  const mergedTerminal = await this.patchSessionCardForTask(task, {
@@ -2720,7 +2886,7 @@ class LarkCliTaskNotifyHook {
2720
2886
  }
2721
2887
  ]
2722
2888
  });
2723
- if (mergedTerminal)
2889
+ if (mergedTerminal && !emitTaskCardTerminal)
2724
2890
  return;
2725
2891
  }
2726
2892
  await this.sendCardFinish(task);
@@ -2738,13 +2904,14 @@ class LarkCliTaskNotifyHook {
2738
2904
  return;
2739
2905
  if (!this.isCardModeEnabled())
2740
2906
  return;
2907
+ const emitTaskCardUpdate = this.currentEmitTaskCard();
2741
2908
  const sessionIdUpdate = this.resolveSessionIdForTask(task.id);
2742
2909
  if (sessionIdUpdate) {
2743
2910
  const mergedUpdate = await this.patchSessionCardForTask(task, {
2744
2911
  sessionId: sessionIdUpdate,
2745
2912
  lifecycle: lifecycleOfTaskStatus(String(task.status)) ?? "running"
2746
2913
  });
2747
- if (mergedUpdate)
2914
+ if (mergedUpdate && !emitTaskCardUpdate)
2748
2915
  return;
2749
2916
  }
2750
2917
  await this.sendCardUpdate(task, changes);
@@ -2917,7 +3084,9 @@ class LarkCliTaskNotifyHook {
2917
3084
  if (rec.sessionId) {
2918
3085
  this.cardNotifier?.bindTaskToSession?.(taskId, rec.sessionId);
2919
3086
  if (rec.messageId) {
2920
- this.cardNotifier?.adoptSessionCard?.(rec.sessionId, rec.messageId);
3087
+ if (!this.currentEmitTaskCard()) {
3088
+ this.cardNotifier?.adoptSessionCard?.(rec.sessionId, rec.messageId);
3089
+ }
2921
3090
  }
2922
3091
  }
2923
3092
  if (!this.restoredTaskIds.has(taskId)) {
@@ -3485,6 +3654,8 @@ class LarkCliTaskNotifyHook {
3485
3654
  syncGroupCardFromOriginFn;
3486
3655
  recordSessionCardForTask(task, sessionId, chatId, profile, messageIdIn) {
3487
3656
  this.cardNotifier?.bindTaskToSession?.(task.id, sessionId);
3657
+ if (this.currentEmitTaskCard())
3658
+ return;
3488
3659
  if (!this.cardStateStore)
3489
3660
  return;
3490
3661
  const messageId = messageIdIn ?? this.cardNotifier?.getSessionCardMessageId?.(sessionId);
@@ -3578,6 +3749,12 @@ class LarkCliTaskNotifyHook {
3578
3749
  __legacyDecorateClassTS([
3579
3750
  TracedAs("lark-cli-task-notify.execute")
3580
3751
  ], LarkCliTaskNotifyHook.prototype, "execute", null);
3752
+ __legacyDecorateClassTS([
3753
+ TracedAs("lark-card.restoreState", {
3754
+ recordParams: true,
3755
+ paramFilter: (args) => ({ taskId: args[0] })
3756
+ })
3757
+ ], LarkCliTaskNotifyHook.prototype, "restoreCardState", null);
3581
3758
  __legacyDecorateClassTS([
3582
3759
  TracedAs("lark-cli-task-notify.resolveCardTarget", {
3583
3760
  recordParams: true,
@@ -3595,6 +3772,24 @@ __legacyDecorateClassTS([
3595
3772
  })
3596
3773
  })
3597
3774
  ], LarkCliTaskNotifyHook.prototype, "resolveCardTarget", null);
3775
+ __legacyDecorateClassTS([
3776
+ TracedAs("lark-card.sendStart", {
3777
+ recordParams: false,
3778
+ paramFilter: (args) => ({ taskId: args[0]?.id, sessionId: args[0]?.sessionId })
3779
+ })
3780
+ ], LarkCliTaskNotifyHook.prototype, "sendCardStart", null);
3781
+ __legacyDecorateClassTS([
3782
+ TracedAs("lark-card.patchForTask", {
3783
+ recordParams: true,
3784
+ flattenParamFilter: true,
3785
+ paramFilter: (args) => ({
3786
+ taskId: args[0]?.id,
3787
+ sessionId: args[0]?.sessionId,
3788
+ lifecycle: args[1]?.lifecycle,
3789
+ statusPhrase: args[1]?.statusPhrase
3790
+ })
3791
+ })
3792
+ ], LarkCliTaskNotifyHook.prototype, "patchSessionCardForTask", null);
3598
3793
  function createLarkCliTaskNotifyHook(config = {}) {
3599
3794
  return new LarkCliTaskNotifyHook(config);
3600
3795
  }
@@ -637,6 +637,47 @@ function renderProcessSteps(steps) {
637
637
  }).join(`
638
638
  `);
639
639
  }
640
+ var SESSION_TASK_LIST_MAX = 5;
641
+ function renderSessionTaskList(sessionId, tasks, taskTotal) {
642
+ const known = tasks.length;
643
+ const total = typeof taskTotal === "number" && taskTotal > known ? taskTotal : known;
644
+ const truncated = total > SESSION_TASK_LIST_MAX;
645
+ const recentFirst = [...tasks].sort((a, b) => b.id - a.id);
646
+ const ordered = recentFirst.slice(0, SESSION_TASK_LIST_MAX);
647
+ const title = truncated ? `\uD83D\uDCCB 任务列表(共 ${total} 个任务,最近 ${SESSION_TASK_LIST_MAX} 个)` : `\uD83D\uDCCB 任务列表(${total})`;
648
+ const elements = [];
649
+ if (truncated) {
650
+ elements.push({
651
+ tag: "markdown",
652
+ content: `**共 ${total} 个任务,最近 ${SESSION_TASK_LIST_MAX} 个:**`
653
+ });
654
+ }
655
+ for (const t of ordered) {
656
+ const label = t.title ? `#${t.id} ${t.title}` : `#${t.id}`;
657
+ elements.push({
658
+ tag: "button",
659
+ text: {
660
+ tag: "plain_text",
661
+ content: `▶ ${sanitizeInlineText(label, 40)}`
662
+ },
663
+ type: "default",
664
+ value: {
665
+ action: "select_task",
666
+ sessionId,
667
+ taskId: String(t.id)
668
+ }
669
+ });
670
+ const meta = [];
671
+ if (t.status)
672
+ meta.push(`\uD83D\uDEA6 ${sanitizeInlineText(t.status, 20)}`);
673
+ if (typeof t.progress === "number")
674
+ meta.push(`\uD83D\uDCCA ${Math.round(t.progress)}%`);
675
+ if (meta.length > 0) {
676
+ elements.push({ tag: "markdown", content: `  ${meta.join(" · ")}` });
677
+ }
678
+ }
679
+ return { title, elements };
680
+ }
640
681
  function milestoneKey(m) {
641
682
  return `${m.title}|${m.timestamp ?? ""}|${m.description ?? ""}`;
642
683
  }
@@ -796,7 +837,7 @@ function buildTaskCard(opts) {
796
837
  return {
797
838
  schema: "2.0",
798
839
  header: {
799
- title: { tag: "plain_text", content: `\uD83D\uDCCA Task 实时更新(${taskLabel})` },
840
+ title: { tag: "plain_text", content: `\uD83D\uDCCB 任务卡实时更新(${taskLabel})` },
800
841
  subtitle: {
801
842
  tag: "plain_text",
802
843
  content: `spinner: '${spinner}' · 第 ${updateCount} 次更新 | ` + STATUS_PHRASE[status]
@@ -865,7 +906,8 @@ function buildSessionCard(opts) {
865
906
  appendHr(elements);
866
907
  }
867
908
  const taskInfo = opts.task;
868
- if (taskInfo) {
909
+ const selectedDuplicatesBoundTask = taskInfo !== undefined && opts.selectedTask !== undefined && Number(opts.selectedTask.id) === Number(taskInfo.id);
910
+ if (taskInfo && !selectedDuplicatesBoundTask) {
869
911
  const taskLines = [];
870
912
  taskLines.push(`- **\uD83C\uDD94 任务 ID**:#${taskInfo.id}`);
871
913
  if (taskInfo.title) {
@@ -914,6 +956,39 @@ function buildSessionCard(opts) {
914
956
  appendHr(elements);
915
957
  }
916
958
  }
959
+ const taskList = opts.tasks ?? [];
960
+ if (taskList.length > 0) {
961
+ const listResult = renderSessionTaskList(opts.sessionId, taskList, opts.taskTotal);
962
+ elements.push(buildCollapsiblePanel({
963
+ title: listResult.title,
964
+ elementId: "session_task_list",
965
+ expanded: true,
966
+ elements: listResult.elements
967
+ }));
968
+ appendHr(elements);
969
+ }
970
+ if (opts.selectedTask) {
971
+ const sel = opts.selectedTask;
972
+ const selLines = [];
973
+ selLines.push(`- **\uD83C\uDD94 任务 ID**:#${sel.id}`);
974
+ if (sel.title)
975
+ selLines.push(`- **\uD83D\uDCCC 标题**:${sanitizeInlineText(sel.title, 120)}`);
976
+ if (sel.status)
977
+ selLines.push(`- **\uD83D\uDEA6 状态**:${sanitizeInlineText(sel.status, 40)}`);
978
+ if (typeof sel.progress === "number") {
979
+ selLines.push(`- **\uD83D\uDCCA 进度**:${renderProgressBar(sel.progress)}`);
980
+ }
981
+ if (sel.currentStatus) {
982
+ selLines.push(`- **\uD83D\uDCDD 当前状态**:${sanitizeInlineText(sel.currentStatus, 200)}`);
983
+ }
984
+ elements.push(buildCollapsiblePanel({
985
+ title: "\uD83D\uDCCB 任务信息",
986
+ elementId: "session_selected_task_detail",
987
+ elements: [{ tag: "markdown", content: selLines.join(`
988
+ `) }]
989
+ }));
990
+ appendHr(elements);
991
+ }
917
992
  if (opts.activity !== undefined) {
918
993
  elements.push(buildCollapsiblePanel({
919
994
  title: "⚡ 子会话活性",
@@ -953,6 +1028,21 @@ function buildSessionCard(opts) {
953
1028
  elements: [{ tag: "markdown", content: renderMilestones(milestones) }]
954
1029
  }));
955
1030
  }
1031
+ if (opts.selectedTask) {
1032
+ const selMilestones = opts.selectedTaskMilestones ?? [];
1033
+ elements.push(buildCollapsiblePanel({
1034
+ title: `\uD83D\uDCCC 任务里程碑(#${opts.selectedTask.id},${selMilestones.length})`,
1035
+ elementId: "session_task_milestones",
1036
+ expanded: selMilestones.length > 0,
1037
+ elements: [
1038
+ {
1039
+ tag: "markdown",
1040
+ content: selMilestones.length > 0 ? renderMilestones(selMilestones) : "(该任务暂无里程碑)"
1041
+ }
1042
+ ]
1043
+ }));
1044
+ appendHr(elements);
1045
+ }
956
1046
  const titleRaw = opts.title?.trim();
957
1047
  const headLabel = titleRaw ? truncateHeadTitle(titleRaw) : truncateHeadTitle(sessionId);
958
1048
  const lifecycle = opts.lifecycle ?? "running";
@@ -961,7 +1051,7 @@ function buildSessionCard(opts) {
961
1051
  return {
962
1052
  schema: "2.0",
963
1053
  header: {
964
- title: { tag: "plain_text", content: `\uD83D\uDCCA 子会话实时更新(${headLabel})` },
1054
+ title: { tag: "plain_text", content: `\uD83D\uDCAC 会话卡实时更新(${headLabel})` },
965
1055
  subtitle: {
966
1056
  tag: "plain_text",
967
1057
  content: `spinner: '${spinner}' · 第 ${updateCount} 次更新 | ${lifecyclePhrase}`
@@ -1159,6 +1249,7 @@ class LarkCardPatchNotifier {
1159
1249
  unpinOnFinish: false,
1160
1250
  ...(({ sessionCardStore: _scs, ...rest }) => rest)(options)
1161
1251
  };
1252
+ this.restoreSessionCardsFromStore();
1162
1253
  }
1163
1254
  mutexFor(messageId) {
1164
1255
  let m = this.mutexes.get(messageId);
@@ -1520,6 +1611,7 @@ class LarkCardPatchNotifier {
1520
1611
  ...opts.activity !== undefined ? { activity: opts.activity } : state.activity !== undefined ? { activity: state.activity } : {},
1521
1612
  ...opts.task !== undefined ? { task: opts.task } : state.task !== undefined ? { task: state.task } : {},
1522
1613
  ...opts.recentMessages !== undefined ? { recentMessages: opts.recentMessages } : state.recentMessages !== undefined ? { recentMessages: state.recentMessages } : {},
1614
+ ...opts.tasks !== undefined ? { tasks: opts.tasks, taskTotal: opts.tasks.length } : state.sessionTasks !== undefined ? { tasks: state.sessionTasks } : {},
1523
1615
  ...opts.perTaskChatId ?? state.perTaskChatId ? { perTaskChatId: opts.perTaskChatId ?? state.perTaskChatId } : {},
1524
1616
  ...opts.perTaskChatName ?? state.perTaskChatName ? { perTaskChatName: opts.perTaskChatName ?? state.perTaskChatName } : {}
1525
1617
  });
@@ -1535,6 +1627,7 @@ class LarkCardPatchNotifier {
1535
1627
  lifecycle: opts.lifecycle,
1536
1628
  ...opts.activity !== undefined ? { activity: opts.activity } : {},
1537
1629
  ...opts.task !== undefined ? { task: opts.task } : {},
1630
+ ...opts.tasks !== undefined ? { sessionTasks: opts.tasks, taskTotal: opts.tasks.length } : {},
1538
1631
  ...opts.perTaskChatId ? { perTaskChatId: opts.perTaskChatId } : {},
1539
1632
  ...opts.perTaskChatName ? { perTaskChatName: opts.perTaskChatName } : {}
1540
1633
  });
@@ -1558,6 +1651,9 @@ class LarkCardPatchNotifier {
1558
1651
  isSessionCardMessage(messageId) {
1559
1652
  return this.sessionStates.has(messageId);
1560
1653
  }
1654
+ isTaskCardMessage(messageId) {
1655
+ return this.states.has(messageId) || this.finalisedCards.has(messageId);
1656
+ }
1561
1657
  applyTaskEventToSessionCard(messageId, delta) {
1562
1658
  const state = this.sessionStates.get(messageId);
1563
1659
  if (!state) {
@@ -1787,6 +1883,7 @@ class LarkCardPatchNotifier {
1787
1883
  updateCount: 1,
1788
1884
  ...opts.activity !== undefined ? { activity: opts.activity } : {},
1789
1885
  ...opts.task !== undefined ? { task: opts.task } : {},
1886
+ ...opts.tasks !== undefined ? { tasks: opts.tasks, taskTotal: opts.tasks.length } : {},
1790
1887
  ...opts.perTaskChatId ? { perTaskChatId: opts.perTaskChatId } : {},
1791
1888
  ...opts.perTaskChatName ? { perTaskChatName: opts.perTaskChatName } : {}
1792
1889
  });
@@ -1812,6 +1909,7 @@ class LarkCardPatchNotifier {
1812
1909
  lifecycle: opts.lifecycle,
1813
1910
  ...opts.activity !== undefined ? { activity: opts.activity } : {},
1814
1911
  ...opts.task !== undefined ? { task: opts.task } : {},
1912
+ ...opts.tasks !== undefined ? { sessionTasks: opts.tasks, taskTotal: opts.tasks.length } : {},
1815
1913
  ...opts.perTaskChatId ? { perTaskChatId: opts.perTaskChatId } : {},
1816
1914
  ...opts.perTaskChatName ? { perTaskChatName: opts.perTaskChatName } : {}
1817
1915
  });
@@ -1847,6 +1945,10 @@ class LarkCardPatchNotifier {
1847
1945
  ...state.perTaskChatId ? { perTaskChatId: state.perTaskChatId } : {},
1848
1946
  ...state.perTaskChatName ? { perTaskChatName: state.perTaskChatName } : {},
1849
1947
  ...opts.recentMessages !== undefined ? { recentMessages: opts.recentMessages } : state.recentMessages !== undefined ? { recentMessages: state.recentMessages } : {},
1948
+ ...opts.sessionTasks !== undefined ? { tasks: opts.sessionTasks } : state.sessionTasks !== undefined ? { tasks: state.sessionTasks } : {},
1949
+ ...state.taskTotal !== undefined ? { taskTotal: state.taskTotal } : {},
1950
+ ...opts.selectedTask !== undefined ? { selectedTask: opts.selectedTask } : state.selectedTask !== undefined ? { selectedTask: state.selectedTask } : {},
1951
+ ...opts.selectedTaskMilestones !== undefined ? { selectedTaskMilestones: opts.selectedTaskMilestones } : state.selectedTaskMilestones !== undefined ? { selectedTaskMilestones: state.selectedTaskMilestones } : {},
1850
1952
  ...opts.now !== undefined ? { activityNow: opts.now } : {}
1851
1953
  });
1852
1954
  if (opts.task !== undefined) {
@@ -1863,6 +1965,20 @@ class LarkCardPatchNotifier {
1863
1965
  if (opts.lifecycle !== undefined) {
1864
1966
  this.rememberSessionCard(messageId, { lifecycle: opts.lifecycle });
1865
1967
  }
1968
+ if (opts.sessionTasks !== undefined) {
1969
+ this.rememberSessionCard(messageId, {
1970
+ sessionTasks: opts.sessionTasks,
1971
+ taskTotal: opts.sessionTasks.length
1972
+ });
1973
+ }
1974
+ if (opts.selectedTask !== undefined) {
1975
+ this.rememberSessionCard(messageId, { selectedTask: opts.selectedTask });
1976
+ }
1977
+ if (opts.selectedTaskMilestones !== undefined) {
1978
+ this.rememberSessionCard(messageId, {
1979
+ selectedTaskMilestones: opts.selectedTaskMilestones
1980
+ });
1981
+ }
1866
1982
  if (activity !== undefined) {
1867
1983
  this.rememberSessionCard(messageId, { activity });
1868
1984
  }
@@ -1885,7 +2001,11 @@ class LarkCardPatchNotifier {
1885
2001
  recentMessages: state.recentMessages !== undefined ? state.recentMessages : prev?.recentMessages,
1886
2002
  task: state.task ?? prev?.task,
1887
2003
  perTaskChatId: state.perTaskChatId ?? prev?.perTaskChatId,
1888
- perTaskChatName: state.perTaskChatName ?? prev?.perTaskChatName
2004
+ perTaskChatName: state.perTaskChatName ?? prev?.perTaskChatName,
2005
+ sessionTasks: state.sessionTasks !== undefined ? state.sessionTasks : prev?.sessionTasks,
2006
+ taskTotal: state.taskTotal ?? prev?.taskTotal,
2007
+ selectedTask: state.selectedTask ?? prev?.selectedTask,
2008
+ selectedTaskMilestones: state.selectedTaskMilestones !== undefined ? state.selectedTaskMilestones : prev?.selectedTaskMilestones
1889
2009
  });
1890
2010
  }
1891
2011
  finalisedCards = new Set;
@@ -2251,6 +2371,31 @@ __legacyDecorateClassTS([
2251
2371
  })
2252
2372
  })
2253
2373
  ], LarkCardPatchNotifier.prototype, "finishTask", null);
2374
+ __legacyDecorateClassTS([
2375
+ TracedAs("lark-card.adopt", {
2376
+ recordParams: true,
2377
+ paramFilter: (args) => ({ sessionId: args[0], messageId: args[1] })
2378
+ })
2379
+ ], LarkCardPatchNotifier.prototype, "adoptSessionCard", null);
2380
+ __legacyDecorateClassTS([
2381
+ TracedAs("lark-card.restore", { recordParams: false, recordResult: true })
2382
+ ], LarkCardPatchNotifier.prototype, "restoreSessionCardsFromStore", null);
2383
+ __legacyDecorateClassTS([
2384
+ TracedAs("lark-card.upsert", {
2385
+ recordParams: true,
2386
+ flattenParamFilter: true,
2387
+ paramFilter: (args) => {
2388
+ const o = args[0] ?? {};
2389
+ return {
2390
+ chatId: o.chatId,
2391
+ sessionId: o.sessionId,
2392
+ title: o.title,
2393
+ statusPhrase: o.statusPhrase,
2394
+ lifecycle: o.lifecycle
2395
+ };
2396
+ }
2397
+ })
2398
+ ], LarkCardPatchNotifier.prototype, "upsertSessionCard", null);
2254
2399
  __legacyDecorateClassTS([
2255
2400
  TracedAs("lark-card.startWorkflow", {
2256
2401
  recordParams: true,
@@ -2386,4 +2531,4 @@ function hasSharedLarkCardNotifier() {
2386
2531
  return sharedNotifier !== undefined;
2387
2532
  }
2388
2533
 
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 };
2534
+ export { MemoryLarkCardStateStore, SqliteLarkCardStateStore, getDefaultLarkCardDbPath, createLarkCardStateStore, getSharedLarkCardStateStore, formatTimestampForDisplay, sanitizeInlineText, HEAD_TITLE_MAX_WIDTH, truncateHeadTitle, formatDateTimeForDisplay, renderProgressBar, resolveTaskTitleForDisplay, humanizeValue, isTerminalStatusForTimeline, isTerminalStatusForWorkflowTimeline, buildCollapsiblePanel, renderTaskInfoLines, renderContextAsLines, renderMilestones, renderProcessSteps, SESSION_TASK_LIST_MAX, renderSessionTaskList, partitionProcessSteps, buildTaskCard, buildSessionCard, buildChatAppLink, DEFAULT_APP_LINK_BASE, formatDurationMs, renderWorkflowInfoLines, buildWorkflowCard, LarkCardPatchNotifier, getSharedLarkCardNotifier, __resetSharedLarkCardNotifierForTest, hasSharedLarkCardNotifier };