@downcity/plugins 1.0.29 → 1.0.34

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.
Files changed (77) hide show
  1. package/bin/BuiltinPlugins.js +2 -2
  2. package/bin/BuiltinPlugins.js.map +1 -1
  3. package/bin/asr/Config.d.ts +1 -1
  4. package/bin/asr/Config.d.ts.map +1 -1
  5. package/bin/auth/Plugin.d.ts +6 -6
  6. package/bin/auth/Plugin.d.ts.map +1 -1
  7. package/bin/auth/Plugin.js +29 -20
  8. package/bin/auth/Plugin.js.map +1 -1
  9. package/bin/auth/types/AuthPlugin.d.ts +19 -19
  10. package/bin/auth/types/AuthPlugin.d.ts.map +1 -1
  11. package/bin/auth/types/AuthPlugin.js +17 -17
  12. package/bin/auth/types/AuthPlugin.js.map +1 -1
  13. package/bin/chat/ChatPlugin.d.ts +1 -1
  14. package/bin/chat/ChatPlugin.d.ts.map +1 -1
  15. package/bin/chat/accounts/Store.d.ts +1 -1
  16. package/bin/chat/accounts/Store.d.ts.map +1 -1
  17. package/bin/chat/runtime/ChatChannelConfig.d.ts +1 -1
  18. package/bin/chat/runtime/ChatChannelConfig.d.ts.map +1 -1
  19. package/bin/chat/runtime/ChatChannelCore.d.ts +1 -1
  20. package/bin/chat/runtime/ChatChannelCore.d.ts.map +1 -1
  21. package/bin/chat/runtime/ChatQueueWorker.d.ts.map +1 -1
  22. package/bin/chat/runtime/ChatQueueWorker.js +2 -3
  23. package/bin/chat/runtime/ChatQueueWorker.js.map +1 -1
  24. package/bin/chat/runtime/PluginDispatch.js.map +1 -1
  25. package/bin/chat/runtime/PluginPoints.d.ts +3 -3
  26. package/bin/chat/runtime/PluginPoints.js +3 -3
  27. package/bin/chat/types/ChannelAccount.d.ts +1 -1
  28. package/bin/chat/types/ChannelAccount.d.ts.map +1 -1
  29. package/bin/index.d.ts +3 -3
  30. package/bin/index.d.ts.map +1 -1
  31. package/bin/index.js +2 -2
  32. package/bin/index.js.map +1 -1
  33. package/bin/shell/runtime/ShellActionRuntime.js +1 -1
  34. package/bin/shell/runtime/ShellActionRuntime.js.map +1 -1
  35. package/bin/shell/runtime/ShellRuntimeEnvironment.d.ts.map +1 -1
  36. package/bin/shell/runtime/ShellRuntimeEnvironment.js +6 -3
  37. package/bin/shell/runtime/ShellRuntimeEnvironment.js.map +1 -1
  38. package/bin/task/runtime/TaskRunnerRound.d.ts.map +1 -1
  39. package/bin/task/runtime/TaskRunnerRound.js +6 -3
  40. package/bin/task/runtime/TaskRunnerRound.js.map +1 -1
  41. package/bin/voice/Config.d.ts +1 -1
  42. package/bin/voice/Config.d.ts.map +1 -1
  43. package/bin/workboard/Plugin.d.ts +1 -1
  44. package/bin/workboard/Plugin.js +1 -1
  45. package/bin/workboard/runtime/Collector.d.ts.map +1 -1
  46. package/bin/workboard/runtime/Collector.js +3 -5
  47. package/bin/workboard/runtime/Collector.js.map +1 -1
  48. package/bin/workboard/runtime/Normalizer.d.ts +3 -3
  49. package/bin/workboard/runtime/Normalizer.d.ts.map +1 -1
  50. package/bin/workboard/runtime/Normalizer.js.map +1 -1
  51. package/bin/workboard/runtime/SessionSummary.d.ts +47 -0
  52. package/bin/workboard/runtime/SessionSummary.d.ts.map +1 -0
  53. package/bin/workboard/runtime/SessionSummary.js +51 -0
  54. package/bin/workboard/runtime/SessionSummary.js.map +1 -0
  55. package/package.json +2 -2
  56. package/src/BuiltinPlugins.ts +2 -2
  57. package/src/asr/Config.ts +1 -1
  58. package/src/auth/Plugin.ts +151 -134
  59. package/src/auth/types/AuthPlugin.ts +24 -24
  60. package/src/chat/ChatPlugin.ts +1 -1
  61. package/src/chat/accounts/ChannelAccountManager.ts +2 -2
  62. package/src/chat/accounts/Store.ts +1 -1
  63. package/src/chat/runtime/ChatChannelConfig.ts +1 -1
  64. package/src/chat/runtime/ChatChannelCore.ts +1 -1
  65. package/src/chat/runtime/ChatQueueWorker.ts +1 -5
  66. package/src/chat/runtime/PluginDispatch.ts +2 -2
  67. package/src/chat/runtime/PluginPoints.ts +3 -3
  68. package/src/chat/types/ChannelAccount.ts +1 -1
  69. package/src/index.ts +6 -6
  70. package/src/shell/runtime/ShellActionRuntime.ts +1 -1
  71. package/src/shell/runtime/ShellRuntimeEnvironment.ts +7 -3
  72. package/src/task/runtime/TaskRunnerRound.ts +7 -3
  73. package/src/voice/Config.ts +1 -1
  74. package/src/workboard/Plugin.ts +1 -1
  75. package/src/workboard/runtime/Collector.ts +3 -5
  76. package/src/workboard/runtime/Normalizer.ts +5 -5
  77. package/src/workboard/runtime/SessionSummary.ts +92 -0
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  import crypto from "node:crypto";
11
- import type { StoredChannelAccountChannel } from "@downcity/agent/internal/types/runtime/host/Store.js";
11
+ import type { StoredChannelAccountChannel } from "@downcity/agent/internal/types/platform/Store.js";
12
12
  import { resolveChatChannelBotInfo } from "@/chat/channels/BotInfoProvider.js";
