@ghl-ai/aw 0.1.37-beta.37 → 0.1.37-beta.39

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.
@@ -1,4 +1,4 @@
1
- // commands/memory.mjs — `aw memory [store|search|pack|stats|validate|invalidate|sync]`
1
+ // commands/memory.mjs — `aw memory [store|search|pack|stats|validate|invalidate|sync|audit]`
2
2
 
3
3
  import { join } from 'node:path';
4
4
  import { homedir } from 'node:os';
@@ -18,6 +18,7 @@ export async function memoryCommand(args) {
18
18
  case 'validate': return memoryValidate(args);
19
19
  case 'invalidate': return memoryInvalidate(args);
20
20
  case 'sync': return memorySync(args);
21
+ case 'audit': return memoryAudit(args);
21
22
  default: return memoryHelp();
22
23
  }
23
24
  }
@@ -345,6 +346,130 @@ async function memorySync(args) {
345
346
  }
346
347
  }
347
348
 
349
+ // ── audit ─────────────────────────────────────────────────────────────
350
+
351
+ async function memoryAudit(args) {
352
+ fmt.intro('aw memory audit');
353
+
354
+ const sampleSize = parseInt(args['--sample'] || '30', 10);
355
+ const days = parseInt(args['--days'] || '30', 10);
356
+
357
+ const s = fmt.spinner();
358
+ s.start(`Fetching memories from last ${days} days...`);
359
+
360
+ try {
361
+ // Search for recent memories
362
+ const result = await callMemoryTool('memory_search', {
363
+ query: '*',
364
+ limit: 200
365
+ });
366
+ const memories = Array.isArray(result) ? result : (result?.memories ?? result?.results ?? []);
367
+
368
+ if (memories.length === 0) {
369
+ s.stop('No memories found');
370
+ fmt.outro('Audit complete — nothing to audit');
371
+ return;
372
+ }
373
+
374
+ // Sample randomly
375
+ const sampled = memories
376
+ .sort(() => Math.random() - 0.5)
377
+ .slice(0, sampleSize);
378
+
379
+ s.stop(`Sampled ${sampled.length} of ${memories.length} memories`);
380
+
381
+ // Rate each memory using simple heuristics (no LLM needed for local audit)
382
+ let totalScore = 0;
383
+ const ratings = { excellent: 0, good: 0, fair: 0, poor: 0, bad: 0 };
384
+ const issues = [];
385
+
386
+ for (const mem of sampled) {
387
+ const content = mem.content || mem.text || '';
388
+ const score = rateMemoryQuality(content);
389
+ totalScore += score;
390
+
391
+ if (score >= 5) ratings.excellent++;
392
+ else if (score >= 4) ratings.good++;
393
+ else if (score >= 3) ratings.fair++;
394
+ else if (score >= 2) ratings.poor++;
395
+ else ratings.bad++;
396
+
397
+ if (score <= 2) {
398
+ issues.push({
399
+ id: (mem.id || '').slice(0, 8),
400
+ score,
401
+ content: content.slice(0, 80),
402
+ reason: getQualityIssue(content),
403
+ });
404
+ }
405
+ }
406
+
407
+ const avgScore = (totalScore / sampled.length).toFixed(1);
408
+
409
+ // Display results
410
+ const distLines = [
411
+ ` ${chalk.green('Excellent (5):')} ${ratings.excellent}`,
412
+ ` ${chalk.cyan('Good (4):')} ${ratings.good}`,
413
+ ` ${chalk.yellow('Fair (3):')} ${ratings.fair}`,
414
+ ` ${chalk.hex('#FF6B35')('Poor (2):')} ${ratings.poor}`,
415
+ ` ${chalk.red('Bad (1):')} ${ratings.bad}`,
416
+ ].join('\n');
417
+ fmt.note(distLines, `Quality Distribution (avg: ${avgScore}/5)`);
418
+
419
+ if (issues.length > 0) {
420
+ const issueLines = issues
421
+ .slice(0, 10)
422
+ .map(i => ` ${chalk.dim(i.id)} ${chalk.red(`[${i.score}]`)} ${i.reason}\n ${chalk.dim(i.content)}`)
423
+ .join('\n');
424
+ fmt.note(issueLines, `Flagged (${issues.length} low-quality)`);
425
+ }
426
+
427
+ fmt.outro(`Audit complete — ${sampled.length} memories sampled, avg score ${avgScore}/5`);
428
+ } catch (err) {
429
+ s.stop(chalk.red('Failed'));
430
+ fmt.cancel(`Audit failed: ${err.message}`);
431
+ }
432
+ }
433
+
434
+ /**
435
+ * Rate memory quality 1-5 using heuristics.
436
+ * 5 = specific, actionable, references code/tools
437
+ * 1 = vague, generic, not useful
438
+ */
439
+ function rateMemoryQuality(content) {
440
+ let score = 3; // Start at "fair"
441
+
442
+ // Positive signals
443
+ if (content.length > 80) score += 0.5; // Detailed
444
+ if (/`[^`]+`/.test(content)) score += 0.5; // References code
445
+ if (/@\w+/.test(content)) score += 0.3; // References packages
446
+ if (/\b(must|never|always|require)\b/i.test(content)) score += 0.3; // Actionable
447
+ if (/\b(because|since|due to|reason)\b/i.test(content)) score += 0.3; // Has reasoning
448
+ if (/\b(port|endpoint|url|api|service|module)\b/i.test(content)) score += 0.2; // Specific
449
+
450
+ // Negative signals
451
+ if (content.length < 30) score -= 1.5; // Too short
452
+ if (content.length < 50) score -= 0.5; // Short
453
+ if (/^(we |I |the team )/i.test(content)) score -= 0.3; // Narrative style
454
+ if (/\b(worked on|looked at|did some)\b/i.test(content)) score -= 1; // Vague
455
+ if (/^(test|e2e test|delete)/i.test(content)) score -= 0.5; // Test artifacts
456
+ if (/\[Updated\].*\[Updated\]/s.test(content)) score -= 0.3; // Over-merged
457
+
458
+ return Math.max(1, Math.min(5, Math.round(score)));
459
+ }
460
+
461
+ /**
462
+ * Return a brief reason why a memory scored low.
463
+ */
464
+ function getQualityIssue(content) {
465
+ if (content.length < 30) return 'Too short';
466
+ if (/\b(worked on|looked at|did some)\b/i.test(content)) return 'Vague/generic';
467
+ if (/^(test|e2e test|delete)/i.test(content)) return 'Test artifact';
468
+ if (/\[Updated\].*\[Updated\]/s.test(content)) return 'Over-merged';
469
+ if (content.length < 50) return 'Lacks detail';
470
+ return 'Low specificity';
471
+ }
472
+
348
473
  // ── help ─────────────────────────────────────────────────────────────
349
474
 
350
475
  function memoryHelp() {
@@ -388,6 +513,10 @@ function memoryHelp() {
388
513
  cmd('aw memory sync', 'Sync memories to local files'),
389
514
  cmd(' --force', 'Force re-sync even if cache is fresh'),
390
515
  '',
516
+ cmd('aw memory audit', 'Audit memory quality (heuristic)'),
517
+ cmd(' --sample <n>', 'Sample size (default: 30)'),
518
+ cmd(' --days <n>', 'Days to look back (default: 30)'),
519
+ '',
391
520
  ].join('\n');
392
521
 
393
522
  console.log(help);
package/ecc.mjs CHANGED
@@ -9,7 +9,7 @@ import * as fmt from "./fmt.mjs";
9
9
 
10
10
  const AW_ECC_REPO_SSH = "git@github.com:shreyansh-ghl/aw-ecc.git";
11
11
  const AW_ECC_REPO_HTTPS = "https://github.com/shreyansh-ghl/aw-ecc.git";
12
- const AW_ECC_TAG = "v1.4.0";
12
+ const AW_ECC_TAG = "v1.4.1";
13
13
 
14
14
  const MARKETPLACE_NAME = "aw-marketplace";
15
15
  const PLUGIN_KEY = `aw@${MARKETPLACE_NAME}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghl-ai/aw",
3
- "version": "0.1.37-beta.37",
3
+ "version": "0.1.37-beta.39",
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",