aws-runtime-bridge 1.9.130 → 1.9.134
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter/AcodeSdkAdapter.d.ts +15 -0
- package/dist/adapter/AcodeSdkAdapter.js +5 -5
- package/dist/adapter/types.d.ts +9 -0
- package/dist/browser/browser-frame-encode.d.ts +16 -0
- package/dist/browser/browser-frame-encode.js +2 -0
- package/dist/browser/browser-pool.js +1 -1
- package/dist/browser/built-in-browser-tools.js +1 -1
- package/dist/browser/screencast-differ.d.ts +35 -0
- package/dist/browser/screencast-differ.js +2 -0
- package/dist/browser/screencast-manager.d.ts +32 -0
- package/dist/browser/screencast-manager.js +1 -1
- package/dist/browser/types.d.ts +48 -1
- package/dist/browser/types.js +1 -1
- package/dist/browser/ws-server.d.ts +1 -1
- package/dist/browser/ws-server.js +1 -1
- package/dist/routes/background-tasks.js +7 -1
- package/dist/routes/instance-tool-status.d.ts +4 -0
- package/dist/routes/instance-tool-status.js +2 -0
- package/dist/routes/instance.d.ts +0 -2
- package/dist/routes/instance.js +1 -1
- package/dist/routes/system-metrics.js +1 -1
- package/dist/routes/terminal.js +19 -19
- package/dist/services/acode-bg-manager.d.ts +36 -0
- package/dist/services/acode-bg-manager.js +2 -0
- package/dist/services/browser-session-manager.js +1 -1
- package/dist/services/instance-features.d.ts +5 -0
- package/dist/services/instance-features.js +1 -1
- package/dist/services/process-detail.d.ts +77 -0
- package/dist/services/process-detail.js +32 -0
- package/dist/services/process-top.d.ts +53 -0
- package/dist/services/process-top.js +50 -0
- package/dist/services/session-output.d.ts +10 -0
- package/dist/services/session-output.js +3 -3
- package/package/acode/dist/await-complete-tool.js +4 -4
- package/package/acode/dist/background-command-manager.d.ts +39 -0
- package/package/acode/dist/background-command-manager.js +5 -5
- package/package/acode/dist/background-command-tools.js +1 -1
- package/package/acode/dist/built-in-file-tools.d.ts +25 -1
- package/package/acode/dist/built-in-file-tools.js +2 -2
- package/package/acode/dist/builtins/shellCommandResult.d.ts +3 -0
- package/package/acode/dist/builtins/shellCommandResult.js +1 -1
- package/package/acode/dist/builtins/shellCommandRunner.d.ts +2 -0
- package/package/acode/dist/builtins/shellCommandRunner.js +1 -1
- package/package/acode/dist/image-utils.d.ts +52 -0
- package/package/acode/dist/image-utils.js +2 -0
- package/package/acode/dist/index.d.ts +1 -0
- package/package/acode/dist/index.js +1 -1
- package/package/acode/dist/runtime.d.ts +15 -1
- package/package/acode/dist/runtime.js +26 -26
- package/package/acode/dist/sub-agent-tools.js +30 -26
- package/package/acode/dist/sub-agent-types.d.ts +1 -1
- package/package/acode/dist/tool-allocation.d.ts +4 -4
- package/package/acode/dist/tool-allocation.js +1 -1
- package/package/acode/dist/types.d.ts +3 -1
- package/package/aws-client-agent-mcp/dist/http-client.d.ts +4 -0
- package/package/aws-client-agent-mcp/dist/http-client.js +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +8 -0
- package/package/aws-client-agent-mcp/dist/mcp-server.js +28 -25
- package/package/aws-client-agent-mcp/dist/mcp-tools.js +6 -6
- package/package/aws-client-agent-mcp/dist/memory-store.d.ts +6 -0
- package/package/aws-client-agent-mcp/dist/memory-tools.js +2 -2
- package/package/aws-client-agent-mcp/dist/types.d.ts +4 -0
- package/package/aws-client-agent-mcp/package.json +1 -1
- package/package.json +3 -3
- package/package/aws-client-agent-mcp/dist/agent-client.test.d.ts +0 -1
- package/package/aws-client-agent-mcp/dist/agent-client.test.js +0 -1066
- package/package/aws-client-agent-mcp/dist/config.test.d.ts +0 -1
- package/package/aws-client-agent-mcp/dist/config.test.js +0 -259
- package/package/aws-client-agent-mcp/dist/context-manager.test.d.ts +0 -2
- package/package/aws-client-agent-mcp/dist/context-manager.test.js +0 -312
- package/package/aws-client-agent-mcp/dist/http-client.test.d.ts +0 -1
- package/package/aws-client-agent-mcp/dist/http-client.test.js +0 -808
- package/package/aws-client-agent-mcp/dist/launch-config-tools.test.d.ts +0 -1
- package/package/aws-client-agent-mcp/dist/launch-config-tools.test.js +0 -110
- package/package/aws-client-agent-mcp/dist/logger.test.d.ts +0 -1
- package/package/aws-client-agent-mcp/dist/logger.test.js +0 -27
- package/package/aws-client-agent-mcp/dist/mcp-server.test.d.ts +0 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js +0 -2798
- package/package/aws-client-agent-mcp/dist/mcp-tools.test.d.ts +0 -1
- package/package/aws-client-agent-mcp/dist/mcp-tools.test.js +0 -152
- package/package/aws-client-agent-mcp/dist/memory-store.test.d.ts +0 -1
- package/package/aws-client-agent-mcp/dist/memory-store.test.js +0 -664
- package/package/aws-client-agent-mcp/dist/message-buffer.test.d.ts +0 -1
- package/package/aws-client-agent-mcp/dist/message-buffer.test.js +0 -142
- package/package/aws-client-agent-mcp/dist/parent-lifecycle.test.d.ts +0 -1
- package/package/aws-client-agent-mcp/dist/parent-lifecycle.test.js +0 -81
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.test.d.ts +0 -1
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.test.js +0 -201
- package/package/aws-client-agent-mcp/dist/status-reporter.test.d.ts +0 -1
- package/package/aws-client-agent-mcp/dist/status-reporter.test.js +0 -157
- package/package/aws-client-agent-mcp/dist/watchdog.test.d.ts +0 -1
- package/package/aws-client-agent-mcp/dist/watchdog.test.js +0 -124
- package/package/aws-client-agent-mcp/dist/websocket-client.test.d.ts +0 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.test.js +0 -725
|
@@ -1,664 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import { mkdtemp, readdir, readFile, rm } from 'node:fs/promises';
|
|
3
|
-
import os from 'node:os';
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import { describe, it } from 'node:test';
|
|
6
|
-
import { MemoryStore, normalizeBoundFilePath } from './memory-store.js';
|
|
7
|
-
describe('MemoryStore', () => {
|
|
8
|
-
it('creates and reads memory by uri', async () => {
|
|
9
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
10
|
-
const storePath = path.join(dir, 'memory');
|
|
11
|
-
const store = new MemoryStore(storePath);
|
|
12
|
-
try {
|
|
13
|
-
const created = await store.createMemory({
|
|
14
|
-
memory_type: 'project_memory',
|
|
15
|
-
uri: 'core://agent/profile',
|
|
16
|
-
content: 'I am a backend expert.'
|
|
17
|
-
});
|
|
18
|
-
assert.equal(created.uri, 'core://agent/profile');
|
|
19
|
-
const loaded = await store.readMemory({ uri: 'core://agent/profile', memory_type: 'project_memory' });
|
|
20
|
-
assert.ok(loaded);
|
|
21
|
-
assert.equal(loaded?.content, 'I am a backend expert.');
|
|
22
|
-
}
|
|
23
|
-
finally {
|
|
24
|
-
await rm(dir, { recursive: true, force: true });
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
it('updates memory with exact replace and append', async () => {
|
|
28
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
29
|
-
const storePath = path.join(dir, 'memory');
|
|
30
|
-
const store = new MemoryStore(storePath);
|
|
31
|
-
try {
|
|
32
|
-
await store.createMemory({
|
|
33
|
-
memory_type: 'project_memory',
|
|
34
|
-
uri: 'notes://project/todo',
|
|
35
|
-
content: 'finish api docs'
|
|
36
|
-
});
|
|
37
|
-
const replaced = await store.updateMemory({
|
|
38
|
-
memory_type: 'project_memory',
|
|
39
|
-
uri: 'notes://project/todo',
|
|
40
|
-
old_string: 'api docs',
|
|
41
|
-
new_string: 'API docs v2'
|
|
42
|
-
});
|
|
43
|
-
assert.equal(replaced.content, 'finish API docs v2');
|
|
44
|
-
const appended = await store.updateMemory({
|
|
45
|
-
memory_type: 'project_memory',
|
|
46
|
-
uri: 'notes://project/todo',
|
|
47
|
-
append: '\n- add memory tests'
|
|
48
|
-
});
|
|
49
|
-
assert.match(appended.content, /add memory tests/);
|
|
50
|
-
}
|
|
51
|
-
finally {
|
|
52
|
-
await rm(dir, { recursive: true, force: true });
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
it('searches memories by query and supports limit', async () => {
|
|
56
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
57
|
-
const storePath = path.join(dir, 'memory');
|
|
58
|
-
const store = new MemoryStore(storePath);
|
|
59
|
-
try {
|
|
60
|
-
await store.createMemory({
|
|
61
|
-
memory_type: 'project_memory',
|
|
62
|
-
uri: 'core://agent/skills',
|
|
63
|
-
content: 'java spring boot mysql'
|
|
64
|
-
});
|
|
65
|
-
await store.createMemory({
|
|
66
|
-
memory_type: 'project_memory',
|
|
67
|
-
uri: 'notes://project/readme',
|
|
68
|
-
content: 'project setup and architecture'
|
|
69
|
-
});
|
|
70
|
-
const result = await store.searchMemory({ query: 'project', limit: 1, memory_type: 'project_memory' });
|
|
71
|
-
assert.equal(result.results.length, 1);
|
|
72
|
-
assert.equal(result.results[0]?.uri, 'notes://project/readme');
|
|
73
|
-
}
|
|
74
|
-
finally {
|
|
75
|
-
await rm(dir, { recursive: true, force: true });
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
it('deletes memory and no longer reads it', async () => {
|
|
79
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
80
|
-
const storePath = path.join(dir, 'memory');
|
|
81
|
-
const store = new MemoryStore(storePath);
|
|
82
|
-
try {
|
|
83
|
-
await store.createMemory({
|
|
84
|
-
memory_type: 'project_memory',
|
|
85
|
-
uri: 'core://agent/temp',
|
|
86
|
-
content: 'temporary memory'
|
|
87
|
-
});
|
|
88
|
-
const deleted = await store.deleteMemory({ uri: 'core://agent/temp', memory_type: 'project_memory' });
|
|
89
|
-
assert.equal(deleted, true);
|
|
90
|
-
const loaded = await store.readMemory({ uri: 'core://agent/temp', memory_type: 'project_memory' });
|
|
91
|
-
assert.equal(loaded, null);
|
|
92
|
-
}
|
|
93
|
-
finally {
|
|
94
|
-
await rm(dir, { recursive: true, force: true });
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
it('supports memory_type classification and list/filter', async () => {
|
|
98
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
99
|
-
const storePath = path.join(dir, 'memory');
|
|
100
|
-
const store = new MemoryStore(storePath);
|
|
101
|
-
try {
|
|
102
|
-
const types = ['recently_memory', 'agent_memory', 'project_memory'];
|
|
103
|
-
await store.createMemory({ memory_type: types[0], uri: 'task://todo/1', content: 'fix tests' });
|
|
104
|
-
await store.createMemory({ memory_type: types[1], uri: 'recent://ctx/1', content: 'just discussed API design' });
|
|
105
|
-
await store.createMemory({ memory_type: types[2], uri: 'core://archive/1', content: 'long-term architecture decision' });
|
|
106
|
-
const taskList = await store.listByType('recently_memory');
|
|
107
|
-
assert.equal(taskList.length, 1);
|
|
108
|
-
assert.equal(taskList[0]?.memory_type, 'recently_memory');
|
|
109
|
-
const recentList = await store.listByType('agent_memory');
|
|
110
|
-
assert.equal(recentList.length, 1);
|
|
111
|
-
assert.equal(recentList[0]?.memory_type, 'agent_memory');
|
|
112
|
-
// project_memory 已放开列举限制(文件变更检测需枚举永久记忆),应正常返回
|
|
113
|
-
const projectList = await store.listByType('project_memory');
|
|
114
|
-
assert.equal(projectList.length, 1);
|
|
115
|
-
assert.equal(projectList[0]?.memory_type, 'project_memory');
|
|
116
|
-
await assert.rejects(() => store.listByType('invalid_type'), /Invalid memory_type/);
|
|
117
|
-
}
|
|
118
|
-
finally {
|
|
119
|
-
await rm(dir, { recursive: true, force: true });
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
it('deletes task_list memory via deleteMemory', async () => {
|
|
123
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
124
|
-
const storePath = path.join(dir, 'memory');
|
|
125
|
-
const store = new MemoryStore(storePath);
|
|
126
|
-
try {
|
|
127
|
-
await store.createMemory({ memory_type: 'recently_memory', uri: 'task://todo/remove-1', content: 'to be removed' });
|
|
128
|
-
const deleted = await store.deleteMemory({ uri: 'task://todo/remove-1', memory_type: 'recently_memory' });
|
|
129
|
-
assert.equal(deleted, true);
|
|
130
|
-
assert.equal(await store.readMemory({ uri: 'task://todo/remove-1' }), null);
|
|
131
|
-
}
|
|
132
|
-
finally {
|
|
133
|
-
await rm(dir, { recursive: true, force: true });
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
it('reports memory stats with top-level counts and per-domain occupancy', async () => {
|
|
137
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
138
|
-
const storePath = path.join(dir, 'memory');
|
|
139
|
-
const store = new MemoryStore(storePath);
|
|
140
|
-
try {
|
|
141
|
-
await store.createMemory({ memory_type: 'recently_memory', uri: 'task://todo/stats', content: 'task' });
|
|
142
|
-
await store.createMemory({ memory_type: 'recently_memory', uri: 'task://todo/other', content: 'another task' });
|
|
143
|
-
await store.createMemory({ memory_type: 'agent_memory', uri: 'recent://ctx/stats', content: 'recent' });
|
|
144
|
-
await store.createMemory({ memory_type: 'agent_memory', uri: 'note://ctx/stats', content: 'recent note' });
|
|
145
|
-
await store.createMemory({ memory_type: 'project_memory', uri: 'core://stats/long-term', content: 'long term' });
|
|
146
|
-
const stats = await store.getStats();
|
|
147
|
-
assert.equal(stats.total, 5);
|
|
148
|
-
assert.deepEqual(stats.listable, { count: 4, limit: 64, hardLimit: 128, exceeded: false, hardExceeded: false });
|
|
149
|
-
assert.equal(stats.by_type.recently_memory.count, 2);
|
|
150
|
-
assert.equal(stats.by_type.recently_memory.domainCount, 1);
|
|
151
|
-
assert.equal(stats.by_type.recently_memory.by_domain.task?.count, 2);
|
|
152
|
-
assert.equal(stats.by_type.agent_memory.count, 2);
|
|
153
|
-
assert.equal(stats.by_type.agent_memory.domainCount, 2);
|
|
154
|
-
assert.equal(stats.by_type.agent_memory.by_domain.recent?.count, 1);
|
|
155
|
-
assert.equal(stats.by_type.agent_memory.by_domain.note?.count, 1);
|
|
156
|
-
assert.equal(stats.by_type.project_memory.count, 1);
|
|
157
|
-
assert.equal(stats.by_type.project_memory.domainCount, 1);
|
|
158
|
-
assert.equal(stats.by_type.project_memory.by_domain.core?.count, 1);
|
|
159
|
-
}
|
|
160
|
-
finally {
|
|
161
|
-
await rm(dir, { recursive: true, force: true });
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
it('saves memory data atomically without leaving temporary files after successful writes', async () => {
|
|
165
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
166
|
-
const storePath = path.join(dir, 'memory');
|
|
167
|
-
const store = new MemoryStore(storePath);
|
|
168
|
-
try {
|
|
169
|
-
await store.createMemory({ memory_type: 'project_memory', uri: 'core://atomic/write', content: 'persisted' });
|
|
170
|
-
const files = await readdir(storePath);
|
|
171
|
-
assert.deepEqual(files, ['core.json']);
|
|
172
|
-
}
|
|
173
|
-
finally {
|
|
174
|
-
await rm(dir, { recursive: true, force: true });
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
it('stores directory-mode memories in per-domain json files', async () => {
|
|
178
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
179
|
-
const storePath = path.join(dir, 'memory');
|
|
180
|
-
const store = new MemoryStore(storePath);
|
|
181
|
-
try {
|
|
182
|
-
await store.createMemory({ memory_type: 'project_memory', uri: 'core://agent/profile', content: 'profile' });
|
|
183
|
-
await store.createMemory({ memory_type: 'project_memory', uri: 'notes://project/readme', content: 'readme' });
|
|
184
|
-
assert.deepEqual((await readdir(storePath)).sort(), ['core.json', 'notes.json']);
|
|
185
|
-
const coreRaw = JSON.parse(await readFile(path.join(storePath, 'core.json'), 'utf-8'));
|
|
186
|
-
const notesRaw = JSON.parse(await readFile(path.join(storePath, 'notes.json'), 'utf-8'));
|
|
187
|
-
assert.equal(coreRaw.by_uri['core://agent/profile']?.content, 'profile');
|
|
188
|
-
assert.equal(notesRaw.by_uri['notes://project/readme']?.content, 'readme');
|
|
189
|
-
const searched = await store.searchMemory({ query: 'readme', memory_type: 'project_memory' });
|
|
190
|
-
assert.equal(searched.results[0]?.uri, 'notes://project/readme');
|
|
191
|
-
}
|
|
192
|
-
finally {
|
|
193
|
-
await rm(dir, { recursive: true, force: true });
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
it('removes an empty domain file after deleting the last memory in that domain', async () => {
|
|
197
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
198
|
-
const storePath = path.join(dir, 'memory');
|
|
199
|
-
const store = new MemoryStore(storePath);
|
|
200
|
-
try {
|
|
201
|
-
await store.createMemory({ memory_type: 'project_memory', uri: 'core://agent/profile', content: 'profile' });
|
|
202
|
-
await store.createMemory({ memory_type: 'project_memory', uri: 'notes://project/readme', content: 'readme' });
|
|
203
|
-
assert.equal(await store.deleteMemory({ uri: 'notes://project/readme', memory_type: 'project_memory' }), true);
|
|
204
|
-
assert.deepEqual(await readdir(storePath), ['core.json']);
|
|
205
|
-
assert.equal(await store.readMemory({ uri: 'notes://project/readme', memory_type: 'project_memory' }), null);
|
|
206
|
-
}
|
|
207
|
-
finally {
|
|
208
|
-
await rm(dir, { recursive: true, force: true });
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
it('marks soft listable limits as exceeded without blocking creation', async () => {
|
|
212
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
213
|
-
const storePath = path.join(dir, 'memory');
|
|
214
|
-
const store = new MemoryStore(storePath);
|
|
215
|
-
try {
|
|
216
|
-
for (let index = 0; index < 32; index += 1) {
|
|
217
|
-
await store.createMemory({
|
|
218
|
-
memory_type: 'recently_memory',
|
|
219
|
-
uri: `task://todo/${index}`,
|
|
220
|
-
content: `task ${index}`
|
|
221
|
-
});
|
|
222
|
-
await store.createMemory({
|
|
223
|
-
memory_type: 'agent_memory',
|
|
224
|
-
uri: `recent://ctx/${index}`,
|
|
225
|
-
content: `recent context ${index}`
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
const longTermMemory = await store.createMemory({
|
|
229
|
-
memory_type: 'project_memory',
|
|
230
|
-
uri: 'core://long-term/not-listable',
|
|
231
|
-
content: 'long-term memories are not constrained by listable limits'
|
|
232
|
-
});
|
|
233
|
-
assert.equal(longTermMemory.memory_type, 'project_memory');
|
|
234
|
-
const stats = await store.getStats();
|
|
235
|
-
assert.equal(stats.listable.count, 64);
|
|
236
|
-
assert.equal(stats.listable.exceeded, false);
|
|
237
|
-
assert.equal(stats.listable.hardExceeded, false);
|
|
238
|
-
assert.equal(stats.by_type.recently_memory.exceeded, false);
|
|
239
|
-
assert.equal(stats.by_type.agent_memory.exceeded, false);
|
|
240
|
-
const allowedBeyondSoftLimit = await store.createMemory({
|
|
241
|
-
memory_type: 'recently_memory',
|
|
242
|
-
uri: 'task://todo/beyond-soft-limit',
|
|
243
|
-
content: 'allowed beyond soft limit until hard limit'
|
|
244
|
-
});
|
|
245
|
-
assert.equal(allowedBeyondSoftLimit.memory_type, 'recently_memory');
|
|
246
|
-
const exceededStats = await store.getStats();
|
|
247
|
-
assert.equal(exceededStats.listable.exceeded, true);
|
|
248
|
-
assert.equal(exceededStats.by_type.recently_memory.exceeded, false);
|
|
249
|
-
assert.equal(exceededStats.by_type.recently_memory.by_domain.task?.exceeded, true);
|
|
250
|
-
}
|
|
251
|
-
finally {
|
|
252
|
-
await rm(dir, { recursive: true, force: true });
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
it('does not block creation by global listable total when domain limits are healthy', async () => {
|
|
256
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
257
|
-
const storePath = path.join(dir, 'memory');
|
|
258
|
-
const store = new MemoryStore(storePath);
|
|
259
|
-
try {
|
|
260
|
-
for (let index = 0; index < 64; index += 1) {
|
|
261
|
-
await store.createMemory({
|
|
262
|
-
memory_type: 'recently_memory',
|
|
263
|
-
uri: `task${index}://todo/current`,
|
|
264
|
-
content: `task ${index}`
|
|
265
|
-
});
|
|
266
|
-
await store.createMemory({
|
|
267
|
-
memory_type: 'agent_memory',
|
|
268
|
-
uri: `recent${index}://ctx/current`,
|
|
269
|
-
content: `recent ${index}`
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
const created = await store.createMemory({
|
|
273
|
-
memory_type: 'recently_memory',
|
|
274
|
-
uri: 'task0://todo/extra',
|
|
275
|
-
content: 'same domain remains below item hard limit'
|
|
276
|
-
});
|
|
277
|
-
assert.equal(created.memory_type, 'recently_memory');
|
|
278
|
-
const stats = await store.getStats();
|
|
279
|
-
assert.equal(stats.listable.hardExceeded, true);
|
|
280
|
-
assert.equal(stats.by_type.recently_memory.hardExceeded, true);
|
|
281
|
-
assert.equal(stats.by_type.recently_memory.by_domain.task0?.count, 2);
|
|
282
|
-
}
|
|
283
|
-
finally {
|
|
284
|
-
await rm(dir, { recursive: true, force: true });
|
|
285
|
-
}
|
|
286
|
-
});
|
|
287
|
-
it('rejects invalid memory_type on create', async () => {
|
|
288
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
289
|
-
const storePath = path.join(dir, 'memory');
|
|
290
|
-
const store = new MemoryStore(storePath);
|
|
291
|
-
try {
|
|
292
|
-
await assert.rejects(() => store.createMemory({ memory_type: 'invalid_type', uri: 'x://1', content: 'x' }), /Invalid memory_type/);
|
|
293
|
-
}
|
|
294
|
-
finally {
|
|
295
|
-
await rm(dir, { recursive: true, force: true });
|
|
296
|
-
}
|
|
297
|
-
});
|
|
298
|
-
it('sets expiresAt for recently_memory on create', async () => {
|
|
299
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
300
|
-
const storePath = path.join(dir, 'memory');
|
|
301
|
-
const store = new MemoryStore(storePath);
|
|
302
|
-
try {
|
|
303
|
-
const created = await store.createMemory({
|
|
304
|
-
memory_type: 'agent_memory',
|
|
305
|
-
uri: 'recent://expire/test1',
|
|
306
|
-
content: 'test expiration'
|
|
307
|
-
});
|
|
308
|
-
assert.ok(created.expiresAt, 'expiresAt should be set for recently_memory');
|
|
309
|
-
const expiresDate = new Date(created.expiresAt);
|
|
310
|
-
const now = new Date();
|
|
311
|
-
const diffHours = (expiresDate.getTime() - now.getTime()) / (60 * 60 * 1000);
|
|
312
|
-
// Should be approximately 12 hours from now (initial TTL)
|
|
313
|
-
assert.ok(diffHours > 11 && diffHours < 13, `expiresAt should be ~12h from now, got ${diffHours}h`);
|
|
314
|
-
// memory type should NOT have expiresAt
|
|
315
|
-
const memoryCreated = await store.createMemory({
|
|
316
|
-
memory_type: 'project_memory',
|
|
317
|
-
uri: 'core://perm/test1',
|
|
318
|
-
content: 'permanent'
|
|
319
|
-
});
|
|
320
|
-
assert.equal(memoryCreated.expiresAt, undefined, 'memory type should not have expiresAt');
|
|
321
|
-
}
|
|
322
|
-
finally {
|
|
323
|
-
await rm(dir, { recursive: true, force: true });
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
|
-
it('updates recently_memory expiresAt on content change', async () => {
|
|
327
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
328
|
-
const storePath = path.join(dir, 'memory');
|
|
329
|
-
const store = new MemoryStore(storePath);
|
|
330
|
-
try {
|
|
331
|
-
const created = await store.createMemory({
|
|
332
|
-
memory_type: 'agent_memory',
|
|
333
|
-
uri: 'recent://expire/test2',
|
|
334
|
-
content: 'original content'
|
|
335
|
-
});
|
|
336
|
-
const originalExpiresAt = created.expiresAt;
|
|
337
|
-
// Wait 50ms so the new expiresAt is guaranteed different
|
|
338
|
-
await new Promise(r => setTimeout(r, 50));
|
|
339
|
-
const updated = await store.updateMemory({
|
|
340
|
-
uri: 'recent://expire/test2',
|
|
341
|
-
old_string: 'original',
|
|
342
|
-
new_string: 'updated',
|
|
343
|
-
});
|
|
344
|
-
assert.ok(updated.expiresAt, 'expiresAt should still be set after update');
|
|
345
|
-
assert.notEqual(updated.expiresAt, originalExpiresAt, 'expiresAt should be refreshed on content change');
|
|
346
|
-
}
|
|
347
|
-
finally {
|
|
348
|
-
await rm(dir, { recursive: true, force: true });
|
|
349
|
-
}
|
|
350
|
-
});
|
|
351
|
-
it('lists expired recently_memories', async () => {
|
|
352
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
353
|
-
const storePath = path.join(dir, 'memory');
|
|
354
|
-
const store = new MemoryStore(storePath);
|
|
355
|
-
try {
|
|
356
|
-
// Already expired (pass expiresAt in the past)
|
|
357
|
-
await store.createMemory({
|
|
358
|
-
memory_type: 'agent_memory',
|
|
359
|
-
uri: 'recent://expire/past1',
|
|
360
|
-
content: 'already expired',
|
|
361
|
-
expiresAt: new Date(Date.now() - 60_000).toISOString(), // 1 minute ago
|
|
362
|
-
});
|
|
363
|
-
// Future expiration
|
|
364
|
-
await store.createMemory({
|
|
365
|
-
memory_type: 'agent_memory',
|
|
366
|
-
uri: 'recent://expire/future1',
|
|
367
|
-
content: 'not expired yet',
|
|
368
|
-
});
|
|
369
|
-
const expired = await store.listExpiredRecentlyMemories();
|
|
370
|
-
assert.equal(expired.length, 1, 'should find exactly 1 expired memory');
|
|
371
|
-
assert.equal(expired[0]?.uri, 'recent://expire/past1', 'should find the past-expired memory');
|
|
372
|
-
}
|
|
373
|
-
finally {
|
|
374
|
-
await rm(dir, { recursive: true, force: true });
|
|
375
|
-
}
|
|
376
|
-
});
|
|
377
|
-
// ========== v2.x 并发认领语义测试 ==========
|
|
378
|
-
it('claims up to limit expired memories as recalling with owner and lease', async () => {
|
|
379
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
380
|
-
const storePath = path.join(dir, 'memory');
|
|
381
|
-
const store = new MemoryStore(storePath);
|
|
382
|
-
try {
|
|
383
|
-
// 创建 3 条已过期记忆(不同过期时间,验证最早过期优先)
|
|
384
|
-
const times = [Date.now() - 180_000, Date.now() - 120_000, Date.now() - 60_000];
|
|
385
|
-
const uris = [];
|
|
386
|
-
for (let i = 0; i < 3; i++) {
|
|
387
|
-
const uri = `recent://claim/expire${i}`;
|
|
388
|
-
uris.push(uri);
|
|
389
|
-
await store.createMemory({
|
|
390
|
-
memory_type: 'agent_memory',
|
|
391
|
-
uri,
|
|
392
|
-
content: `expired memory ${i}`,
|
|
393
|
-
expiresAt: new Date(times[i]).toISOString(),
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
// 认领(不传 uris → 全部认领)
|
|
397
|
-
const claim = await store.markExpiredMemoriesRecalling();
|
|
398
|
-
assert.equal(claim.marked, 3, 'should claim all 3 expired memories');
|
|
399
|
-
assert.deepEqual(new Set(claim.uris), new Set(uris));
|
|
400
|
-
// 认领后的记录:recalling + owner + 租约
|
|
401
|
-
const held = await store.listExpiredRecentlyMemories();
|
|
402
|
-
assert.equal(held.length, 3, 'own claimed memories still visible via list');
|
|
403
|
-
for (const m of held) {
|
|
404
|
-
assert.equal(m.memory_status, 'recalling');
|
|
405
|
-
assert.equal(m.updating_agent_id, 'local');
|
|
406
|
-
assert.ok(m.lease_expires_at, 'lease should be set');
|
|
407
|
-
}
|
|
408
|
-
// 幂等:再次认领不重复计数,仅续期
|
|
409
|
-
const claimAgain = await store.markExpiredMemoriesRecalling();
|
|
410
|
-
assert.equal(claimAgain.marked, 3, 'idempotent: no new claims counted');
|
|
411
|
-
}
|
|
412
|
-
finally {
|
|
413
|
-
await rm(dir, { recursive: true, force: true });
|
|
414
|
-
}
|
|
415
|
-
});
|
|
416
|
-
it('excludes others-recalling memories from list (ownership filter)', async () => {
|
|
417
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
418
|
-
const storePath = path.join(dir, 'memory');
|
|
419
|
-
const store = new MemoryStore(storePath);
|
|
420
|
-
try {
|
|
421
|
-
// 直接构造一条"他人认领"(updating_agent_id != 'local')的过期记忆
|
|
422
|
-
await store.createMemory({
|
|
423
|
-
memory_type: 'agent_memory',
|
|
424
|
-
uri: 'recent://claim/other1',
|
|
425
|
-
content: 'claimed by another instance',
|
|
426
|
-
expiresAt: new Date(Date.now() - 60_000).toISOString(),
|
|
427
|
-
});
|
|
428
|
-
const data = await store.loadData();
|
|
429
|
-
const rec = data.by_uri['recent://claim/other1'];
|
|
430
|
-
rec.memory_status = 'recalling';
|
|
431
|
-
rec.updating_agent_id = 'other-instance';
|
|
432
|
-
await store.saveData(data);
|
|
433
|
-
// 自己的可认领记忆
|
|
434
|
-
await store.createMemory({
|
|
435
|
-
memory_type: 'agent_memory',
|
|
436
|
-
uri: 'recent://claim/mine1',
|
|
437
|
-
content: 'mine to claim',
|
|
438
|
-
expiresAt: new Date(Date.now() - 30_000).toISOString(),
|
|
439
|
-
});
|
|
440
|
-
// 他人的 recalling 不可见,仅自己的 normal 可见
|
|
441
|
-
const expired = await store.listExpiredRecentlyMemories();
|
|
442
|
-
assert.equal(expired.length, 1, 'others-recalling should be filtered out');
|
|
443
|
-
assert.equal(expired[0]?.uri, 'recent://claim/mine1');
|
|
444
|
-
}
|
|
445
|
-
finally {
|
|
446
|
-
await rm(dir, { recursive: true, force: true });
|
|
447
|
-
}
|
|
448
|
-
});
|
|
449
|
-
it('clearRecallingExpiredMemories only deletes own claimed + supports uris filter', async () => {
|
|
450
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
|
|
451
|
-
const storePath = path.join(dir, 'memory');
|
|
452
|
-
const store = new MemoryStore(storePath);
|
|
453
|
-
try {
|
|
454
|
-
// 两条自己认领的过期记忆 + 一条他人认领的过期记忆
|
|
455
|
-
await store.createMemory({
|
|
456
|
-
memory_type: 'agent_memory',
|
|
457
|
-
uri: 'recent://clear/own1',
|
|
458
|
-
content: 'own 1',
|
|
459
|
-
expiresAt: new Date(Date.now() - 60_000).toISOString(),
|
|
460
|
-
});
|
|
461
|
-
await store.createMemory({
|
|
462
|
-
memory_type: 'agent_memory',
|
|
463
|
-
uri: 'recent://clear/own2',
|
|
464
|
-
content: 'own 2',
|
|
465
|
-
expiresAt: new Date(Date.now() - 60_000).toISOString(),
|
|
466
|
-
});
|
|
467
|
-
await store.createMemory({
|
|
468
|
-
memory_type: 'agent_memory',
|
|
469
|
-
uri: 'recent://clear/other1',
|
|
470
|
-
content: 'other 1',
|
|
471
|
-
expiresAt: new Date(Date.now() - 60_000).toISOString(),
|
|
472
|
-
});
|
|
473
|
-
await store.markExpiredMemoriesRecalling();
|
|
474
|
-
// 标记"他人认领"(模拟另一实例)
|
|
475
|
-
const data = await store.loadData();
|
|
476
|
-
data.by_uri['recent://clear/other1'].memory_status = 'recalling';
|
|
477
|
-
data.by_uri['recent://clear/other1'].updating_agent_id = 'other-instance';
|
|
478
|
-
await store.saveData(data);
|
|
479
|
-
// 分批收尾:只删 own1
|
|
480
|
-
const partial = await store.clearRecallingExpiredMemories(['recent://clear/own1']);
|
|
481
|
-
assert.equal(partial.deleted, 1);
|
|
482
|
-
assert.deepEqual(partial.uris, ['recent://clear/own1']);
|
|
483
|
-
// own2 仍在,他人认领的仍在(归属校验)
|
|
484
|
-
const remaining = await store.listExpiredRecentlyMemories();
|
|
485
|
-
const remainingUris = remaining.map(m => m.uri).sort();
|
|
486
|
-
assert.deepEqual(remainingUris, ['recent://clear/own2']);
|
|
487
|
-
// 最终收尾:不传 uris 删全部本人认领的
|
|
488
|
-
const final = await store.clearRecallingExpiredMemories();
|
|
489
|
-
assert.equal(final.deleted, 1);
|
|
490
|
-
assert.deepEqual(final.uris, ['recent://clear/own2']);
|
|
491
|
-
// 他人认领的始终未被删除(模拟:其 URI 仍在数据中)
|
|
492
|
-
const dataAfter = await store.loadData();
|
|
493
|
-
assert.ok(dataAfter.by_uri['recent://clear/other1'], 'others-recalling must not be deleted');
|
|
494
|
-
}
|
|
495
|
-
finally {
|
|
496
|
-
await rm(dir, { recursive: true, force: true });
|
|
497
|
-
}
|
|
498
|
-
});
|
|
499
|
-
});
|
|
500
|
-
// ========== listByFile 与 normalizeBoundFilePath 测试 ==========
|
|
501
|
-
describe('normalizeBoundFilePath', () => {
|
|
502
|
-
it('normalizes @/ prefix to ./', () => {
|
|
503
|
-
assert.equal(normalizeBoundFilePath('@/src/main.ts'), './src/main.ts');
|
|
504
|
-
});
|
|
505
|
-
it('normalizes / prefix to ./', () => {
|
|
506
|
-
assert.equal(normalizeBoundFilePath('/src/main.ts'), './src/main.ts');
|
|
507
|
-
});
|
|
508
|
-
it('normalizes bare path to ./', () => {
|
|
509
|
-
assert.equal(normalizeBoundFilePath('src/main.ts'), './src/main.ts');
|
|
510
|
-
});
|
|
511
|
-
it('keeps ./ prefix as-is', () => {
|
|
512
|
-
assert.equal(normalizeBoundFilePath('./src/main.ts'), './src/main.ts');
|
|
513
|
-
});
|
|
514
|
-
it('trims whitespace', () => {
|
|
515
|
-
assert.equal(normalizeBoundFilePath(' ./src/main.ts '), './src/main.ts');
|
|
516
|
-
});
|
|
517
|
-
it('converts backslashes to forward slashes (Windows path alignment with Java)', () => {
|
|
518
|
-
assert.equal(normalizeBoundFilePath('src\\utils\\file.ts'), './src/utils/file.ts');
|
|
519
|
-
assert.equal(normalizeBoundFilePath('.\\src\\utils\\file.ts'), './src/utils/file.ts');
|
|
520
|
-
assert.equal(normalizeBoundFilePath('@\\src\\utils\\file.ts'), './src/utils/file.ts');
|
|
521
|
-
});
|
|
522
|
-
it('collapses multiple leading slashes', () => {
|
|
523
|
-
assert.equal(normalizeBoundFilePath('//src/main.ts'), './src/main.ts');
|
|
524
|
-
assert.equal(normalizeBoundFilePath('///src/main.ts'), './src/main.ts');
|
|
525
|
-
});
|
|
526
|
-
it('produces identical output for slash-equivalent paths (TS/Java consistency)', () => {
|
|
527
|
-
const candidates = [
|
|
528
|
-
'./src/utils/file.ts',
|
|
529
|
-
'src/utils/file.ts',
|
|
530
|
-
'/src/utils/file.ts',
|
|
531
|
-
'@/src/utils/file.ts',
|
|
532
|
-
'src\\utils\\file.ts',
|
|
533
|
-
'.\\src\\utils\\file.ts',
|
|
534
|
-
];
|
|
535
|
-
const results = new Set(candidates.map(normalizeBoundFilePath));
|
|
536
|
-
assert.equal(results.size, 1, `expected all to normalize identically, got: ${[...results].join(', ')}`);
|
|
537
|
-
assert.equal([...results][0], './src/utils/file.ts');
|
|
538
|
-
});
|
|
539
|
-
});
|
|
540
|
-
describe('MemoryStore listByFile', () => {
|
|
541
|
-
it('finds memories by exact bound_files match', async () => {
|
|
542
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-listbyfile-'));
|
|
543
|
-
const storePath = path.join(dir, 'memory');
|
|
544
|
-
const store = new MemoryStore(storePath);
|
|
545
|
-
try {
|
|
546
|
-
await store.createMemory({
|
|
547
|
-
memory_type: 'project_memory',
|
|
548
|
-
uri: 'core://file/notes',
|
|
549
|
-
content: 'Notes about main.ts',
|
|
550
|
-
bound_files: ['./src/main.ts'],
|
|
551
|
-
});
|
|
552
|
-
await store.createMemory({
|
|
553
|
-
memory_type: 'project_memory',
|
|
554
|
-
uri: 'core://other/entry',
|
|
555
|
-
content: 'Unrelated memory',
|
|
556
|
-
bound_files: ['./src/utils.ts'],
|
|
557
|
-
});
|
|
558
|
-
const results = await store.listByFile('./src/main.ts');
|
|
559
|
-
assert.equal(results.length, 1);
|
|
560
|
-
assert.equal(results[0]?.uri, 'core://file/notes');
|
|
561
|
-
}
|
|
562
|
-
finally {
|
|
563
|
-
await rm(dir, { recursive: true, force: true });
|
|
564
|
-
}
|
|
565
|
-
});
|
|
566
|
-
it('normalizes file path before matching', async () => {
|
|
567
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-listbyfile-'));
|
|
568
|
-
const storePath = path.join(dir, 'memory');
|
|
569
|
-
const store = new MemoryStore(storePath);
|
|
570
|
-
try {
|
|
571
|
-
await store.createMemory({
|
|
572
|
-
memory_type: 'project_memory',
|
|
573
|
-
uri: 'core://file/notes',
|
|
574
|
-
content: 'Notes',
|
|
575
|
-
bound_files: ['./src/main.ts'],
|
|
576
|
-
});
|
|
577
|
-
// Search with @/ prefix should normalize to ./src/main.ts
|
|
578
|
-
const results = await store.listByFile('@/src/main.ts');
|
|
579
|
-
assert.equal(results.length, 1);
|
|
580
|
-
assert.equal(results[0]?.uri, 'core://file/notes');
|
|
581
|
-
// Search with bare path should also match
|
|
582
|
-
const results2 = await store.listByFile('src/main.ts');
|
|
583
|
-
assert.equal(results2.length, 1);
|
|
584
|
-
// Search with / prefix should also match
|
|
585
|
-
const results3 = await store.listByFile('/src/main.ts');
|
|
586
|
-
assert.equal(results3.length, 1);
|
|
587
|
-
}
|
|
588
|
-
finally {
|
|
589
|
-
await rm(dir, { recursive: true, force: true });
|
|
590
|
-
}
|
|
591
|
-
});
|
|
592
|
-
it('returns empty when no bound_files match', async () => {
|
|
593
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-listbyfile-'));
|
|
594
|
-
const storePath = path.join(dir, 'memory');
|
|
595
|
-
const store = new MemoryStore(storePath);
|
|
596
|
-
try {
|
|
597
|
-
await store.createMemory({
|
|
598
|
-
memory_type: 'project_memory',
|
|
599
|
-
uri: 'core://other/entry',
|
|
600
|
-
content: 'No files bound',
|
|
601
|
-
});
|
|
602
|
-
const results = await store.listByFile('./src/main.ts');
|
|
603
|
-
assert.equal(results.length, 0);
|
|
604
|
-
}
|
|
605
|
-
finally {
|
|
606
|
-
await rm(dir, { recursive: true, force: true });
|
|
607
|
-
}
|
|
608
|
-
});
|
|
609
|
-
it('matches memories with multiple bound_files', async () => {
|
|
610
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-listbyfile-'));
|
|
611
|
-
const storePath = path.join(dir, 'memory');
|
|
612
|
-
const store = new MemoryStore(storePath);
|
|
613
|
-
try {
|
|
614
|
-
await store.createMemory({
|
|
615
|
-
memory_type: 'project_memory',
|
|
616
|
-
uri: 'core://multi/file',
|
|
617
|
-
content: 'Multi-file memory',
|
|
618
|
-
bound_files: ['./src/main.ts', './src/utils.ts'],
|
|
619
|
-
});
|
|
620
|
-
const results1 = await store.listByFile('./src/main.ts');
|
|
621
|
-
assert.equal(results1.length, 1);
|
|
622
|
-
const results2 = await store.listByFile('./src/utils.ts');
|
|
623
|
-
assert.equal(results2.length, 1);
|
|
624
|
-
const results3 = await store.listByFile('./src/other.ts');
|
|
625
|
-
assert.equal(results3.length, 0);
|
|
626
|
-
}
|
|
627
|
-
finally {
|
|
628
|
-
await rm(dir, { recursive: true, force: true });
|
|
629
|
-
}
|
|
630
|
-
});
|
|
631
|
-
it('filters by memory_type when provided', async () => {
|
|
632
|
-
const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-listbyfile-'));
|
|
633
|
-
const storePath = path.join(dir, 'memory');
|
|
634
|
-
const store = new MemoryStore(storePath);
|
|
635
|
-
try {
|
|
636
|
-
await store.createMemory({
|
|
637
|
-
memory_type: 'project_memory',
|
|
638
|
-
uri: 'core://permanent/notes',
|
|
639
|
-
content: 'Permanent notes',
|
|
640
|
-
bound_files: ['./src/main.ts'],
|
|
641
|
-
});
|
|
642
|
-
await store.createMemory({
|
|
643
|
-
memory_type: 'agent_memory',
|
|
644
|
-
uri: 'recent://temp/notes',
|
|
645
|
-
content: 'Temporary notes',
|
|
646
|
-
bound_files: ['./src/main.ts'],
|
|
647
|
-
});
|
|
648
|
-
// Both types match without filter
|
|
649
|
-
const allResults = await store.listByFile('./src/main.ts');
|
|
650
|
-
assert.equal(allResults.length, 2);
|
|
651
|
-
// Filter by memory type
|
|
652
|
-
const memResults = await store.listByFile('./src/main.ts', 'project_memory');
|
|
653
|
-
assert.equal(memResults.length, 1);
|
|
654
|
-
assert.equal(memResults[0]?.memory_type, 'project_memory');
|
|
655
|
-
// Filter with options object
|
|
656
|
-
const recentResults = await store.listByFile('./src/main.ts', { memory_type: 'agent_memory' });
|
|
657
|
-
assert.equal(recentResults.length, 1);
|
|
658
|
-
assert.equal(recentResults[0]?.memory_type, 'agent_memory');
|
|
659
|
-
}
|
|
660
|
-
finally {
|
|
661
|
-
await rm(dir, { recursive: true, force: true });
|
|
662
|
-
}
|
|
663
|
-
});
|
|
664
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|