@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.
- package/commands/memory.mjs +130 -1
- package/ecc.mjs +1 -1
- package/package.json +1 -1
package/commands/memory.mjs
CHANGED
|
@@ -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.
|
|
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}`;
|