@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.
@@ -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 via memory_curated_store...');
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
- const result = await callMemoryTool('memory_stats', params);
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 stats = result?.stats ?? result;
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 (stats.by_layer) {
165
- const layerLines = Object.entries(stats.by_layer)
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 (stats.by_overlay) {
172
- const overlayLines = Object.entries(stats.by_overlay)
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 (stats.by_angle) {
179
- const angleLines = Object.entries(stats.by_angle)
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
- if (stats.total != null) {
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.30",
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"