sema-core 2.0.0 → 2.0.1

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 (172) hide show
  1. package/dist/core/Conversation.d.ts.map +1 -1
  2. package/dist/core/Conversation.js +22 -22
  3. package/dist/core/Conversation.js.map +1 -1
  4. package/dist/core/RunTools.d.ts.map +1 -1
  5. package/dist/core/RunTools.js +6 -6
  6. package/dist/core/RunTools.js.map +1 -1
  7. package/dist/core/SemaCore.d.ts +20 -24
  8. package/dist/core/SemaCore.d.ts.map +1 -1
  9. package/dist/core/SemaCore.js +50 -40
  10. package/dist/core/SemaCore.js.map +1 -1
  11. package/dist/core/SemaEngine.d.ts +24 -15
  12. package/dist/core/SemaEngine.d.ts.map +1 -1
  13. package/dist/core/SemaEngine.js +116 -206
  14. package/dist/core/SemaEngine.js.map +1 -1
  15. package/dist/core/SemaSession.d.ts +43 -0
  16. package/dist/core/SemaSession.d.ts.map +1 -0
  17. package/dist/core/SemaSession.js +72 -0
  18. package/dist/core/SemaSession.js.map +1 -0
  19. package/dist/core/SessionPool.d.ts +32 -0
  20. package/dist/core/SessionPool.d.ts.map +1 -0
  21. package/dist/core/SessionPool.js +89 -0
  22. package/dist/core/SessionPool.js.map +1 -0
  23. package/dist/events/EventSystem.d.ts +40 -12
  24. package/dist/events/EventSystem.d.ts.map +1 -1
  25. package/dist/events/EventSystem.js +83 -25
  26. package/dist/events/EventSystem.js.map +1 -1
  27. package/dist/events/types.d.ts +11 -5
  28. package/dist/events/types.d.ts.map +1 -1
  29. package/dist/index.d.ts +1 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +3 -1
  32. package/dist/index.js.map +1 -1
  33. package/dist/manager/CronManager.d.ts +16 -5
  34. package/dist/manager/CronManager.d.ts.map +1 -1
  35. package/dist/manager/CronManager.js +46 -19
  36. package/dist/manager/CronManager.js.map +1 -1
  37. package/dist/manager/PermissionManager.d.ts +2 -2
  38. package/dist/manager/PermissionManager.d.ts.map +1 -1
  39. package/dist/manager/PermissionManager.js +18 -19
  40. package/dist/manager/PermissionManager.js.map +1 -1
  41. package/dist/manager/StateManager.d.ts +63 -134
  42. package/dist/manager/StateManager.d.ts.map +1 -1
  43. package/dist/manager/StateManager.js +140 -197
  44. package/dist/manager/StateManager.js.map +1 -1
  45. package/dist/manager/TaskManager.d.ts +28 -10
  46. package/dist/manager/TaskManager.d.ts.map +1 -1
  47. package/dist/manager/TaskManager.js +100 -39
  48. package/dist/manager/TaskManager.js.map +1 -1
  49. package/dist/prompt/design/design.d.ts.map +1 -1
  50. package/dist/prompt/design/design.js +15 -9
  51. package/dist/prompt/design/design.js.map +1 -1
  52. package/dist/prompt/system.d.ts +1 -1
  53. package/dist/prompt/system.d.ts.map +1 -1
  54. package/dist/prompt/system.js +5 -2
  55. package/dist/prompt/system.js.map +1 -1
  56. package/dist/services/agents/genSystemPrompt.d.ts +1 -1
  57. package/dist/services/agents/genSystemPrompt.js +1 -1
  58. package/dist/services/api/adapt/anthropic.d.ts +1 -1
  59. package/dist/services/api/adapt/anthropic.d.ts.map +1 -1
  60. package/dist/services/api/adapt/anthropic.js +7 -7
  61. package/dist/services/api/adapt/anthropic.js.map +1 -1
  62. package/dist/services/api/adapt/openai.d.ts +1 -1
  63. package/dist/services/api/adapt/openai.d.ts.map +1 -1
  64. package/dist/services/api/adapt/openai.js +7 -7
  65. package/dist/services/api/adapt/openai.js.map +1 -1
  66. package/dist/services/api/adapt/util.d.ts +2 -2
  67. package/dist/services/api/adapt/util.d.ts.map +1 -1
  68. package/dist/services/api/adapt/util.js +4 -4
  69. package/dist/services/api/adapt/util.js.map +1 -1
  70. package/dist/services/api/cache.d.ts +1 -1
  71. package/dist/services/api/cache.d.ts.map +1 -1
  72. package/dist/services/api/cache.js +7 -7
  73. package/dist/services/api/cache.js.map +1 -1
  74. package/dist/services/api/queryLLM.d.ts +14 -1
  75. package/dist/services/api/queryLLM.d.ts.map +1 -1
  76. package/dist/services/api/queryLLM.js +17 -17
  77. package/dist/services/api/queryLLM.js.map +1 -1
  78. package/dist/services/commands/runCommand.d.ts +1 -1
  79. package/dist/services/commands/runCommand.d.ts.map +1 -1
  80. package/dist/services/commands/runCommand.js +26 -26
  81. package/dist/services/commands/runCommand.js.map +1 -1
  82. package/dist/tools/CreateCron.d.ts +1 -1
  83. package/dist/tools/CreateCron.d.ts.map +1 -1
  84. package/dist/tools/CreateCron.js +2 -2
  85. package/dist/tools/CreateCron.js.map +1 -1
  86. package/dist/tools/CreateTodo.js +1 -1
  87. package/dist/tools/CreateTodo.js.map +1 -1
  88. package/dist/tools/EditNotebook.js +2 -2
  89. package/dist/tools/EditNotebook.js.map +1 -1
  90. package/dist/tools/FetchUrl.js +1 -1
  91. package/dist/tools/FetchUrl.js.map +1 -1
  92. package/dist/tools/GetTodo.js +1 -1
  93. package/dist/tools/GetTodo.js.map +1 -1
  94. package/dist/tools/ListTodos.js +1 -1
  95. package/dist/tools/ListTodos.js.map +1 -1
  96. package/dist/tools/PatchFile.js +2 -2
  97. package/dist/tools/PatchFile.js.map +1 -1
  98. package/dist/tools/PeekBgJob.d.ts.map +1 -1
  99. package/dist/tools/PeekBgJob.js +4 -3
  100. package/dist/tools/PeekBgJob.js.map +1 -1
  101. package/dist/tools/PickOption.js +3 -3
  102. package/dist/tools/PickOption.js.map +1 -1
  103. package/dist/tools/PlanToAgent.d.ts.map +1 -1
  104. package/dist/tools/PlanToAgent.js +10 -11
  105. package/dist/tools/PlanToAgent.js.map +1 -1
  106. package/dist/tools/RunShell.js +1 -1
  107. package/dist/tools/RunShell.js.map +1 -1
  108. package/dist/tools/SubAgent.d.ts.map +1 -1
  109. package/dist/tools/SubAgent.js +20 -17
  110. package/dist/tools/SubAgent.js.map +1 -1
  111. package/dist/tools/UpdateTodo.js +1 -1
  112. package/dist/tools/UpdateTodo.js.map +1 -1
  113. package/dist/tools/ViewFile.js +1 -1
  114. package/dist/tools/ViewFile.js.map +1 -1
  115. package/dist/tools/WriteFile.js +2 -2
  116. package/dist/tools/WriteFile.js.map +1 -1
  117. package/dist/tools/base/tools.d.ts +2 -2
  118. package/dist/tools/base/tools.d.ts.map +1 -1
  119. package/dist/tools/base/tools.js +10 -4
  120. package/dist/tools/base/tools.js.map +1 -1
  121. package/dist/types/agent.d.ts +2 -0
  122. package/dist/types/agent.d.ts.map +1 -1
  123. package/dist/types/cron.d.ts +1 -0
  124. package/dist/types/cron.d.ts.map +1 -1
  125. package/dist/types/index.d.ts +2 -0
  126. package/dist/types/index.d.ts.map +1 -1
  127. package/dist/types/index.js.map +1 -1
  128. package/dist/types/session.d.ts +18 -0
  129. package/dist/types/session.d.ts.map +1 -0
  130. package/dist/types/session.js +3 -0
  131. package/dist/types/session.js.map +1 -0
  132. package/dist/types/task.d.ts +2 -0
  133. package/dist/types/task.d.ts.map +1 -1
  134. package/dist/util/compact.d.ts +2 -2
  135. package/dist/util/compact.d.ts.map +1 -1
  136. package/dist/util/compact.js +6 -7
  137. package/dist/util/compact.js.map +1 -1
  138. package/dist/util/file.d.ts +2 -0
  139. package/dist/util/file.d.ts.map +1 -1
  140. package/dist/util/file.js +11 -0
  141. package/dist/util/file.js.map +1 -1
  142. package/dist/util/fileReference.d.ts.map +1 -1
  143. package/dist/util/fileReference.js +4 -0
  144. package/dist/util/fileReference.js.map +1 -1
  145. package/dist/util/logLLM.d.ts +3 -3
  146. package/dist/util/logLLM.d.ts.map +1 -1
  147. package/dist/util/logLLM.js +10 -15
  148. package/dist/util/logLLM.js.map +1 -1
  149. package/dist/util/message.d.ts +1 -1
  150. package/dist/util/message.d.ts.map +1 -1
  151. package/dist/util/message.js +6 -6
  152. package/dist/util/message.js.map +1 -1
  153. package/dist/util/notifyRegistry.d.ts +18 -0
  154. package/dist/util/notifyRegistry.d.ts.map +1 -0
  155. package/dist/util/notifyRegistry.js +28 -0
  156. package/dist/util/notifyRegistry.js.map +1 -0
  157. package/dist/util/process.d.ts.map +1 -1
  158. package/dist/util/process.js +3 -4
  159. package/dist/util/process.js.map +1 -1
  160. package/dist/util/quickchat.d.ts +1 -1
  161. package/dist/util/quickchat.d.ts.map +1 -1
  162. package/dist/util/quickchat.js +12 -10
  163. package/dist/util/quickchat.js.map +1 -1
  164. package/dist/util/session.d.ts +4 -0
  165. package/dist/util/session.d.ts.map +1 -1
  166. package/dist/util/session.js +8 -1
  167. package/dist/util/session.js.map +1 -1
  168. package/dist/util/shell.d.ts +2 -0
  169. package/dist/util/shell.d.ts.map +1 -1
  170. package/dist/util/shell.js +20 -1
  171. package/dist/util/shell.js.map +1 -1
  172. package/package.json +1 -1
