@ghl-ai/aw 0.1.37-beta.30 → 0.1.37-beta.32
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/commands/memory.mjs +30 -17
- package/memory-bridge.mjs +68 -0
- package/package.json +3 -2
package/commands/memory.mjs
CHANGED
|
@@ -35,7 +35,7 @@ async function memoryStore(args) {
|
|
|
35
35
|
if (args['--tags']) params.tags = args['--tags'].split(',').map(s => s.trim());
|
|
36
36
|
|
|
37
37
|
const s = fmt.spinner();
|
|
38
|
-
s.start('Storing memory
|
|
38
|
+
s.start('Storing memory...');
|
|
39
39
|
try {
|
|
40
40
|
const result = await callMemoryTool('memory_curated_store', params);
|
|
41
41
|
s.stop('Memory stored');
|
|
@@ -156,40 +156,53 @@ async function memoryStats(args) {
|
|
|
156
156
|
const s = fmt.spinner();
|
|
157
157
|
s.start('Fetching memory statistics...');
|
|
158
158
|
try {
|
|
159
|
-
|
|
159
|
+
// No dedicated stats tool — use memory_search with broad query and aggregate
|
|
160
|
+
const result = await callMemoryTool('memory_search', { query: '*', limit: 200, ...params });
|
|
160
161
|
s.stop('Stats loaded');
|
|
161
162
|
|
|
162
|
-
const
|
|
163
|
+
const memories = result?.memories ?? result?.results ?? [];
|
|
164
|
+
const total = memories.length;
|
|
165
|
+
|
|
166
|
+
// Aggregate by layer, overlay, angle
|
|
167
|
+
const byLayer = {};
|
|
168
|
+
const byOverlay = {};
|
|
169
|
+
const byAngle = {};
|
|
170
|
+
for (const mem of memories) {
|
|
171
|
+
const layer = mem.layer || 'unclassified';
|
|
172
|
+
byLayer[layer] = (byLayer[layer] || 0) + 1;
|
|
173
|
+
for (const o of (mem.overlay || mem.overlays || [])) {
|
|
174
|
+
byOverlay[o] = (byOverlay[o] || 0) + 1;
|
|
175
|
+
}
|
|
176
|
+
for (const a of (mem.angle || mem.angles || [])) {
|
|
177
|
+
byAngle[a] = (byAngle[a] || 0) + 1;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
163
180
|
|
|
164
|
-
if (
|
|
165
|
-
const layerLines = Object.entries(
|
|
181
|
+
if (Object.keys(byLayer).length) {
|
|
182
|
+
const layerLines = Object.entries(byLayer)
|
|
183
|
+
.sort((a, b) => b[1] - a[1])
|
|
166
184
|
.map(([layer, count]) => ` ${chalk.cyan(layer.padEnd(20))} ${count}`)
|
|
167
185
|
.join('\n');
|
|
168
186
|
fmt.note(layerLines, 'By Layer');
|
|
169
187
|
}
|
|
170
188
|
|
|
171
|
-
if (
|
|
172
|
-
const overlayLines = Object.entries(
|
|
189
|
+
if (Object.keys(byOverlay).length) {
|
|
190
|
+
const overlayLines = Object.entries(byOverlay)
|
|
191
|
+
.sort((a, b) => b[1] - a[1])
|
|
173
192
|
.map(([overlay, count]) => ` ${chalk.magenta(overlay.padEnd(20))} ${count}`)
|
|
174
193
|
.join('\n');
|
|
175
194
|
fmt.note(overlayLines, 'By Overlay');
|
|
176
195
|
}
|
|
177
196
|
|
|
178
|
-
if (
|
|
179
|
-
const angleLines = Object.entries(
|
|
197
|
+
if (Object.keys(byAngle).length) {
|
|
198
|
+
const angleLines = Object.entries(byAngle)
|
|
199
|
+
.sort((a, b) => b[1] - a[1])
|
|
180
200
|
.map(([angle, count]) => ` ${chalk.yellow(angle.padEnd(20))} ${count}`)
|
|
181
201
|
.join('\n');
|
|
182
202
|
fmt.note(angleLines, 'By Angle');
|
|
183
203
|
}
|
|
184
204
|
|
|
185
|
-
|
|
186
|
-
fmt.logStep(`Total memories: ${chalk.bold(stats.total)}`);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (stats.recent_activity) {
|
|
190
|
-
fmt.logStep(`Recent activity: ${chalk.dim(stats.recent_activity)}`);
|
|
191
|
-
}
|
|
192
|
-
|
|
205
|
+
fmt.logStep(`Total memories: ${chalk.bold(total)}`);
|
|
193
206
|
fmt.outro('Stats complete');
|
|
194
207
|
} catch (err) {
|
|
195
208
|
s.stop(chalk.red('Failed'));
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// memory-bridge.mjs — Bridge between CLI and MCP memory backend (JSON-RPC)
|
|
2
|
+
|
|
3
|
+
import { MCP_BASE_URL } from './constants.mjs';
|
|
4
|
+
|
|
5
|
+
let _rpcId = 1;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Call an MCP memory tool by name via JSON-RPC 2.0 (Streamable HTTP).
|
|
9
|
+
* @param {string} toolName — MCP tool name (e.g. 'memory_curated_store', 'memory_search')
|
|
10
|
+
* @param {object} params — Tool arguments
|
|
11
|
+
* @returns {Promise<object>} Parsed tool result
|
|
12
|
+
*/
|
|
13
|
+
export async function callMemoryTool(toolName, params) {
|
|
14
|
+
const response = await fetch(MCP_BASE_URL, {
|
|
15
|
+
method: 'POST',
|
|
16
|
+
headers: {
|
|
17
|
+
'Content-Type': 'application/json',
|
|
18
|
+
'Accept': 'application/json, text/event-stream',
|
|
19
|
+
},
|
|
20
|
+
body: JSON.stringify({
|
|
21
|
+
jsonrpc: '2.0',
|
|
22
|
+
id: _rpcId++,
|
|
23
|
+
method: 'tools/call',
|
|
24
|
+
params: { name: toolName, arguments: params },
|
|
25
|
+
}),
|
|
26
|
+
signal: AbortSignal.timeout(30000),
|
|
27
|
+
});
|
|
28
|
+
if (!response.ok) {
|
|
29
|
+
const body = await response.text().catch(() => '');
|
|
30
|
+
throw new Error(`MCP ${toolName} failed: ${response.status} ${body}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const contentType = response.headers.get('content-type') || '';
|
|
34
|
+
|
|
35
|
+
// Handle SSE responses (text/event-stream)
|
|
36
|
+
if (contentType.includes('text/event-stream')) {
|
|
37
|
+
const text = await response.text();
|
|
38
|
+
const lines = text.split('\n');
|
|
39
|
+
for (const line of lines) {
|
|
40
|
+
if (line.startsWith('data: ')) {
|
|
41
|
+
try {
|
|
42
|
+
const event = JSON.parse(line.slice(6));
|
|
43
|
+
if (event.result) return extractToolResult(event.result);
|
|
44
|
+
if (event.error) throw new Error(`MCP ${toolName}: ${event.error.message}`);
|
|
45
|
+
} catch (e) {
|
|
46
|
+
if (e.message.startsWith('MCP ')) throw e;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
throw new Error(`MCP ${toolName}: no result in SSE stream`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Handle direct JSON responses
|
|
54
|
+
const json = await response.json();
|
|
55
|
+
if (json.error) throw new Error(`MCP ${toolName}: ${json.error.message}`);
|
|
56
|
+
return extractToolResult(json.result);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Extract the actual content from an MCP tools/call result. */
|
|
60
|
+
function extractToolResult(result) {
|
|
61
|
+
if (!result) return {};
|
|
62
|
+
// MCP tools/call returns { content: [{ type: 'text', text: '...' }] }
|
|
63
|
+
const content = result.content;
|
|
64
|
+
if (Array.isArray(content) && content.length > 0 && content[0].text) {
|
|
65
|
+
try { return JSON.parse(content[0].text); } catch { return { text: content[0].text }; }
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ghl-ai/aw",
|
|
3
|
-
"version": "0.1.37-beta.
|
|
3
|
+
"version": "0.1.37-beta.32",
|
|
4
4
|
"description": "Agentic Workspace CLI — pull, push & manage agents, skills and commands from the registry",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": "bin.js",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"hooks.mjs",
|
|
27
27
|
"ecc.mjs",
|
|
28
28
|
"render-rules.mjs",
|
|
29
|
-
"telemetry.mjs"
|
|
29
|
+
"telemetry.mjs",
|
|
30
|
+
"memory-bridge.mjs"
|
|
30
31
|
],
|
|
31
32
|
"engines": {
|
|
32
33
|
"node": ">=18.0.0"
|