13
13
  import {
14
14
  getStoredChannelAccountSync,
@@ -24,7 +24,7 @@ import type {
24
24
  ChatChannelAccountProbeResult,
25
25
  ChatChannelAccountUpsertInput,
26
26
  } from "@/chat/types/ChannelAccount.js";
27
- import type { StoredChannelAccount } from "@downcity/agent/internal/types/runtime/host/Store.js";
27
+ import type { StoredChannelAccount } from "@downcity/agent/internal/types/platform/Store.js";
28
28
 
29
29
  const SUPPORTED_CHANNELS: readonly StoredChannelAccountChannel[] = [
30
30
  "telegram",
@@ -20,7 +20,7 @@ import type {
20
20
  StoredChannelAccount,
21
21
  StoredChannelAccountChannel,
22
22
  UpsertChannelAccountInput,
23
- } from "@downcity/agent/internal/types/runtime/host/Store.js";
23
+ } from "@downcity/agent/internal/types/platform/Store.js";
24
24
 
25
25
  function nowIso(): string {
26
26
  return new Date().toISOString();
@@ -11,7 +11,7 @@ import fs from "node:fs/promises";
11
11
  import path from "node:path";
12
12
  import type { JsonObject, JsonValue } from "@downcity/agent/internal/types/common/Json.js";
13
13
  import type { AgentContext } from "@downcity/agent/internal/types/runtime/agent/AgentContext.js";
14
- import type { StoredChannelAccount } from "@downcity/agent/internal/types/runtime/host/Store.js";
14
+ import type { StoredChannelAccount } from "@downcity/agent/internal/types/platform/Store.js";
15
15
  import type {
16
16
  ChatChannelName,
17
17
  ChatChannelStateSnapshot,
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  import type { AgentContext } from "@downcity/agent/internal/types/runtime/agent/AgentContext.js";
11
- import type { StoredChannelAccount } from "@downcity/agent/internal/types/runtime/host/Store.js";
11
+ import type { StoredChannelAccount } from "@downcity/agent/internal/types/platform/Store.js";
12
12
  import type { ChatChannelName } from "@/chat/types/ChannelStatus.js";
13
13
  import type { ChatChannelState } from "@/chat/types/ChatRuntime.js";
14
14
  import { getStoredChannelAccountSync } from "@/chat/accounts/Store.js";
@@ -18,7 +18,6 @@ import {
18
18
  } from "./ChatQueue.js";
19
19
  import { getChatSender } from "./ChatSendRegistry.js";
20
20
  import {
21
- hasPersistedAssistantSteps,
22
21
  pickLastSuccessfulChatSendText,
23
22
  } from "@downcity/agent/internal/executor/messages/UserVisibleText.js";
24
23
  import {
@@ -439,10 +438,7 @@ export class ChatQueueWorker {
439
438
  return;
440
439
  }
441
440
 
442
- if (
443
- observation.assistantStepDispatched ||
444
- hasPersistedAssistantSteps(result.assistantMessage)
445
- ) {
441
+ if (observation.assistantStepDispatched) {
446
442
  return;
447
443
  }
448
444
 
@@ -9,7 +9,7 @@
9
9
  import type { AgentContext } from "@downcity/agent/internal/types/runtime/agent/AgentContext.js";
10
10
  import type { JsonObject } from "@downcity/agent/internal/types/common/Json.js";
11
11
  import type {
12
- AuthObservePrincipalPayload,
12
+ ChatAuthorizationObservePrincipalPayload,
13
13
  ChatAuthorizationEvaluateInput,
14
14
  ChatAuthorizationRole,
15
15
  } from "@/auth/types/AuthPlugin.js";
@@ -40,7 +40,7 @@ export async function observeIncomingChatPrincipal(params: {
40
40
  ...(params.chatTitle ? { chatTitle: params.chatTitle } : {}),
41
41
  ...(params.userId ? { userId: params.userId } : {}),
42
42
  ...(params.username ? { username: params.username } : {}),
43
- } as AuthObservePrincipalPayload as unknown as JsonObject);
43
+ } as ChatAuthorizationObservePrincipalPayload as unknown as JsonObject);
44
44
  }
45
45
 
46
46
  /**
@@ -56,7 +56,7 @@ export const CHAT_PLUGIN_POINTS = {
56
56
  *
57
57
  * 说明(中文)
58
58
  * - 仅做副作用记录,不返回值。
59
- * - 典型实现方是 auth plugin。
59
+ * - 典型实现方是 chat-authorization plugin。
60
60
  */
61
61
  observePrincipal: "chat.observePrincipal",
62
62
  /**
@@ -64,7 +64,7 @@ export const CHAT_PLUGIN_POINTS = {
64
64
  *
65
65
  * 说明(中文)
66
66
  * - 由 chat plugin runtime 在 ingress 阶段显式调用。
67
- * - 典型实现方是 auth plugin。
67
+ * - 典型实现方是 chat-authorization plugin。
68
68
  */
69
69
  authorizeIncoming: "chat.authorizeIncoming",
70
70
  /**
@@ -72,7 +72,7 @@ export const CHAT_PLUGIN_POINTS = {
72
72
  *
73
73
  * 说明(中文)
74
74
  * - 主要用于在 history / queue metadata 中补齐授权上下文。
75
- * - 典型实现方是 auth plugin。
75
+ * - 典型实现方是 chat-authorization plugin。
76
76
  */
77
77
  resolveUserRole: "chat.resolveUserRole",
78
78
  } as const;
@@ -6,7 +6,7 @@
6
6
  * - 凭据明文只允许出现在写入输入中,读取结果必须是脱敏后的安全视图。
7
7
  */
8
8
 
9
- import type { StoredChannelAccountChannel } from "@downcity/agent/internal/types/runtime/host/Store.js";
9
+ import type { StoredChannelAccountChannel } from "@downcity/agent/internal/types/platform/Store.js";
10
10
 
11
11
  /**
12
12
  * 支持的 chat channel account 类型。
package/src/index.ts CHANGED
@@ -14,7 +14,7 @@ export {
14
14
  export type { BuiltinPluginClass } from "./BuiltinPlugins.js";
15
15
  export { ChatPlugin } from "./chat/ChatPlugin.js";
16
16
  export { ChatChannelAccountManager } from "./chat/accounts/ChannelAccountManager.js";
17
- export { AuthPlugin } from "./auth/Plugin.js";
17
+ export { ChatAuthorizationPlugin } from "./auth/Plugin.js";
18
18
  export { SkillPlugin } from "./skill/Plugin.js";
19
19
  export { WebPlugin } from "./web/Plugin.js";
20
20
  export { AsrPlugin } from "./asr/Plugin.js";
@@ -28,6 +28,7 @@ export {
28
28
  export { resolveAuthorizedUserRole } from "./auth/runtime/AuthorizationPolicy.js";
29
29
  export {
30
30
  CHAT_AUTHORIZATION_CHANNELS,
31
+ CHAT_AUTHORIZATION_PLUGIN_NAME,
31
32
  createDefaultChatAuthorizationRoles,
32
33
  isChatAuthorizationChannel,
33
34
  } from "./auth/types/AuthPlugin.js";
@@ -42,23 +43,22 @@ export type {
42
43
  ChatPluginTelegramOptions,
43
44
  } from "./chat/ChatPluginTypes.js";
44
45
  export type {
45
- AuthObservePrincipalPayload,
46
- AuthObservePrincipalResult,
47
- AuthResolveUserRolePayload,
48
- AuthSetUserRolePayload,
49
- AuthWriteConfigPayload,
50
46
  ChatAuthorizationCatalog,
51
47
  ChatAuthorizationChannel,
52
48
  ChatAuthorizationConfig,
53
49
  ChatAuthorizationDecision,
54
50
  ChatAuthorizationEvaluateInput,
55
51
  ChatAuthorizationEvaluateResult,
52
+ ChatAuthorizationObservePrincipalPayload,
56
53
  ChatAuthorizationObservedChat,
57
54
  ChatAuthorizationObservedUser,
58
55
  ChatAuthorizationPermission,
59
56
  ChatAuthorizationPermissionMeta,
57
+ ChatAuthorizationResolveUserRolePayload,
60
58
  ChatAuthorizationRole,
59
+ ChatAuthorizationSetUserRolePayload,
61
60
  ChatAuthorizationSnapshot,
62
61
  ChatAuthorizationStateFile,
62
+ ChatAuthorizationWriteConfigPayload,
63
63
  ChatChannelAuthorizationConfig,
64
64
  } from "./auth/types/AuthPlugin.js";
@@ -9,7 +9,7 @@
9
9
 
10
10
  import fs from "fs-extra";
11
11
  import type { AgentContext } from "@downcity/agent/internal/types/runtime/agent/AgentContext.js";
12
- import { spawnShellProcess } from "@downcity/agent/internal/runtime/sandbox/SandboxRunner.js";
12
+ import { spawnShellProcess } from "@downcity/agent/internal/sandbox/SandboxRunner.js";
13
13
  import type {
14
14
  ShellPluginState,
15
15
  ShellSessionRuntimeState,
@@ -8,9 +8,13 @@
8
8
 
9
9
  import path from "node:path";
10
10
  import type { AgentContext } from "@downcity/agent/internal/types/runtime/agent/AgentContext.js";
11
- import { stripInvocationAuthEnv } from "@downcity/agent/internal/runtime/auth/AuthEnv.js";
12
11
  import { getSessionRunScope } from "@downcity/agent/internal/executor/SessionRunScope.js";
13
12
 
13
+ function stripShellSecretEnv(env: NodeJS.ProcessEnv): void {
14
+ delete env.DC_AUTH_TOKEN;
15
+ delete env.DC_AGENT_TOKEN;
16
+ }
17
+
14
18
  /**
15
19
  * 构造 shell 子进程环境变量。
16
20
  */
@@ -36,13 +40,13 @@ export function buildShellEnv(context: AgentContext): NodeJS.ProcessEnv {
36
40
  // 关键点(中文)
37
41
  // - agent 自己在 shell 里执行 `town <service> ...` 时,也需要显式知道“当前 agent 是谁”。
38
42
  // - 否则 service CLI 会退回到当前终端 cwd / registry 猜测,在多 agent 或外部工作目录下
39
- // 很容易把请求发到错误项目,最终误报 “Agent server 没启动”。
43
+ // 很容易把请求发到错误项目,最终误报 “Agent runtime 没启动”。
40
44
  if (agentPath) env.DC_AGENT_PATH = agentPath;
41
45
  if (agentId) env.DC_AGENT_ID = agentId;
42
46
  if (sessionId) env.DC_SESSION_ID = sessionId;
43
47
  if (process.env.DC_CITY_HOST) env.DC_CITY_HOST = process.env.DC_CITY_HOST;
44
48
  if (process.env.DC_CITY_PORT) env.DC_CITY_PORT = process.env.DC_CITY_PORT;
45
- stripInvocationAuthEnv(env);
49
+ stripShellSecretEnv(env);
46
50
 
47
51
  return env;
48
52
  }
@@ -8,9 +8,8 @@
8
8
 
9
9
  import path from "node:path";
10
10
  import fs from "fs-extra";
11
- import { stripInvocationAuthEnv } from "@downcity/agent/internal/runtime/auth/AuthEnv.js";
12
11
  import type { AgentContext } from "@downcity/agent/internal/types/runtime/agent/AgentContext.js";
13
- import { runSandboxCommand } from "@downcity/agent/internal/runtime/sandbox/SandboxRunner.js";
12
+ import { runSandboxCommand } from "@downcity/agent/internal/sandbox/SandboxRunner.js";
14
13
  import type { SessionRunResult } from "@downcity/agent/internal/executor/types/SessionRun.js";
15
14
  import type { JsonObject } from "@downcity/agent/internal/types/common/Json.js";
16
15
  import type {
@@ -23,6 +22,11 @@ import type {
23
22
  import { withSessionRunScope } from "@downcity/agent/internal/executor/SessionRunScope.js";
24
23
  import { appendTaskRoundUserMessage } from "./TaskRunnerSession.js";
25
24
 
25
+ function stripTaskSecretEnv(env: NodeJS.ProcessEnv): void {
26
+ delete env.DC_AUTH_TOKEN;
27
+ delete env.DC_AGENT_TOKEN;
28
+ }
29
+
26
30
  /**
27
31
  * 从文本中提取 JSON 对象(支持 ```json 代码块)。
28
32
  */
@@ -288,7 +292,7 @@ export async function runScriptTask(params: {
288
292
  ...process.env,
289
293
  DC_SESSION_ID: params.sessionId,
290
294
  };
291
- stripInvocationAuthEnv(childEnv);
295
+ stripTaskSecretEnv(childEnv);
292
296
  return runSandboxCommand({
293
297
  context: params.context,
294
298
  shellId: `task-script:${params.sessionId}`,
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  import type { VoicePluginConfig } from "@/voice/types/VoicePlugin.js";
10
- import type { AgentPluginConfigRuntime } from "@downcity/agent/internal/types/runtime/host/AgentHost.js";
10
+ import type { AgentPluginConfigRuntime } from "@downcity/agent/internal/types/agent/AgentRuntimeAssembly.js";
11
11
  import type { JsonObject, JsonValue } from "@downcity/agent/internal/types/common/Json.js";
12
12
 
13
13
  /**
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * 关键点(中文)
5
5
  * - workboard 是一个 runtime 观测面板插件,负责提供结构化工作快照。
6
- * - 当前同时通过 plugin action 与 HTTP 注入提供快照,供 Town/RPC 与旧 HTTP 宿主复用。
6
+ * - 当前同时通过 plugin action 与 HTTP 注入提供快照,供 Town RPC Town HTTP gateway 复用。
7
7
  */
8
8
 
9
9
  import type { AgentRuntime } from "@downcity/agent/internal/types/runtime/agent/AgentRuntime.js";
@@ -8,9 +8,9 @@
8
8
 
9
9
  import { listTaskDefinitions } from "@/task/Action.js";
10
10
  import { listPluginStates } from "@downcity/agent/internal/plugin/core/Manager.js";
11
- import { listControlSessionSummaries } from "@downcity/agent/internal/runtime/control/SessionSummaryStore.js";
12
11
  import type { AgentContext } from "@downcity/agent/internal/types/runtime/agent/AgentContext.js";
13
12
  import type { WorkboardSnapshot } from "@/workboard/types/Workboard.js";
13
+ import { listWorkboardSessionSummaries } from "@/workboard/runtime/SessionSummary.js";
14
14
  import {
15
15
  buildIdleActivity,
16
16
  toRecentActivity,
@@ -30,10 +30,8 @@ export async function collectWorkboardSnapshot(
30
30
  ): Promise<WorkboardSnapshot> {
31
31
  const collectedAt = new Date().toISOString();
32
32
  const executingSessionIds = new Set(context.session.listExecutingSessionIds());
33
- const sessions = await listControlSessionSummaries({
34
- projectRoot: context.rootPath,
35
- agentId: context.paths.agentId,
36
- executionContext: context,
33
+ const sessions = await listWorkboardSessionSummaries({
34
+ context,
37
35
  limit: WORKBOARD_RECENT_LIMIT + Math.max(executingSessionIds.size, 1),
38
36
  executingSessionIds,
39
37
  });
@@ -6,9 +6,9 @@
6
6
  * - 所有会泄漏上下文的字段都必须在这里截断或抽象。
7
7
  */
8
8
 
9
- import type { ControlSessionSummary } from "@downcity/agent/internal/runtime/control/types/ControlViewData.js";
10
9
  import type { PluginStateSnapshot } from "@downcity/agent/internal/plugin/types/PluginState.js";
11
10
  import type { TaskListResponse } from "@/task/types/TaskCommand.js";
11
+ import type { WorkboardSessionSummary } from "@/workboard/runtime/SessionSummary.js";
12
12
  import type {
13
13
  WorkboardActivityItem,
14
14
  WorkboardAgentSummary,
@@ -59,7 +59,7 @@ function buildMomentum(params: { currentCount: number; recentCount: number }): s
59
59
  return "安静";
60
60
  }
61
61
 
62
- function buildRunningSummary(item: ControlSessionSummary): string {
62
+ function buildRunningSummary(item: WorkboardSessionSummary): string {
63
63
  const messageCount = typeof item.messageCount === "number" ? item.messageCount : 0;
64
64
  if (messageCount >= 24) return "正在延展一段较长的工作脉络,并持续生成新的内容。";
65
65
  if (messageCount >= 8) return "正在承接连续输入,逐步形成新的阶段结果。";
@@ -67,7 +67,7 @@ function buildRunningSummary(item: ControlSessionSummary): string {
67
67
  return "当前处于活跃展开之中。";
68
68
  }
69
69
 
70
- function buildRecentSummary(item: ControlSessionSummary, index: number): string {
70
+ function buildRecentSummary(item: WorkboardSessionSummary, index: number): string {
71
71
  const messageCount = typeof item.messageCount === "number" ? item.messageCount : 0;
72
72
  if (index === 0 && messageCount > 0) return "刚刚完成一段新的展开,正在短暂停留。";
73
73
  if (messageCount >= 12) return "近期完成了一次较长的内容延展。";
@@ -103,7 +103,7 @@ export function toWorkboardAgentSummary(params: {
103
103
  * 将运行中的 session 映射为对外安全活动项。
104
104
  */
105
105
  export function toRunningActivity(params: {
106
- item: ControlSessionSummary;
106
+ item: WorkboardSessionSummary;
107
107
  index: number;
108
108
  }): WorkboardActivityItem {
109
109
  const title = params.index === 0 ? "当前主线" : `当前并行线 ${params.index + 1}`;
@@ -123,7 +123,7 @@ export function toRunningActivity(params: {
123
123
  * 将近期 session 映射为对外安全活动项。
124
124
  */
125
125
  export function toRecentActivity(params: {
126
- item: ControlSessionSummary;
126
+ item: WorkboardSessionSummary;
127
127
  index: number;
128
128
  }): WorkboardActivityItem {
129
129
  const title = params.index === 0 ? "最近一次更新" : `近期片段 ${params.index + 1}`;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Workboard session 摘要采集。
3
+ *
4
+ * 关键点(中文)
5
+ * - workboard 只需要模糊运行态,不复用 Town control 视图模型。
6
+ * - 这里只读取消息数量、更新时间与执行中状态,不暴露消息内容。
7
+ */
8
+
9
+ import fs from "fs-extra";
10
+ import path from "node:path";
11
+ import type { AgentContext } from "@downcity/agent/internal/types/runtime/agent/AgentContext.js";
12
+
13
+ /**
14
+ * Workboard 内部 session 摘要。
15
+ */
16
+ export interface WorkboardSessionSummary {
17
+ /**
18
+ * session 稳定标识,仅供内部排序和执行态匹配使用,不会进入公开输出。
19
+ */
20
+ sessionId: string;
21
+ /**
22
+ * 当前 session 消息数量。
23
+ */
24
+ messageCount: number;
25
+ /**
26
+ * 最近更新时间戳。
27
+ */
28
+ updatedAt?: number;
29
+ /**
30
+ * 当前 session 是否仍在执行。
31
+ */
32
+ executing?: boolean;
33
+ }
34
+
35
+ /**
36
+ * 采集 workboard 需要的 session 摘要。
37
+ */
38
+ export async function listWorkboardSessionSummaries(params: {
39
+ /**
40
+ * Agent runtime context。
41
+ */
42
+ context: AgentContext;
43
+ /**
44
+ * 返回上限。
45
+ */
46
+ limit: number;
47
+ /**
48
+ * 正在执行的 session id 集合。
49
+ */
50
+ executingSessionIds?: Set<string>;
51
+ }): Promise<WorkboardSessionSummary[]> {
52
+ const root_dir = params.context.paths.getDowncitySessionRootDirPath();
53
+ if (!(await fs.pathExists(root_dir))) return [];
54
+
55
+ const entries = await fs.readdir(root_dir, { withFileTypes: true });
56
+ const items: WorkboardSessionSummary[] = [];
57
+
58
+ for (const entry of entries) {
59
+ if (!entry.isDirectory()) continue;
60
+ const session_id = decodeMaybe(entry.name);
61
+ if (!session_id) continue;
62
+ const messages_path = path.join(
63
+ params.context.paths.getDowncitySessionDirPath(session_id),
64
+ "messages",
65
+ "messages.jsonl",
66
+ );
67
+ const stat = await fs.stat(messages_path).catch(() => null);
68
+ items.push({
69
+ sessionId: session_id,
70
+ messageCount: await countJsonlLines(messages_path),
71
+ ...(stat ? { updatedAt: stat.mtimeMs } : {}),
72
+ ...(params.executingSessionIds?.has(session_id) ? { executing: true } : {}),
73
+ });
74
+ }
75
+
76
+ items.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));
77
+ return items.slice(0, Math.max(1, params.limit));
78
+ }
79
+
80
+ async function countJsonlLines(file_path: string): Promise<number> {
81
+ const raw = await fs.readFile(file_path, "utf-8").catch(() => "");
82
+ if (!raw) return 0;
83
+ return raw.split("\n").filter((line) => line.trim()).length;
84
+ }
85
+
86
+ function decodeMaybe(value: string): string {
87
+ try {
88
+ return decodeURIComponent(String(value || "")).trim();
89
+ } catch {
90
+ return String(value || "").trim();
91
+ }
92
+ }