@@ -1,5 +1,15 @@
1
1
  "use strict";
2
2
  /**
3
+ * 多会话状态管理
4
+ *
5
+ * 两层隔离:sessionId → agentId
6
+ * - StateManager 是单例注册表,持有 Map<sessionId, SessionRuntime>
7
+ * - SessionRuntime 持有单个会话的全部状态:
8
+ * - 按 agentId 隔离:statesMap / messageHistoryMap / readFileTimestampsMap / todosMap / todoTasksMap
9
+ * (agentId='main' 为该会话主代理,子代理为各自 taskId)
10
+ * - 会话级:abortController / 输入队列 / 编辑权限 / Plan&Design 模式标记 / 前台 agent 集合
11
+ * - 会话级配置:agentMode / useTools
12
+ *
3
13
  * 子代理不触发 conversation:usage、message:chunk、tool:execution:chunk、state:update、todos:update、topic:update
4
14
  * 子代理相关事件 message:complete、tool:execution:complete、tool:execution:error、session:interrupted、tool:permission:request 有agentId字段
5
15
  */
@@ -37,7 +47,7 @@ var __importStar = (this && this.__importStar) || (function () {
37
47
  };
38
48
  })();
39
49
  Object.defineProperty(exports, "__esModule", { value: true });
40
- exports.getStateManager = exports.StateManager = exports.MAIN_AGENT_ID = void 0;
50
+ exports.getStateManager = exports.StateManager = exports.SessionRuntime = exports.MAIN_AGENT_ID = void 0;
41
51
  const crypto = __importStar(require("crypto"));
