aws-runtime-bridge 1.0.3 → 1.1.0

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 (142) hide show
  1. package/dist/adapter/adapter.test.js +4 -4
  2. package/dist/adapter/types.d.ts.map +1 -1
  3. package/dist/adapter/types.js +0 -7
  4. package/dist/adapter/types.test.js +5 -53
  5. package/dist/middleware/auth.d.ts.map +1 -1
  6. package/dist/middleware/auth.js +4 -0
  7. package/dist/routes/instance.d.ts.map +1 -1
  8. package/dist/routes/instance.js +36 -0
  9. package/dist/routes/runtime-binding.d.ts.map +1 -1
  10. package/dist/routes/runtime-binding.js +45 -0
  11. package/dist/routes/sessions.js +1 -1
  12. package/dist/routes/terminal.d.ts.map +1 -1
  13. package/dist/routes/terminal.js +48 -14
  14. package/dist/routes/terminal.test.js +6 -2
  15. package/dist/services/agent-process-manager.js +4 -4
  16. package/dist/services/auto-register.d.ts +9 -0
  17. package/dist/services/auto-register.d.ts.map +1 -1
  18. package/dist/services/auto-register.js +190 -32
  19. package/dist/services/aws-client-agent-mcp.test.js +3 -0
  20. package/dist/services/mcp-launch-binding-queue.d.ts +36 -0
  21. package/dist/services/mcp-launch-binding-queue.d.ts.map +1 -0
  22. package/dist/services/mcp-launch-binding-queue.js +92 -0
  23. package/dist/services/mcp-launch-binding-queue.test.d.ts +2 -0
  24. package/dist/services/mcp-launch-binding-queue.test.d.ts.map +1 -0
  25. package/dist/services/mcp-launch-binding-queue.test.js +107 -0
  26. package/dist/services/orphan-monitor.js +1 -1
  27. package/dist/services/process-detector.d.ts +1 -1
  28. package/dist/services/process-detector.d.ts.map +1 -1
  29. package/dist/services/process-detector.js +2 -11
  30. package/dist/services/process-registry.d.ts +1 -0
  31. package/dist/services/process-registry.d.ts.map +1 -1
  32. package/dist/services/process-registry.js +129 -108
  33. package/dist/services/terminal-persistence.d.ts.map +1 -1
  34. package/dist/services/terminal-persistence.js +47 -37
  35. package/dist/services/terminal-persistence.test.js +47 -1
  36. package/dist/utils/file-utils.d.ts +3 -0
  37. package/dist/utils/file-utils.d.ts.map +1 -1
  38. package/dist/utils/file-utils.js +32 -0
  39. package/package/aws-client-agent-mcp/README.md +288 -288
  40. package/package.json +76 -76
  41. package/dist/routes/aws-mcp.d.ts +0 -10
  42. package/dist/routes/aws-mcp.d.ts.map +0 -1
  43. package/dist/routes/aws-mcp.js +0 -74
  44. package/dist/routes/aws-mcp.test.d.ts +0 -2
  45. package/dist/routes/aws-mcp.test.d.ts.map +0 -1
  46. package/dist/routes/aws-mcp.test.js +0 -42
  47. package/dist/routes/memory.d.ts +0 -13
  48. package/dist/routes/memory.d.ts.map +0 -1
  49. package/dist/routes/memory.js +0 -429
  50. package/dist/services/aws-mcp-http.d.ts +0 -11
  51. package/dist/services/aws-mcp-http.d.ts.map +0 -1
  52. package/dist/services/aws-mcp-http.js +0 -225
  53. package/dist/services/aws-mcp-http.test.d.ts +0 -2
  54. package/dist/services/aws-mcp-http.test.d.ts.map +0 -1
  55. package/dist/services/aws-mcp-http.test.js +0 -27
  56. package/dist/services/easytier-manager.d.ts +0 -106
  57. package/dist/services/easytier-manager.d.ts.map +0 -1
  58. package/dist/services/easytier-manager.js +0 -331
  59. package/dist/services/easytier-manager.test.d.ts +0 -5
  60. package/dist/services/easytier-manager.test.d.ts.map +0 -1
  61. package/dist/services/easytier-manager.test.js +0 -98
  62. package/dist/services/memory-service.d.ts +0 -195
  63. package/dist/services/memory-service.d.ts.map +0 -1
  64. package/dist/services/memory-service.js +0 -650
  65. package/dist/services/session-lookup.d.ts +0 -20
  66. package/dist/services/session-lookup.d.ts.map +0 -1
  67. package/dist/services/session-lookup.js +0 -43
  68. package/dist/services/user-api-key-service.d.ts +0 -28
  69. package/dist/services/user-api-key-service.d.ts.map +0 -1
  70. package/dist/services/user-api-key-service.js +0 -75
  71. package/node_modules/@cc-switch/sdk/dist/adapters/common.d.ts +0 -38
  72. package/node_modules/@cc-switch/sdk/dist/adapters/common.d.ts.map +0 -1
  73. package/node_modules/@cc-switch/sdk/dist/adapters/common.js +0 -47
  74. package/node_modules/@cc-switch/sdk/dist/adapters/index.d.ts +0 -5
  75. package/node_modules/@cc-switch/sdk/dist/adapters/index.d.ts.map +0 -1
  76. package/node_modules/@cc-switch/sdk/dist/adapters/index.js +0 -28
  77. package/node_modules/@cc-switch/sdk/dist/adapters/mcp-claude.d.ts +0 -10
  78. package/node_modules/@cc-switch/sdk/dist/adapters/mcp-claude.d.ts.map +0 -1
  79. package/node_modules/@cc-switch/sdk/dist/adapters/mcp-claude.js +0 -39
  80. package/node_modules/@cc-switch/sdk/dist/adapters/mcp-claudecode.d.ts +0 -10
  81. package/node_modules/@cc-switch/sdk/dist/adapters/mcp-claudecode.d.ts.map +0 -1
  82. package/node_modules/@cc-switch/sdk/dist/adapters/mcp-claudecode.js +0 -40
  83. package/node_modules/@cc-switch/sdk/dist/adapters/mcp-opencode.d.ts +0 -18
  84. package/node_modules/@cc-switch/sdk/dist/adapters/mcp-opencode.d.ts.map +0 -1
  85. package/node_modules/@cc-switch/sdk/dist/adapters/mcp-opencode.js +0 -63
  86. package/node_modules/@cc-switch/sdk/dist/adapters/mcp-opencode.test.d.ts +0 -2
  87. package/node_modules/@cc-switch/sdk/dist/adapters/mcp-opencode.test.d.ts.map +0 -1
  88. package/node_modules/@cc-switch/sdk/dist/adapters/mcp-opencode.test.js +0 -86
  89. package/node_modules/@cc-switch/sdk/dist/adapters/mcp-placeholder.d.ts +0 -9
  90. package/node_modules/@cc-switch/sdk/dist/adapters/mcp-placeholder.d.ts.map +0 -1
  91. package/node_modules/@cc-switch/sdk/dist/adapters/mcp-placeholder.js +0 -14
  92. package/node_modules/@cc-switch/sdk/dist/adapters/skill-claude.d.ts +0 -10
  93. package/node_modules/@cc-switch/sdk/dist/adapters/skill-claude.d.ts.map +0 -1
  94. package/node_modules/@cc-switch/sdk/dist/adapters/skill-claude.js +0 -51
  95. package/node_modules/@cc-switch/sdk/dist/adapters/skill-claudecode.d.ts +0 -10
  96. package/node_modules/@cc-switch/sdk/dist/adapters/skill-claudecode.d.ts.map +0 -1
  97. package/node_modules/@cc-switch/sdk/dist/adapters/skill-claudecode.js +0 -51
  98. package/node_modules/@cc-switch/sdk/dist/adapters/skill-opencode.d.ts +0 -10
  99. package/node_modules/@cc-switch/sdk/dist/adapters/skill-opencode.d.ts.map +0 -1
  100. package/node_modules/@cc-switch/sdk/dist/adapters/skill-opencode.js +0 -51
  101. package/node_modules/@cc-switch/sdk/dist/adapters/skill-placeholder.d.ts +0 -9
  102. package/node_modules/@cc-switch/sdk/dist/adapters/skill-placeholder.d.ts.map +0 -1
  103. package/node_modules/@cc-switch/sdk/dist/adapters/skill-placeholder.js +0 -14
  104. package/node_modules/@cc-switch/sdk/dist/services/instance-service.d.ts +0 -78
  105. package/node_modules/@cc-switch/sdk/dist/services/instance-service.d.ts.map +0 -1
  106. package/node_modules/@cc-switch/sdk/dist/services/instance-service.js +0 -180
  107. package/package/cc-switch-sdk/dist/adapters/common.d.ts +0 -38
  108. package/package/cc-switch-sdk/dist/adapters/common.d.ts.map +0 -1
  109. package/package/cc-switch-sdk/dist/adapters/common.js +0 -47
  110. package/package/cc-switch-sdk/dist/adapters/index.d.ts +0 -5
  111. package/package/cc-switch-sdk/dist/adapters/index.d.ts.map +0 -1
  112. package/package/cc-switch-sdk/dist/adapters/index.js +0 -28
  113. package/package/cc-switch-sdk/dist/adapters/mcp-claude.d.ts +0 -10
  114. package/package/cc-switch-sdk/dist/adapters/mcp-claude.d.ts.map +0 -1
  115. package/package/cc-switch-sdk/dist/adapters/mcp-claude.js +0 -39
  116. package/package/cc-switch-sdk/dist/adapters/mcp-claudecode.d.ts +0 -10
  117. package/package/cc-switch-sdk/dist/adapters/mcp-claudecode.d.ts.map +0 -1
  118. package/package/cc-switch-sdk/dist/adapters/mcp-claudecode.js +0 -40
  119. package/package/cc-switch-sdk/dist/adapters/mcp-opencode.d.ts +0 -18
  120. package/package/cc-switch-sdk/dist/adapters/mcp-opencode.d.ts.map +0 -1
  121. package/package/cc-switch-sdk/dist/adapters/mcp-opencode.js +0 -63
  122. package/package/cc-switch-sdk/dist/adapters/mcp-opencode.test.d.ts +0 -2
  123. package/package/cc-switch-sdk/dist/adapters/mcp-opencode.test.d.ts.map +0 -1
  124. package/package/cc-switch-sdk/dist/adapters/mcp-opencode.test.js +0 -86
  125. package/package/cc-switch-sdk/dist/adapters/mcp-placeholder.d.ts +0 -9
  126. package/package/cc-switch-sdk/dist/adapters/mcp-placeholder.d.ts.map +0 -1
  127. package/package/cc-switch-sdk/dist/adapters/mcp-placeholder.js +0 -14
  128. package/package/cc-switch-sdk/dist/adapters/skill-claude.d.ts +0 -10
  129. package/package/cc-switch-sdk/dist/adapters/skill-claude.d.ts.map +0 -1
  130. package/package/cc-switch-sdk/dist/adapters/skill-claude.js +0 -51
  131. package/package/cc-switch-sdk/dist/adapters/skill-claudecode.d.ts +0 -10
  132. package/package/cc-switch-sdk/dist/adapters/skill-claudecode.d.ts.map +0 -1
  133. package/package/cc-switch-sdk/dist/adapters/skill-claudecode.js +0 -51
  134. package/package/cc-switch-sdk/dist/adapters/skill-opencode.d.ts +0 -10
  135. package/package/cc-switch-sdk/dist/adapters/skill-opencode.d.ts.map +0 -1
  136. package/package/cc-switch-sdk/dist/adapters/skill-opencode.js +0 -51
  137. package/package/cc-switch-sdk/dist/adapters/skill-placeholder.d.ts +0 -9
  138. package/package/cc-switch-sdk/dist/adapters/skill-placeholder.d.ts.map +0 -1
  139. package/package/cc-switch-sdk/dist/adapters/skill-placeholder.js +0 -14
  140. package/package/cc-switch-sdk/dist/services/instance-service.d.ts +0 -78
  141. package/package/cc-switch-sdk/dist/services/instance-service.d.ts.map +0 -1
  142. package/package/cc-switch-sdk/dist/services/instance-service.js +0 -180