42
52
  const EventSystem_1 = require("../events/EventSystem");
43
53
  const log_1 = require("../util/log");
@@ -46,90 +56,49 @@ const ConfManager_1 = require("./ConfManager");
46
56
  // 主代理固定 ID
47
57
  exports.MAIN_AGENT_ID = 'main';
48
58
  /**
49
- * 全局状态管理器
50
- * 负责管理会话状态并发送状态更新事件
51
- *
52
- * 隔离状态(按 agentId):
53
- * - statesMap: 代理状态 (currentState/previousState)
54
- * - messageHistoryMap: 消息历史
55
- * - readFileTimestampsMap: 文件读取时间戳
56
- * - todosMap: todos 列表
57
- *
58
- * 共享状态:
59
- * - sessionId: 会话ID
60
- * - globalEditPermissionGranted: 全局编辑权限
61
- * - currentAbortController: 中断控制器
59
+ * 单个会话的运行时状态
60
+ * 由 StateManager 按 sessionId 持有
62
61
  */
63
- class StateManager {
64
- constructor() {
65
- // === 隔离状态(按 agentId) ===
62
+ class SessionRuntime {
63
+ constructor(sessionId) {
64
+ this.sessionId = sessionId;
65
+ // === 按 agentId 隔离 ===
66
66
  this.statesMap = new Map();
67
67
  this.messageHistoryMap = new Map();
68
68
  this.readFileTimestampsMap = new Map();
69
69
  this.todosMap = new Map();
70
70
  this.todoTasksMap = new Map();
71
71
  this.fileLineEndingsMap = new Map();
72
- // === 共享状态 ===
73
- this.sessionId = null;
72
+ // === 会话级状态 ===
73
+ this.currentAbortController = null;
74
74
  this.globalEditPermissionGranted = false;
75
75
  this.planModeInfoSent = false;
76
76
  this.designModeInfoSent = false;
77
- this.currentAbortController = null;
78
77
  // 当前正在运行的前台 agent taskId 集合
79
78
  this.foregroundAgents = new Set();
80
- // 待处理用户输入队列(共享状态)
79
+ // 待处理用户输入队列
81
80
  this.pendingUserInputs = [];
82
- // 私有构造函数,确保单例模式
83
- }
84
- /**
85
- * 获取StateManager实例(单例模式)
86
- */
87
- static getInstance() {
88
- if (!StateManager.instance) {
89
- StateManager.instance = new StateManager();
90
- }
91
- return StateManager.instance;
92
- }
93
- /**
94
- * 获取当前会话ID
95
- */
96
- getSessionId() {
97
- return this.sessionId;
98
- }
99
- /**
100
- * 设置会话ID
101
- */
102
- setSessionId(sessionId) {
103
- this.sessionId = sessionId;
104
- // 新建会话时重置全局编辑权限
105
- this.globalEditPermissionGranted = false;
106
- (0, log_1.logInfo)(`会话ID已设置: ${sessionId},全局编辑权限已重置`);
81
+ // === 会话级配置(从全局 coreConfig 下沉到会话级)===
82
+ this.agentMode = 'Agent';
83
+ // 会话级系统提示快照:首次构建后冻结,整个会话不再变化
84
+ this.systemPromptContent = null;
107
85
  }
108
86
  // ============================================================
109
87
  // 消息历史管理(按代理隔离)
110
88
  // ============================================================
111
- /**
112
- * 设置消息历史
113
- */
114
89
  setMessageHistory(messages, agentId = exports.MAIN_AGENT_ID, skipAutoSave = false) {
115
90
  this.messageHistoryMap.set(agentId, messages);
116
91
  // 主代理设置消息历史时自动保存
117
- if (!skipAutoSave && agentId === exports.MAIN_AGENT_ID && this.sessionId && messages.length > 0) {
92
+ if (!skipAutoSave && agentId === exports.MAIN_AGENT_ID && messages.length > 0) {
118
93
  this.saveSessionHistory();
119
94
  }
120
95
  }
121
- /**
122
- * 获取消息历史
123
- */
124
96
  getMessageHistory(agentId = exports.MAIN_AGENT_ID) {
125
97
  return this.messageHistoryMap.get(agentId) || [];
126
98
  }
127
99
  // ============================================================
128
100
  // 文件读取时间戳管理(按代理隔离)
129
101
  // ============================================================
130
- /**
131
- * 获取文件读取时间戳
132
- */
133
102
  getReadFileTimestamps(agentId = exports.MAIN_AGENT_ID) {
134
103
  let timestamps = this.readFileTimestampsMap.get(agentId);
135
104
  if (!timestamps) {
@@ -138,37 +107,22 @@ class StateManager {
138
107
  }
139
108
  return timestamps;
140
109
  }
141
- /**
142
- * 设置单个文件的读取时间戳
143
- */
144
110
  setReadFileTimestamp(filePath, timestamp, agentId = exports.MAIN_AGENT_ID) {
145
111
  const timestamps = this.getReadFileTimestamps(agentId);
146
112
  timestamps[filePath] = timestamp;
147
113
  }
148
- /**
149
- * 批量设置文件读取时间戳(覆盖)
150
- */
151
114
  setReadFileTimestamps(timestamps, agentId = exports.MAIN_AGENT_ID) {
152
115
  this.readFileTimestampsMap.set(agentId, { ...timestamps });
153
116
  }
154
- /**
155
- * 获取单个文件的读取时间戳
156
- */
157
117
  getReadFileTimestamp(filePath, agentId = exports.MAIN_AGENT_ID) {
158
118
  return this.getReadFileTimestamps(agentId)[filePath];
159
119
  }
160
120
  // ============================================================
161
121
  // 文件换行符缓存(按代理隔离)
162
122
  // ============================================================
163
- /**
164
- * 获取缓存的文件换行符类型
165
- */
166
123
  getFileLineEnding(filePath, agentId = exports.MAIN_AGENT_ID) {
167
124
  return this.fileLineEndingsMap.get(agentId)?.[filePath];
168
125
  }
169
- /**
170
- * 缓存文件的换行符类型
171
- */
172
126
  setFileLineEnding(filePath, ending, agentId = exports.MAIN_AGENT_ID) {
173
127
  let endings = this.fileLineEndingsMap.get(agentId);
174
128
  if (!endings) {
@@ -180,74 +134,50 @@ class StateManager {
180
134
  // ============================================================
181
135
  // todos 管理(按代理隔离)
182
136
  // ============================================================
183
- /**
184
- * 获取 todos 列表
185
- */
186
137
  getTodos(agentId = exports.MAIN_AGENT_ID) {
187
138
  return this.todosMap.get(agentId) || [];
188
139
  }
189
- /**
190
- * 设置 todos 列表
191
- */
192
140
  setTodos(todos, agentId = exports.MAIN_AGENT_ID) {
193
141
  this.todosMap.set(agentId, todos);
194
142
  }
195
- /**
196
- * 清理指定代理的 todos
197
- */
198
143
  clearAgentTodos(agentId) {
199
144
  if (agentId !== exports.MAIN_AGENT_ID) {
200
145
  this.todosMap.delete(agentId);
201
146
  (0, log_1.logInfo)(`[${agentId}] todos已清理`);
202
147
  }
203
148
  }
204
- /**
205
- * 智能更新 todos 列表
206
- * 如果传入的 todos 都有 id 且是现有 todos 的子集,则进行子集更新,否则进行完全替换
207
- */
208
149
  updateTodosIntelligently(newTodos, agentId = exports.MAIN_AGENT_ID) {
209
150
  const currentTodos = this.todosMap.get(agentId) || [];
210
151
  if (newTodos.length === 0) {
211
- // 空数组直接替换
212
152
  this.todosMap.set(agentId, newTodos);
213
153
  (0, log_1.logInfo)(`[${agentId}] todos完全替换: ${newTodos.length} 项`);
214
- // 只有主代理才发送事件
215
154
  if (agentId === exports.MAIN_AGENT_ID) {
216
155
  this.emitTodosUpdateEvent(newTodos);
217
156
  }
218
157
  return;
219
158
  }
220
- // 检查是否为子集更新
221
159
  const isSubsetUpdate = newTodos.every(todo => todo.id && currentTodos.some(existing => existing.id === todo.id));
222
160
  if (isSubsetUpdate && currentTodos.length > 0) {
223
- // 子集更新:更新现有 todos 中匹配的项
224
161
  const updatedTodos = currentTodos.map(existing => {
225
162
  const update = newTodos.find(todo => todo.id === existing.id);
226
163
  return update || existing;
227
164
  });
228
165
  this.todosMap.set(agentId, updatedTodos);
229
166
  (0, log_1.logInfo)(`[${agentId}] todos子集更新: ${newTodos.length} 项更新,总共 ${updatedTodos.length} 项`);
230
- // 只有主代理才发送事件
231
167
  if (agentId === exports.MAIN_AGENT_ID) {
232
168
  this.emitTodosUpdateEvent(newTodos);
233
169
  }
234
170
  }
235
171
  else {
236
- // 完全替换:有新的 id 或没有 id 的情况
237
172
  this.todosMap.set(agentId, newTodos);
238
173
  (0, log_1.logInfo)(`[${agentId}] todos完全替换: ${newTodos.length} 项`);
239
- // 只有主代理才发送事件
240
174
  if (agentId === exports.MAIN_AGENT_ID) {
241
175
  this.emitTodosUpdateEvent(newTodos);
242
176
  }
243
177
  }
244
178
  }
245
- /**
246
- * 发送 todos 更新事件
247
- */
248
179
  emitTodosUpdateEvent(todos) {
249
- const eventBus = (0, EventSystem_1.getEventBus)();
250
- eventBus.emit('todos:update', todos);
180
+ (0, EventSystem_1.getEventBus)().emit('todos:update', todos, this.sessionId);
251
181
  }
252
182
  // ============================================================
253
183
  // TodoTask CRUD(按代理隔离)
@@ -262,7 +192,6 @@ class StateManager {
262
192
  }
263
193
  createTodoTask(agentId, task) {
264
194
  const tasks = this.getTodoTasks(agentId);
265
- // 递增数字编号:取当前最大 id + 1
266
195
  const maxId = tasks.reduce((max, t) => Math.max(max, parseInt(t.id, 10) || 0), 0);
267
196
  const id = String(maxId + 1);
268
197
  const now = Date.now();
@@ -309,7 +238,6 @@ class StateManager {
309
238
  if (idx === -1)
310
239
  return false;
311
240
  tasks.splice(idx, 1);
312
- // 清理其他任务中对被删任务的引用
313
241
  for (const t of tasks) {
314
242
  t.blocks = t.blocks.filter(id => id !== taskId);
315
243
  t.blockedBy = t.blockedBy.filter(id => id !== taskId);
@@ -318,17 +246,12 @@ class StateManager {
318
246
  this.syncTodoTasksToTodos(agentId);
319
247
  return true;
320
248
  }
321
- /**
322
- * 建立阻塞关系:fromId 阻塞 toId(toId 需等待 fromId 完成)
323
- * 双向写入保持一致性
324
- */
325
249
  blockTask(agentId, fromId, toId) {
326
250
  const tasks = this.getTodoTasks(agentId);
327
251
  const fromTask = tasks.find(t => t.id === fromId);
328
252
  const toTask = tasks.find(t => t.id === toId);
329
253
  if (!fromTask || !toTask)
330
254
  return false;
331
- // 去重追加
332
255
  if (!fromTask.blocks.includes(toId)) {
333
256
  fromTask.blocks.push(toId);
334
257
  fromTask.updatedAt = Date.now();
@@ -341,11 +264,7 @@ class StateManager {
341
264
  this.syncTodoTasksToTodos(agentId);
342
265
  return true;
343
266
  }
344
- /**
345
- * 从持久化数据恢复 TodoTask 列表(主代理)
346
- */
347
267
  restoreTodoTasks(tasks) {
348
- // 兼容旧数据:补充 blocks/blockedBy 默认值
349
268
  const normalized = tasks.map(t => ({
350
269
  ...t,
351
270
  blocks: t.blocks ?? [],
@@ -354,12 +273,9 @@ class StateManager {
354
273
  this.todoTasksMap.set(exports.MAIN_AGENT_ID, normalized);
355
274
  (0, log_1.logInfo)(`TodoTasks restored: ${tasks.length} 项`);
356
275
  }
357
- /**
358
- * 从旧版 TodoItem 格式恢复为 TodoTask(兼容旧历史数据)
359
- */
360
276
  restoreTodoTasksFromLegacy(todos) {
361
277
  const now = Date.now();
362
- const tasks = todos.map((todo, index) => ({
278
+ const tasks = todos.map((todo) => ({
363
279
  id: todo.id || crypto.randomBytes(4).toString('hex'),
364
280
  title: todo.title,
365
281
  description: todo.title,
@@ -373,12 +289,8 @@ class StateManager {
373
289
  this.todoTasksMap.set(exports.MAIN_AGENT_ID, tasks);
374
290
  (0, log_1.logInfo)(`TodoTasks restored from legacy todos: ${tasks.length} 项`);
375
291
  }
376
- /**
377
- * 将 TodoTask 列表同步到 todosMap 并触发 UI 更新事件
378
- */
379
292
  syncTodoTasksToTodos(agentId) {
380
293
  const tasks = this.getTodoTasks(agentId);
381
- // 排序:completed > in_progress > pending;pending 中被阻塞的排最后
382
294
  const statusOrder = { completed: 0, in_progress: 1, pending: 2 };
383
295
  const completedIds = new Set(tasks.filter(t => t.status === 'completed').map(t => t.id));
384
296
  const sorted = [...tasks].sort((a, b) => {
@@ -386,7 +298,6 @@ class StateManager {
386
298
  const ob = statusOrder[b.status] ?? 3;
387
299
  if (oa !== ob)
388
300
  return oa - ob;
389
- // 同为 pending 时,被阻塞(且阻塞者未完成)的排后面
390
301
  if (a.status === 'pending' && b.status === 'pending') {
391
302
  const aBlocked = a.blockedBy.some(id => !completedIds.has(id));
392
303
  const bBlocked = b.blockedBy.some(id => !completedIds.has(id));
@@ -409,9 +320,6 @@ class StateManager {
409
320
  // ============================================================
410
321
  // 代理状态管理(按代理隔离)
411
322
  // ============================================================
412
- /**
413
- * 获取代理状态
414
- */
415
323
  getAgentState(agentId) {
416
324
  let state = this.statesMap.get(agentId);
417
325
  if (!state) {
@@ -426,18 +334,13 @@ class StateManager {
426
334
  */
427
335
  updateState(newState, agentId = exports.MAIN_AGENT_ID) {
428
336
  const agentState = this.getAgentState(agentId);
429
- // 添加调试日志
430
- (0, log_1.logInfo)(`updateState: agentId=${agentId}, current=${agentState.currentState}, new=${newState}, sessionId=${this.sessionId}`);
337
+ (0, log_1.logInfo)(`updateState: sessionId=${this.sessionId}, agentId=${agentId}, current=${agentState.currentState}, new=${newState}`);
431
338
  if (agentState.currentState !== newState) {
432
339
  agentState.previousState = agentState.currentState;
433
340
  agentState.currentState = newState;
434
- // 只有主代理才发送全局状态更新事件(直接使用 eventBus,参见方法注释)
435
341
  if (agentId === exports.MAIN_AGENT_ID) {
436
- const eventBus = (0, EventSystem_1.getEventBus)();
437
- const stateData = {
438
- state: newState
439
- };
440
- eventBus.emit('state:update', stateData);
342
+ const stateData = { state: newState };
343
+ (0, EventSystem_1.getEventBus)().emit('state:update', stateData, this.sessionId);
441
344
  (0, log_1.logInfo)(`状态更新: ${agentState.previousState} → ${newState}`);
442
345
  }
443
346
  else {
@@ -448,14 +351,11 @@ class StateManager {
448
351
  (0, log_1.logInfo)(`updateState: 状态未变化`);
449
352
  }
450
353
  }
451
- /**
452
- * 获取当前状态
453
- */
454
354
  getCurrentState(agentId = exports.MAIN_AGENT_ID) {
455
355
  return this.getAgentState(agentId).currentState;
456
356
  }
457
357
  // ============================================================
458
- // 前台 Agent 管理(共享状态)
358
+ // 前台 Agent 管理(会话级)
459
359
  // ============================================================
460
360
  addForegroundAgent(taskId) {
461
361
  this.foregroundAgents.add(taskId);
@@ -470,24 +370,14 @@ class StateManager {
470
370
  this.foregroundAgents.clear();
471
371
  }
472
372
  // ============================================================
473
- // 待处理用户输入队列管理(共享状态)
373
+ // 待处理用户输入队列管理(会话级)
474
374
  // ============================================================
475
- /**
476
- * 添加待处理输入到队列末尾
477
- */
478
375
  addPendingUserInput(item) {
479
376
  this.pendingUserInputs.push(item);
480
377
  }
481
- /**
482
- * 获取待处理输入队列长度
483
- */
484
378
  getPendingUserInputsLength() {
485
379
  return this.pendingUserInputs.length;
486
380
  }
487
- /**
488
- * 从队头连续取 inject 类型,遇到 command 停止
489
- * 取出的从队列移除,command 及之后保留
490
- */
491
381
  consumeInjectInputsBeforeNextCommand() {
492
382
  const result = [];
493
383
  while (this.pendingUserInputs.length > 0 &&
@@ -496,39 +386,36 @@ class StateManager {
496
386
  }
497
387
  return result;
498
388
  }
499
- /**
500
- * 消费全部剩余输入并清空队列
501
- */
502
389
  consumeAllPendingInputs() {
503
390
  return this.pendingUserInputs.splice(0);
504
391
  }
505
- /**
506
- * 清空待处理输入队列
507
- */
508
392
  clearPendingUserInputs() {
509
393
  this.pendingUserInputs = [];
510
394
  }
395
+ // ============================================================
396
+ // 清理
397
+ // ============================================================
511
398
  /**
512
- * 清空所有状态数据
399
+ * 清空本会话所有状态数据
513
400
  */
514
401
  clearAllState() {
515
- // 清空所有隔离状态的 Map
516
402
  this.statesMap.clear();
517
403
  this.messageHistoryMap.clear();
518
404
  this.readFileTimestampsMap.clear();
519
405
  this.todosMap.clear();
520
406
  this.todoTasksMap.clear();
521
- // 重置共享状态
407
+ this.fileLineEndingsMap.clear();
522
408
  this.currentAbortController = null;
409
+ this.systemPromptContent = null;
523
410
  this.globalEditPermissionGranted = false;
524
411
  this.planModeInfoSent = false;
525
412
  this.designModeInfoSent = false;
526
413
  this.foregroundAgents.clear();
527
414
  this.clearPendingUserInputs();
528
- (0, log_1.logInfo)(`所有状态数据已清空`);
415
+ (0, log_1.logInfo)(`[${this.sessionId}] 所有状态数据已清空`);
529
416
  }
530
417
  /**
531
- * 清理指定代理的所有隔离状态
418
+ * 清理指定子代理的所有隔离状态
532
419
  */
533
420
  clearAgentState(agentId) {
534
421
  if (agentId !== exports.MAIN_AGENT_ID) {
@@ -537,6 +424,7 @@ class StateManager {
537
424
  this.readFileTimestampsMap.delete(agentId);
538
425
  this.todosMap.delete(agentId);
539
426
  this.todoTasksMap.delete(agentId);
427
+ this.fileLineEndingsMap.delete(agentId);
540
428
  (0, log_1.logInfo)(`[${agentId}] 所有隔离状态已清理`);
541
429
  }
542
430
  }
@@ -550,9 +438,8 @@ class StateManager {
550
438
  const todoTasks = this.listTodoTasks(exports.MAIN_AGENT_ID);
551
439
  const readFileTimestamps = this.getReadFileTimestamps(exports.MAIN_AGENT_ID);
552
440
  const workingDir = (0, ConfManager_1.getConfManager)().getCoreConfig()?.workingDir;
553
- if (this.sessionId && messageHistory.length > 0) {
441
+ if (messageHistory.length > 0) {
554
442
  await (0, history_1.saveHistory)(this.sessionId, messageHistory, todos, workingDir, readFileTimestamps, todoTasks);
555
- // logInfo(`saveHistory: ${JSON.stringify(messageHistory, null, 2)}`)
556
443
  (0, log_1.logInfo)(`会话历史已保存: ${this.sessionId}`);
557
444
  }
558
445
  }
@@ -560,20 +447,17 @@ class StateManager {
560
447
  (0, log_1.logInfo)(`保存会话历史失败: ${error instanceof Error ? error.message : String(error)}`);
561
448
  }
562
449
  }
563
- /**
564
- * 获取全局编辑权限状态
565
- */
450
+ // ============================================================
451
+ // 全局编辑权限(会话级)
452
+ // ============================================================
566
453
  hasGlobalEditPermission() {
567
454
  return this.globalEditPermissionGranted;
568
455
  }
569
- /**
570
- * 授予全局编辑权限
571
- */
572
456
  grantGlobalEditPermission() {
573
457
  if (this.globalEditPermissionGranted)
574
458
  return;
575
459
  this.globalEditPermissionGranted = true;
576
- (0, log_1.logInfo)('全局编辑权限已授予');
460
+ (0, log_1.logInfo)(`[${this.sessionId}] 全局编辑权限已授予`);
577
461
  this.emitAutoEditUpdate(true);
578
462
  }
579
463
  /**
@@ -586,64 +470,53 @@ class StateManager {
586
470
  if (this.globalEditPermissionGranted === enable)
587
471
  return;
588
472
  this.globalEditPermissionGranted = enable;
589
- (0, log_1.logInfo)(`自动编辑已${enable ? '开启' : '关闭'}`);
473
+ (0, log_1.logInfo)(`[${this.sessionId}] 自动编辑已${enable ? '开启' : '关闭'}`);
590
474
  this.emitAutoEditUpdate(enable);
591
475
  }
592
- /**
593
- * 发送自动编辑状态更新事件
594
- */
595
476
  emitAutoEditUpdate(enable) {
596
477
  const data = { enable };
597
- (0, EventSystem_1.getEventBus)().emit('autoEdit:update', data);
478
+ (0, EventSystem_1.getEventBus)().emit('autoEdit:update', data, this.sessionId);
598
479
  }
599
- /**
600
- * 检查 Plan 模式信息是否已发送
601
- */
480
+ // ============================================================
481
+ // Plan / Design 模式信息发送标记(会话级)
482
+ // ============================================================
602
483
  isPlanModeInfoSent() {
603
484
  return this.planModeInfoSent;
604
485
  }
605
- /**
606
- * 标记 Plan 模式信息已发送
607
- */
608
486
  markPlanModeInfoSent() {
609
487
  this.planModeInfoSent = true;
610
- (0, log_1.logInfo)('Plan 模式信息已标记为已发送');
488
+ (0, log_1.logInfo)(`[${this.sessionId}] Plan 模式信息已标记为已发送`);
611
489
  }
612
- /**
613
- * 重置 Plan 模式信息发送状态
614
- */
615
490
  resetPlanModeInfoSent() {
616
491
  this.planModeInfoSent = false;
617
- (0, log_1.logInfo)('Plan 模式信息发送状态已重置');
492
+ (0, log_1.logInfo)(`[${this.sessionId}] Plan 模式信息发送状态已重置`);
618
493
  }
619
- /**
620
- * 检查 Design 模式信息是否已发送
621
- */
622
494
  isDesignModeInfoSent() {
623
495
  return this.designModeInfoSent;
624
496
  }
625
- /**
626
- * 标记 Design 模式信息已发送
627
- */
628
497
  markDesignModeInfoSent() {
629
498
  this.designModeInfoSent = true;
630
- (0, log_1.logInfo)('Design 模式信息已标记为已发送');
499
+ (0, log_1.logInfo)(`[${this.sessionId}] Design 模式信息已标记为已发送`);
631
500
  }
632
- /**
633
- * 重置 Design 模式信息发送状态
634
- */
635
501
  resetDesignModeInfoSent() {
636
502
  this.designModeInfoSent = false;
637
- (0, log_1.logInfo)('Design 模式信息发送状态已重置');
503
+ (0, log_1.logInfo)(`[${this.sessionId}] Design 模式信息发送状态已重置`);
504
+ }
505
+ // ============================================================
506
+ // 系统提示快照(会话级,整会话不变)
507
+ // ============================================================
508
+ getSystemPromptContent() {
509
+ return this.systemPromptContent;
510
+ }
511
+ setSystemPromptContent(content) {
512
+ this.systemPromptContent = content;
638
513
  }
639
514
  /**
640
515
  * 为指定 agentId 创建状态访问代理对象
641
- * 返回一个封装了该 agentId 所有状态操作的对象
642
516
  */
643
517
  forAgent(agentId) {
644
518
  const isSubagent = agentId !== exports.MAIN_AGENT_ID;
645
519
  return {
646
- // Todos 管理
647
520
  getTodos: () => this.getTodos(agentId),
648
521
  setTodos: (todos) => this.setTodos(todos, agentId),
649
522
  updateTodosIntelligently: (todos) => this.updateTodosIntelligently(todos, agentId),
@@ -652,7 +525,6 @@ class StateManager {
652
525
  this.clearAgentTodos(agentId);
653
526
  }
654
527
  },
655
- // 消息历史管理
656
528
  getMessageHistory: () => this.getMessageHistory(agentId),
657
529
  setMessageHistory: (messages, skipAutoSave) => this.setMessageHistory(messages, agentId, skipAutoSave),
658
530
  finalizeMessages: (messages) => {
@@ -660,25 +532,20 @@ class StateManager {
660
532
  this.updateState('idle', agentId);
661
533
  },
662
534
  flushHistory: () => this.saveSessionHistory(),
663
- // 文件读取时间戳管理
664
535
  getReadFileTimestamps: () => this.getReadFileTimestamps(agentId),
665
536
  getReadFileTimestamp: (filePath) => this.getReadFileTimestamp(filePath, agentId),
666
537
  setReadFileTimestamp: (filePath, timestamp) => this.setReadFileTimestamp(filePath, timestamp, agentId),
667
538
  setReadFileTimestamps: (timestamps) => this.setReadFileTimestamps(timestamps, agentId),
668
- // 文件换行符缓存
669
539
  getFileLineEnding: (filePath) => this.getFileLineEnding(filePath, agentId),
670
540
  setFileLineEnding: (filePath, ending) => this.setFileLineEnding(filePath, ending, agentId),
671
- // 状态管理
672
541
  getCurrentState: () => this.getCurrentState(agentId),
673
542
  updateState: (state) => this.updateState(state, agentId),
674
- // TodoTask CRUD
675
543
  createTodoTask: (task) => this.createTodoTask(agentId, task),
676
544
  getTodoTask: (taskId) => this.getTodoTask(agentId, taskId),
677
545
  listTodoTasks: () => this.listTodoTasks(agentId),
678
546
  updateTodoTask: (taskId, updates) => this.updateTodoTask(agentId, taskId, updates),
679
547
  deleteTodoTask: (taskId) => this.deleteTodoTask(agentId, taskId),
680
548
  blockTask: (fromId, toId) => this.blockTask(agentId, fromId, toId),
681
- // 清理
682
549
  clearAllState: () => {
683
550
  if (isSubagent) {
684
551
  this.clearAgentState(agentId);
@@ -687,6 +554,82 @@ class StateManager {
687
554
  };
688
555
  }
689
556
  }
557
+ exports.SessionRuntime = SessionRuntime;
558
+ /**
559
+ * 全局状态管理器(单例注册表)
560
+ * 按 sessionId 持有多个 SessionRuntime
561
+ */
562
+ class StateManager {
563
+ constructor() {
564
+ this.sessions = new Map();
565
+ /** UI 层当前打开的活跃会话(多会话共存时由 UI 指定,用于通知兜底投递) */
566
+ this.activeSessionId = null;
567
+ }
568
+ static getInstance() {
569
+ if (!StateManager.instance) {
570
+ StateManager.instance = new StateManager();
571
+ }
572
+ return StateManager.instance;
573
+ }
574
+ /**
575
+ * 获取(不存在则创建)指定会话的运行时
576
+ */
577
+ session(sessionId) {
578
+ let runtime = this.sessions.get(sessionId);
579
+ if (!runtime) {
580
+ runtime = new SessionRuntime(sessionId);
581
+ this.sessions.set(sessionId, runtime);
582
+ (0, log_1.logInfo)(`SessionRuntime 已创建: ${sessionId}`);
583
+ }
584
+ return runtime;
585
+ }
586
+ /**
587
+ * 从 AgentContext 直接取得代理状态访问器
588
+ */
589
+ forAgent(ctx) {
590
+ return this.session(ctx.sessionId).forAgent(ctx.agentId);
591
+ }
592
+ hasSession(sessionId) {
593
+ return this.sessions.has(sessionId);
594
+ }
595
+ /** 设置 UI 层当前活跃会话 */
596
+ setActiveSession(sessionId) {
597
+ this.activeSessionId = sessionId;
598
+ }
599
+ /** 获取 UI 层当前活跃会话(未设置或已关闭则为 null) */
600
+ getActiveSessionId() {
601
+ return this.activeSessionId;
602
+ }
603
+ /**
604
+ * 移除单个会话的全部状态(会话级 dispose)
605
+ */
606
+ removeSession(sessionId) {
607
+ const runtime = this.sessions.get(sessionId);
608
+ if (runtime) {
609
+ runtime.clearAllState();
610
+ this.sessions.delete(sessionId);
611
+ (0, log_1.logInfo)(`SessionRuntime 已移除: ${sessionId}`);
612
+ }
613
+ // 活跃会话被关闭:清空,等待 UI 指定新的活跃会话
614
+ if (this.activeSessionId === sessionId) {
615
+ this.activeSessionId = null;
616
+ }
617
+ }
618
+ /**
619
+ * 清空所有会话(进程级 dispose)
620
+ */
621
+ clearAll() {
622
+ for (const runtime of this.sessions.values()) {
623
+ runtime.clearAllState();
624
+ }
625
+ this.sessions.clear();
626
+ this.activeSessionId = null;
627
+ (0, log_1.logInfo)(`所有会话状态数据已清空`);
628
+ }
629
+ getSessionIds() {
630
+ return Array.from(this.sessions.keys());
631
+ }
632
+ }
690
633
  exports.StateManager = StateManager;
691
634
  StateManager.instance = null;
692
635
  /**