@@ -1,650 +0,0 @@
1
- /**
2
- * 记忆服务
3
- *
4
- * 支持三文件存储结构:
5
- * - todo-memory.json: task_list 类型记忆
6
- * - hot-memory.json: recently_memory 类型记忆
7
- * - cold-memory.json: memory 类型记忆(长期记忆)
8
- *
9
- * 文件存储在项目根目录下的 vibe-coding/memory/ 目录
10
- *
11
- * 权限控制:
12
- * - 私有记忆(isPublic=false):仅创建者可读写
13
- * - 公开记忆(isPublic=true):小组内所有成员可读取,仅创建者可编辑删除
14
- */
15
- import { promises as fs } from "node:fs";
16
- import path from "node:path";
17
- import { createLogger } from "../utils/logger.js";
18
- const log = createLogger("memory-service");
19
- const MEMORY_TYPE_TO_FILE = {
20
- task_list: "todo-memory.json",
21
- recently_memory: "hot-memory.json",
22
- memory: "cold-memory.json",
23
- };
24
- const ALL_MEMORY_TYPES = [
25
- "task_list",
26
- "recently_memory",
27
- "memory",
28
- ];
29
- const LISTABLE_MEMORY_TYPES = ["task_list", "recently_memory"];
30
- const URI_PATTERN = /^([a-zA-Z_][a-zA-Z0-9_]*):\/\/(.*)$/;
31
- /**
32
- * 获取记忆文件路径(异步版本)
33
- *
34
- * 记忆文件存储在 vibe-coding/memory/ 目录下(与 my.yml 同级)
35
- */
36
- export async function getMemoryFilePath(workspacePath, memoryType) {
37
- const vibeCodingDir = await findVibeCodingDir(workspacePath);
38
- const memoryDir = path.join(vibeCodingDir, "memory");
39
- const fileName = MEMORY_TYPE_TO_FILE[memoryType];
40
- return path.join(memoryDir, fileName);
41
- }
42
- /**
43
- * 获取记忆目录路径(异步版本)
44
- */
45
- export async function getMemoryDirPath(workspacePath) {
46
- const vibeCodingDir = await findVibeCodingDir(workspacePath);
47
- return path.join(vibeCodingDir, "memory");
48
- }
49
- /**
50
- * 向上查找 vibe-coding 目录(异步版本)
51
- */
52
- async function findVibeCodingDir(startPath) {
53
- let currentPath = path.resolve(startPath);
54
- // 向上查找,最多查找 10 层
55
- for (let i = 0; i < 10; i++) {
56
- const vibeCodingPath = path.join(currentPath, "vibe-coding");
57
- // 检查是否存在 vibe-coding 目录或 my.yml 文件
58
- const myYmlPath = path.join(vibeCodingPath, "my.yml");
59
- try {
60
- // 如果存在 my.yml,则返回 vibe-coding 目录
61
- const stat = await fs.stat(myYmlPath);
62
- if (stat.isFile()) {
63
- return vibeCodingPath;
64
- }
65
- }
66
- catch {
67
- // 文件不存在,继续向上查找
68
- }
69
- // 检查 vibe-coding 目录是否存在
70
- try {
71
- const stat = await fs.stat(vibeCodingPath);
72
- if (stat.isDirectory()) {
73
- return vibeCodingPath;
74
- }
75
- }
76
- catch {
77
- // 目录不存在,继续向上查找
78
- }
79
- // 向上一级
80
- const parentPath = path.dirname(currentPath);
81
- if (parentPath === currentPath) {
82
- // 已经到达根目录,停止查找
83
- break;
84
- }
85
- currentPath = parentPath;
86
- }
87
- // 未找到 vibe-coding 目录,在 workspacePath 同级创建
88
- log.warn(`[MemoryService] 未找到 vibe-coding 目录,将在 ${startPath} 同级创建`);
89
- return path.join(path.dirname(startPath), "vibe-coding");
90
- }
91
- /**
92
- * 检查记忆访问权限
93
- *
94
- * @param record 记忆记录
95
- * @param requestorId 请求者 Agent ID
96
- * @returns 是否有权限访问
97
- */
98
- function canAccess(record, requestorId) {
99
- // 创建者始终可以访问自己的记忆
100
- if (record.creatorId === requestorId) {
101
- return true;
102
- }
103
- // 公开记忆可以被小组内其他成员访问
104
- if (record.isPublic) {
105
- return true;
106
- }
107
- // 私有记忆,非创建者无法访问
108
- return false;
109
- }
110
- /**
111
- * 检查记忆编辑/删除权限
112
- *
113
- * @param record 记忆记录
114
- * @param requestorId 请求者 Agent ID
115
- * @returns 是否有权限编辑/删除
116
- */
117
- function canModify(record, requestorId) {
118
- // 只有创建者可以编辑/删除自己的记忆
119
- return record.creatorId === requestorId;
120
- }
121
- /**
122
- * 为公开记忆添加来源信息标注
123
- *
124
- * 当读取他人公开记忆时,添加来源信息以便识别
125
- */
126
- function annotatePublicMemory(record, requestorId) {
127
- const isOwn = record.creatorId === requestorId;
128
- if (isOwn) {
129
- return { ...record, isOwn: true };
130
- }
131
- // 格式化时间为更易读的格式(YYYY-MM-DD HH:mm)
132
- const createdDate = new Date(record.createdAt);
133
- const formattedTime = createdDate.toLocaleString("zh-CN", {
134
- year: "numeric",
135
- month: "2-digit",
136
- day: "2-digit",
137
- hour: "2-digit",
138
- minute: "2-digit",
139
- });
140
- return {
141
- ...record,
142
- isOwn: false,
143
- source: `由 ${record.creatorName} 创建于 ${formattedTime}`,
144
- };
145
- }
146
- export class MemoryService {
147
- /**
148
- * 确保记忆目录存在(已使用异步 API)
149
- */
150
- async ensureMemoryDir(workspacePath) {
151
- const memoryDir = await getMemoryDirPath(workspacePath);
152
- await fs.mkdir(memoryDir, { recursive: true });
153
- return memoryDir;
154
- }
155
- /**
156
- * 生成当前时间的 ISO 字符串
157
- */
158
- nowIso() {
159
- return new Date().toISOString();
160
- }
161
- /**
162
- * 规范化 URI
163
- */
164
- normalizeUri(input) {
165
- const value = String(input || "").trim();
166
- const matched = URI_PATTERN.exec(value);
167
- if (!matched) {
168
- throw new Error(`Invalid memory uri: ${input}`);
169
- }
170
- const domainPart = matched[1];
171
- const pathPart = matched[2];
172
- if (!domainPart || !pathPart) {
173
- throw new Error(`Invalid memory uri: ${input}`);
174
- }
175
- const domain = domainPart.toLowerCase();
176
- const normalizedPath = pathPart.replace(/^\/+|\/+$/g, "");
177
- if (!normalizedPath) {
178
- throw new Error(`Invalid memory uri path: ${input}`);
179
- }
180
- return {
181
- uri: `${domain}://${normalizedPath}`,
182
- domain,
183
- path: normalizedPath,
184
- };
185
- }
186
- /**
187
- * 规范化记忆类型
188
- */
189
- normalizeMemoryType(input, allowedTypes = ALL_MEMORY_TYPES) {
190
- const value = String(input || "").trim();
191
- if (!allowedTypes.includes(value)) {
192
- throw new Error(`Invalid memory_type: ${input}`);
193
- }
194
- return value;
195
- }
196
- /**
197
- * 确保类型匹配
198
- */
199
- ensureTypeMatch(record, expectedType) {
200
- if (expectedType && record.memory_type !== expectedType) {
201
- throw new Error(`Memory type mismatch: expected ${expectedType}, actual ${record.memory_type}`);
202
- }
203
- }
204
- /**
205
- * 生成记忆 ID
206
- */
207
- generateId(uri) {
208
- const cleaned = uri.replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "");
209
- return `${cleaned}_${Date.now().toString(36)}`;
210
- }
211
- /**
212
- * 加载指定类型的记忆文件(已使用异步 API)
213
- */
214
- async loadMemoryFile(workspacePath, memoryType) {
215
- const filePath = await getMemoryFilePath(workspacePath, memoryType);
216
- try {
217
- const raw = await fs.readFile(filePath, "utf-8");
218
- const parsed = JSON.parse(raw);
219
- // 确保 records 数组存在
220
- if (!parsed.records || !Array.isArray(parsed.records)) {
221
- parsed.records = [];
222
- }
223
- // 规范化每条记录,补充缺失的创建者信息(兼容旧数据)
224
- for (const record of parsed.records) {
225
- record.memory_type = this.normalizeMemoryType(record.memory_type || memoryType);
226
- // 兼容旧数据:如果没有创建者信息,使用默认值
227
- if (!record.creatorId) {
228
- record.creatorId = "unknown";
229
- record.creatorName = "未知创建者";
230
- }
231
- if (record.isPublic === undefined) {
232
- record.isPublic = false;
233
- }
234
- }
235
- return parsed;
236
- }
237
- catch (err) {
238
- const error = err;
239
- if (error?.code === "ENOENT") {
240
- // 文件不存在,返回空数据
241
- return {
242
- records: [],
243
- updatedAt: this.nowIso(),
244
- };
245
- }
246
- throw err;
247
- }
248
- }
249
- /**
250
- * 保存记忆文件(已使用异步 API)
251
- */
252
- async saveMemoryFile(workspacePath, memoryType, data) {
253
- await this.ensureMemoryDir(workspacePath);
254
- const filePath = await getMemoryFilePath(workspacePath, memoryType);
255
- data.updatedAt = this.nowIso();
256
- await fs.writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
257
- log.info(`[MemoryService] 保存记忆文件: ${filePath}, 记录数: ${data.records.length}`);
258
- }
259
- /**
260
- * 创建记忆
261
- */
262
- async createMemory(workspacePath, input) {
263
- const normalizedType = this.normalizeMemoryType(input.memory_type);
264
- const normalized = this.normalizeUri(input.uri);
265
- const data = await this.loadMemoryFile(workspacePath, normalizedType);
266
- // 检查是否已存在
267
- const existing = data.records.find((r) => r.uri === normalized.uri);
268
- if (existing) {
269
- throw new Error(`Memory already exists: ${normalized.uri}`);
270
- }
271
- // 验证创建者信息
272
- if (!input.creatorId) {
273
- throw new Error("creatorId is required");
274
- }
275
- if (!input.creatorName) {
276
- throw new Error("creatorName is required");
277
- }
278
- const now = this.nowIso();
279
- const record = {
280
- id: this.generateId(normalized.uri),
281
- uri: normalized.uri,
282
- domain: normalized.domain,
283
- path: normalized.path,
284
- content: String(input.content || ""),
285
- memory_type: normalizedType,
286
- createdAt: now,
287
- updatedAt: now,
288
- version: 1,
289
- creatorId: input.creatorId,
290
- creatorName: input.creatorName,
291
- isPublic: input.isPublic ?? false, // 默认私有
292
- };
293
- data.records.push(record);
294
- await this.saveMemoryFile(workspacePath, normalizedType, data);
295
- const visibility = record.isPublic ? "公开" : "私有";
296
- log.info(`[MemoryService] 创建记忆: ${normalized.uri}, 类型: ${normalizedType}, 创建者: ${input.creatorName}, 可见性: ${visibility}`);
297
- return record;
298
- }
299
- /**
300
- * 读取记忆(带权限检查)
301
- *
302
- * 权限规则:
303
- * - 自己的记忆:可读取
304
- * - 公开的记忆:可读取,但会标注来源信息
305
- * - 他人私有记忆:无法读取
306
- */
307
- async readMemory(workspacePath, input) {
308
- const normalized = this.normalizeUri(input.uri);
309
- const expectedType = typeof input.memory_type === "string"
310
- ? this.normalizeMemoryType(input.memory_type)
311
- : undefined;
312
- // 如果指定了类型,只从对应文件读取
313
- if (expectedType) {
314
- const data = await this.loadMemoryFile(workspacePath, expectedType);
315
- const record = data.records.find((r) => r.uri === normalized.uri) ?? null;
316
- if (record) {
317
- this.ensureTypeMatch(record, expectedType);
318
- // 权限检查
319
- if (!canAccess(record, input.requestorId)) {
320
- log.warn(`[MemoryService] 无权限读取记忆: ${normalized.uri}, 请求者: ${input.requestorId}, 创建者: ${record.creatorId}`);
321
- return null;
322
- }
323
- return annotatePublicMemory(record, input.requestorId);
324
- }
325
- return null;
326
- }
327
- // 未指定类型,依次从三个文件查找
328
- for (const memoryType of ALL_MEMORY_TYPES) {
329
- const data = await this.loadMemoryFile(workspacePath, memoryType);
330
- const record = data.records.find((r) => r.uri === normalized.uri);
331
- if (record) {
332
- // 权限检查
333
- if (!canAccess(record, input.requestorId)) {
334
- log.warn(`[MemoryService] 无权限读取记忆: ${normalized.uri}, 请求者: ${input.requestorId}, 创建者: ${record.creatorId}`);
335
- return null;
336
- }
337
- return annotatePublicMemory(record, input.requestorId);
338
- }
339
- }
340
- return null;
341
- }
342
- /**
343
- * 更新记忆(带权限检查)
344
- *
345
- * 权限规则:只有创建者可以更新自己的记忆
346
- * 更新时会记录最后编辑者信息
347
- */
348
- async updateMemory(workspacePath, input) {
349
- const normalized = this.normalizeUri(input.uri);
350
- // 先找到记忆所在的文件
351
- let existingRecord = null;
352
- let existingType = null;
353
- for (const memoryType of ALL_MEMORY_TYPES) {
354
- const data = await this.loadMemoryFile(workspacePath, memoryType);
355
- const record = data.records.find((r) => r.uri === normalized.uri);
356
- if (record) {
357
- existingRecord = record;
358
- existingType = memoryType;
359
- break;
360
- }
361
- }
362
- if (!existingRecord || !existingType) {
363
- throw new Error(`Memory not found: ${normalized.uri}`);
364
- }
365
- // 权限检查:只有创建者可以编辑
366
- if (!canModify(existingRecord, input.editorId)) {
367
- throw new Error(`无权限编辑此记忆: 只有创建者 ${existingRecord.creatorName} 可以编辑`);
368
- }
369
- // 校验类型
370
- const expectedType = typeof input.memory_type === "string"
371
- ? this.normalizeMemoryType(input.memory_type)
372
- : undefined;
373
- this.ensureTypeMatch(existingRecord, expectedType);
374
- // 更新内容
375
- let nextContent = existingRecord.content;
376
- if (typeof input.old_string === "string" &&
377
- typeof input.new_string === "string") {
378
- const oldString = input.old_string;
379
- if (!oldString) {
380
- throw new Error("old_string cannot be empty when replacing");
381
- }
382
- const occurrenceCount = nextContent.split(oldString).length - 1;
383
- if (occurrenceCount === 0) {
384
- throw new Error("old_string not found in memory content");
385
- }
386
- if (occurrenceCount > 1) {
387
- throw new Error("old_string appears multiple times; replace is ambiguous");
388
- }
389
- nextContent = nextContent.replace(oldString, input.new_string);
390
- }
391
- if (typeof input.append === "string" && input.append.length > 0) {
392
- nextContent = `${nextContent}${input.append}`;
393
- }
394
- // 加载文件并更新
395
- const data = await this.loadMemoryFile(workspacePath, existingType);
396
- const existing = data.records.find((r) => r.uri === normalized.uri);
397
- if (!existing) {
398
- throw new Error(`Memory not found: ${normalized.uri}`);
399
- }
400
- const updated = {
401
- ...existing,
402
- content: nextContent,
403
- updatedAt: this.nowIso(),
404
- version: existing.version + 1,
405
- // 记录最后编辑者(如果编辑者不是创建者)
406
- lastEditorId: input.editorId,
407
- lastEditorName: input.editorName,
408
- };
409
- // 替换数组中的记录
410
- const index = data.records.findIndex((r) => r.uri === normalized.uri);
411
- data.records[index] = updated;
412
- await this.saveMemoryFile(workspacePath, existingType, data);
413
- log.info(`[MemoryService] 更新记忆: ${normalized.uri}, 版本: ${updated.version}, 编辑者: ${input.editorName}`);
414
- return updated;
415
- }
416
- /**
417
- * 删除记忆(带权限检查)
418
- *
419
- * 权限规则:只有创建者可以删除自己的记忆
420
- */
421
- async deleteMemory(workspacePath, input) {
422
- const normalized = this.normalizeUri(input.uri);
423
- const expectedType = typeof input.memory_type === "string"
424
- ? this.normalizeMemoryType(input.memory_type)
425
- : undefined;
426
- // 找到记忆
427
- for (const memoryType of ALL_MEMORY_TYPES) {
428
- if (expectedType && memoryType !== expectedType) {
429
- continue;
430
- }
431
- const data = await this.loadMemoryFile(workspacePath, memoryType);
432
- const index = data.records.findIndex((r) => r.uri === normalized.uri);
433
- if (index !== -1) {
434
- const existing = data.records[index];
435
- this.ensureTypeMatch(existing, expectedType);
436
- // 权限检查:只有创建者可以删除
437
- if (!canModify(existing, input.requestorId)) {
438
- log.warn(`[MemoryService] 无权限删除记忆: ${normalized.uri}, 请求者: ${input.requestorId}, 创建者: ${existing.creatorId}`);
439
- return {
440
- deleted: false,
441
- reason: `无权限删除此记忆: 只有创建者 ${existing.creatorName} 可以删除`,
442
- };
443
- }
444
- data.records.splice(index, 1);
445
- await this.saveMemoryFile(workspacePath, memoryType, data);
446
- log.info(`[MemoryService] 删除记忆: ${normalized.uri}, 类型: ${memoryType}`);
447
- return { deleted: true };
448
- }
449
- }
450
- return { deleted: false, reason: "Memory not found" };
451
- }
452
- /**
453
- * 搜索记忆(带权限过滤)
454
- *
455
- * 权限规则:只返回自己的记忆 + 公开的记忆
456
- * 公开的记忆会标注来源信息
457
- */
458
- async searchMemory(workspacePath, input) {
459
- const query = String(input.query || "")
460
- .trim()
461
- .toLowerCase();
462
- const memoryTypeFilter = input.memory_type
463
- ? this.normalizeMemoryType(input.memory_type)
464
- : undefined;
465
- const limit = typeof input.limit === "number" && input.limit > 0 ? input.limit : 10;
466
- if (!query) {
467
- return { query, results: [], totalFound: 0 };
468
- }
469
- const seenById = new Set();
470
- const ranked = [];
471
- // 从所有文件(或指定类型文件)搜索
472
- const typesToSearch = memoryTypeFilter
473
- ? [memoryTypeFilter]
474
- : ALL_MEMORY_TYPES;
475
- for (const memoryType of typesToSearch) {
476
- const data = await this.loadMemoryFile(workspacePath, memoryType);
477
- for (const record of data.records) {
478
- if (seenById.has(record.id)) {
479
- continue;
480
- }
481
- // 权限过滤:只搜索自己可访问的记忆
482
- if (!canAccess(record, input.requestorId)) {
483
- continue;
484
- }
485
- const haystack = `${record.uri}\n${record.content}`.toLowerCase();
486
- if (!haystack.includes(query)) {
487
- continue;
488
- }
489
- // 计算得分:URI 匹配权重更高
490
- const inUri = record.uri.toLowerCase().includes(query) ? 2 : 0;
491
- const inContent = record.content.toLowerCase().includes(query) ? 1 : 0;
492
- const score = inUri + inContent;
493
- const isOwn = record.creatorId === input.requestorId;
494
- seenById.add(record.id);
495
- ranked.push({ score, record, isOwn });
496
- }
497
- }
498
- // 按得分和更新时间排序,自己的记忆优先
499
- ranked.sort((a, b) => {
500
- // 自己的记忆优先显示
501
- if (a.isOwn !== b.isOwn) {
502
- return a.isOwn ? -1 : 1;
503
- }
504
- // 然后按得分排序
505
- if (b.score !== a.score) {
506
- return b.score - a.score;
507
- }
508
- // 最后按更新时间排序
509
- return b.record.updatedAt.localeCompare(a.record.updatedAt);
510
- });
511
- const results = ranked
512
- .slice(0, limit)
513
- .map((item) => annotatePublicMemory(item.record, input.requestorId));
514
- log.info(`[MemoryService] 搜索记忆: query="${query}", 找到 ${ranked.length} 条, 返回 ${results.length} 条`);
515
- return {
516
- query,
517
- results,
518
- totalFound: ranked.length,
519
- };
520
- }
521
- /**
522
- * 按类型列出记忆(带权限过滤)
523
- *
524
- * 权限规则:只列出自己的记忆 + 公开的记忆
525
- */
526
- async listByType(workspacePath, input) {
527
- const listType = this.normalizeMemoryType(input.memory_type, LISTABLE_MEMORY_TYPES);
528
- const data = await this.loadMemoryFile(workspacePath, listType);
529
- // 权限过滤
530
- const filteredRecords = data.records.filter((record) => canAccess(record, input.requestorId));
531
- // 按更新时间排序,自己的记忆优先
532
- const records = [...filteredRecords];
533
- records.sort((a, b) => {
534
- // 自己的记忆优先显示
535
- const aIsOwn = a.creatorId === input.requestorId;
536
- const bIsOwn = b.creatorId === input.requestorId;
537
- if (aIsOwn !== bIsOwn) {
538
- return aIsOwn ? -1 : 1;
539
- }
540
- // 然后按更新时间排序
541
- return b.updatedAt.localeCompare(a.updatedAt);
542
- });
543
- // 标注来源信息
544
- const annotatedRecords = records.map((record) => annotatePublicMemory(record, input.requestorId));
545
- log.info(`[MemoryService] 列出记忆: 类型=${listType}, 总数=${data.records.length}, 可访问=${annotatedRecords.length}`);
546
- return annotatedRecords;
547
- }
548
- /**
549
- * 删除任务列表记忆(仅限 task_list 类型,带权限检查)
550
- */
551
- async removeTaskListMemory(workspacePath, uri, requestorId) {
552
- const record = await this.readMemory(workspacePath, {
553
- uri,
554
- requestorId,
555
- });
556
- if (!record) {
557
- return { deleted: false, reason: "Memory not found or no access" };
558
- }
559
- if (record.memory_type !== "task_list") {
560
- throw new Error("task_list_remove only supports task_list type");
561
- }
562
- return this.deleteMemory(workspacePath, {
563
- uri: record.uri,
564
- memory_type: "task_list",
565
- requestorId,
566
- });
567
- }
568
- /**
569
- * 归档短期记忆(将 recently_memory 转为 memory,带权限检查)
570
- *
571
- * 权限规则:只有创建者可以归档自己的记忆
572
- */
573
- async archiveRecentlyMemory(workspacePath, uri, requestorId) {
574
- const recordResult = await this.readMemory(workspacePath, {
575
- uri,
576
- requestorId,
577
- });
578
- if (!recordResult) {
579
- throw new Error(`Memory not found or no access: ${uri}`);
580
- }
581
- const record = recordResult;
582
- if (record.memory_type !== "recently_memory") {
583
- throw new Error("archive only supports recently_memory type");
584
- }
585
- // 权限检查:只有创建者可以归档
586
- if (!canModify(record, requestorId)) {
587
- throw new Error(`无权限归档此记忆: 只有创建者 ${record.creatorName} 可以归档`);
588
- }
589
- // 从 hot-memory.json 中删除
590
- const hotData = await this.loadMemoryFile(workspacePath, "recently_memory");
591
- const hotIndex = hotData.records.findIndex((r) => r.uri === uri);
592
- if (hotIndex === -1) {
593
- throw new Error(`Memory not found in hot-memory.json: ${uri}`);
594
- }
595
- hotData.records.splice(hotIndex, 1);
596
- await this.saveMemoryFile(workspacePath, "recently_memory", hotData);
597
- // 添加到 cold-memory.json
598
- const coldData = await this.loadMemoryFile(workspacePath, "memory");
599
- const archived = {
600
- ...record,
601
- memory_type: "memory",
602
- updatedAt: this.nowIso(),
603
- version: record.version + 1,
604
- };
605
- coldData.records.push(archived);
606
- await this.saveMemoryFile(workspacePath, "memory", coldData);
607
- log.info(`[MemoryService] 归档记忆: ${uri}, 从 recently_memory 到 memory`);
608
- return archived;
609
- }
610
- /**
611
- * 获取所有记忆统计信息(已使用异步 API)
612
- */
613
- async getStats(workspacePath, requestorId) {
614
- const memoryDir = await getMemoryDirPath(workspacePath);
615
- const stats = {
616
- task_list: 0,
617
- recently_memory: 0,
618
- memory: 0,
619
- total: 0,
620
- accessible: 0,
621
- own: 0,
622
- public: 0,
623
- memoryDir,
624
- };
625
- for (const memoryType of ALL_MEMORY_TYPES) {
626
- const data = await this.loadMemoryFile(workspacePath, memoryType);
627
- stats[memoryType] = data.records.length;
628
- stats.total += data.records.length;
629
- for (const record of data.records) {
630
- if (record.isPublic) {
631
- stats.public++;
632
- }
633
- if (requestorId && record.creatorId === requestorId) {
634
- stats.own++;
635
- }
636
- if (requestorId && canAccess(record, requestorId)) {
637
- stats.accessible++;
638
- }
639
- }
640
- }
641
- // 如果没有提供 requestorId,accessible 等于 total
642
- if (!requestorId) {
643
- stats.accessible = stats.total;
644
- stats.own = 0;
645
- }
646
- return stats;
647
- }
648
- }
649
- // 导出单例
650
- export const memoryService = new MemoryService();
@@ -1,20 +0,0 @@
1
- import type { PersistedSession } from '../types.js';
2
- type ActiveSessionSnapshot = {
3
- sessionId: string;
4
- workspacePath: string;
5
- mode: 'pty' | 'sdk';
6
- };
7
- type PersistedSessionSnapshot = Pick<PersistedSession, 'sessionId' | 'workspacePath' | 'command' | 'status' | 'startedAt'> & {
8
- mode?: 'pty';
9
- };
10
- /**
11
- * 构建按 Agent 查询会话状态的统一响应。
12
- *
13
- * 主流程:
14
- * 1. 活跃会话返回 hasActiveSession=true 且 isActive=true
15
- * 2. 持久化可恢复会话返回 hasActiveSession=true 且 isActive=false
16
- * 3. 无会话返回 false/false
17
- */
18
- export declare function buildSessionLookupResponse(agentId: string, activeSession?: ActiveSessionSnapshot | null, persistedSession?: PersistedSessionSnapshot | null): Record<string, unknown>;
19
- export {};
20
- //# sourceMappingURL=session-lookup.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"session-lookup.d.ts","sourceRoot":"","sources":["../../src/services/session-lookup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,KAAK,qBAAqB,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC;CACrB,CAAC;AAEF,KAAK,wBAAwB,GAAG,IAAI,CAAC,gBAAgB,EAAE,WAAW,GAAG,eAAe,GAAG,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC,GAAG;IAC3H,IAAI,CAAC,EAAE,KAAK,CAAC;CACd,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,MAAM,EACf,aAAa,CAAC,EAAE,qBAAqB,GAAG,IAAI,EAC5C,gBAAgB,CAAC,EAAE,wBAAwB,GAAG,IAAI,GACjD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoCzB"}