@kevin0181/memoc 1.0.6 → 1.0.8
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/README.md +7 -3
- package/bin/cli.js +80 -34
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -46,9 +46,13 @@ npx @kevin0181/memoc update
|
|
|
46
46
|
# Print current status in ~10 lines
|
|
47
47
|
npx @kevin0181/memoc summary
|
|
48
48
|
|
|
49
|
-
#
|
|
50
|
-
npx @kevin0181/memoc search "auth"
|
|
51
|
-
npx @kevin0181/memoc search "auth" --snippets --limit 5
|
|
49
|
+
# Search memory/agent docs first (token-efficient)
|
|
50
|
+
npx @kevin0181/memoc search "auth"
|
|
51
|
+
npx @kevin0181/memoc search "auth" --snippets --limit 5
|
|
52
|
+
|
|
53
|
+
# Search project source/text files only when memory is not enough
|
|
54
|
+
npx @kevin0181/memoc grep "GetParticles"
|
|
55
|
+
npx @kevin0181/memoc grep "GetParticles" --snippets --limit 5
|
|
52
56
|
|
|
53
57
|
# Estimate token cost of current memory files
|
|
54
58
|
npx @kevin0181/memoc tokens
|
package/bin/cli.js
CHANGED
|
@@ -546,7 +546,8 @@ function managedBlock() {
|
|
|
546
546
|
## Before Opening More Files
|
|
547
547
|
- [ ] Run memoc commands in this order: \`memoc search "<query>"\` → \`.\\.memoc\\bin\\memoc.cmd search "<query>"\` (Windows) or \`.memoc/bin/memoc search "<query>"\` (sh) → \`npx @kevin0181/memoc search "<query>"\`
|
|
548
548
|
- [ ] Open on demand: \`02\` status · \`04\` resume · \`06\` rules · \`llms.txt\` map
|
|
549
|
-
- [ ]
|
|
549
|
+
- [ ] If memory search is not enough, search project files with \`memoc grep "<query>" --limit 5\`
|
|
550
|
+
- [ ] Keep output small: \`summary\`, \`search --limit\`, \`grep --limit\`, \`--snippets\`
|
|
550
551
|
|
|
551
552
|
## Before Finishing _(update only applicable files; skip Q&A / throwaway exploration)_
|
|
552
553
|
- [ ] Code/config/deps changed → \`02\` (version, commands list, Last synced) + \`session-summary.md\` (status, changed, open tasks)
|
|
@@ -859,7 +860,8 @@ On-demand reference only. The entry-file managed block is authoritative.
|
|
|
859
860
|
|
|
860
861
|
## Search First
|
|
861
862
|
|
|
862
|
-
\`memoc search "<query>"\` — returns file:line matches across
|
|
863
|
+
\`memoc search "<query>"\` — returns file:line matches across memory and agent docs only.
|
|
864
|
+
\`memoc grep "<query>"\` — searches project source/text files when memory docs are not enough.
|
|
863
865
|
If \`memoc\` is not on PATH, try \`.\\.memoc\\bin\\memoc.cmd search "<query>"\` on Windows or \`.memoc/bin/memoc search "<query>"\` in sh, then \`npx @kevin0181/memoc search "<query>"\`.
|
|
864
866
|
Use it before opening any file to avoid reading more than needed.
|
|
865
867
|
`;
|
|
@@ -1039,9 +1041,13 @@ memoc update
|
|
|
1039
1041
|
# Tiny status overview
|
|
1040
1042
|
memoc summary
|
|
1041
1043
|
|
|
1042
|
-
#
|
|
1043
|
-
memoc search "<query>" --limit 12
|
|
1044
|
+
# Search memory first; add --snippets only when needed
|
|
1045
|
+
memoc search "<query>" --limit 12
|
|
1044
1046
|
memoc search "<query>" --snippets --limit 5
|
|
1047
|
+
|
|
1048
|
+
# Search project source/text files when memory is not enough
|
|
1049
|
+
memoc grep "<query>" --limit 12
|
|
1050
|
+
memoc grep "<query>" --snippets --limit 5
|
|
1045
1051
|
\`\`\`
|
|
1046
1052
|
|
|
1047
1053
|
If \`memoc\` is not on PATH, use \`.\\.memoc\\bin\\memoc.cmd <command>\` on Windows or \`.memoc/bin/memoc <command>\` in sh. If that is unavailable, use \`npx @kevin0181/memoc <command>\`.
|
|
@@ -1050,9 +1056,9 @@ If \`memoc\` is not on PATH, use \`.\\.memoc\\bin\\memoc.cmd <command>\` on Wind
|
|
|
1050
1056
|
|
|
1051
1057
|
1. Entry-file managed block.
|
|
1052
1058
|
2. \`.memoc/session-summary.md\` only.
|
|
1053
|
-
3. Search
|
|
1054
|
-
4.
|
|
1055
|
-
5.
|
|
1059
|
+
3. Search memory first: \`memoc search "<query>"\`.
|
|
1060
|
+
4. If memory is not enough, search project files: \`memoc grep "<query>" --limit 5\`.
|
|
1061
|
+
5. Use \`--snippets\` only when file names are not enough.
|
|
1056
1062
|
|
|
1057
1063
|
## When To Run Memory Updates
|
|
1058
1064
|
|
|
@@ -1146,7 +1152,7 @@ Use this local skill after meaningful project work so future agents can continue
|
|
|
1146
1152
|
## Required Reads
|
|
1147
1153
|
|
|
1148
1154
|
1. \`.memoc/session-summary.md\`
|
|
1149
|
-
2. \`memoc summary\` or \`memoc search "<query>"\`;
|
|
1155
|
+
2. \`memoc summary\` or \`memoc search "<query>"\`; use \`memoc grep "<query>"\` only when source/text search is needed
|
|
1150
1156
|
3. Open only files you will use or update.
|
|
1151
1157
|
|
|
1152
1158
|
## Maintenance Checklist
|
|
@@ -1470,9 +1476,9 @@ function runAdd(dir) {
|
|
|
1470
1476
|
// SEARCH
|
|
1471
1477
|
// ═══════════════════════════════════════════════════════════════════
|
|
1472
1478
|
|
|
1473
|
-
function runSearch(dir) {
|
|
1474
|
-
const rawArgs = process.argv.slice(3);
|
|
1475
|
-
const opts = { mode: 'files', limit: 12, all: false };
|
|
1479
|
+
function runSearch(dir, scope = 'memory') {
|
|
1480
|
+
const rawArgs = process.argv.slice(3);
|
|
1481
|
+
const opts = { mode: 'files', limit: 12, all: false };
|
|
1476
1482
|
const queryParts = [];
|
|
1477
1483
|
|
|
1478
1484
|
for (let i = 0; i < rawArgs.length; i++) {
|
|
@@ -1493,19 +1499,12 @@ function runSearch(dir) {
|
|
|
1493
1499
|
queryParts.push(arg);
|
|
1494
1500
|
}
|
|
1495
1501
|
|
|
1496
|
-
const query = queryParts.join(' ').toLowerCase();
|
|
1497
|
-
|
|
1498
|
-
const searchRoots = [
|
|
1499
|
-
path.join(dir, '.memoc'),
|
|
1500
|
-
path.join(dir, 'skills'),
|
|
1501
|
-
path.join(dir, 'llms.txt'),
|
|
1502
|
-
path.join(dir, 'AGENTS.md'),
|
|
1503
|
-
path.join(dir, 'CLAUDE.md'),
|
|
1504
|
-
...Object.values(AGENT_REGISTRY).map(agent => path.join(dir, agent.file)),
|
|
1505
|
-
];
|
|
1502
|
+
const query = queryParts.join(' ').toLowerCase();
|
|
1503
|
+
|
|
1504
|
+
const searchRoots = scope === 'project' ? [dir] : memorySearchRoots(dir);
|
|
1506
1505
|
|
|
1507
1506
|
if (!query) {
|
|
1508
|
-
// No query — list
|
|
1507
|
+
// No query — list searchable files sorted by recency
|
|
1509
1508
|
const allFiles = [];
|
|
1510
1509
|
function collectFile(fp) {
|
|
1511
1510
|
if (!fs.existsSync(fp)) return;
|
|
@@ -1519,8 +1518,10 @@ function runSearch(dir) {
|
|
|
1519
1518
|
for (const entry of fs.readdirSync(d)) {
|
|
1520
1519
|
const fp = path.join(d, entry);
|
|
1521
1520
|
try {
|
|
1522
|
-
|
|
1523
|
-
|
|
1521
|
+
const st = fs.statSync(fp);
|
|
1522
|
+
if (st.isDirectory()) {
|
|
1523
|
+
if (!shouldSkipSearchDir(entry)) collectDir(fp);
|
|
1524
|
+
} else if (isSearchableFile(fp, entry, st, scope)) collectFile(fp);
|
|
1524
1525
|
} catch {}
|
|
1525
1526
|
}
|
|
1526
1527
|
}
|
|
@@ -1541,11 +1542,15 @@ function runSearch(dir) {
|
|
|
1541
1542
|
|
|
1542
1543
|
const matchesByFile = new Map(); // rel -> { matches: [], mtime: number }
|
|
1543
1544
|
|
|
1544
|
-
function searchFile(fp) {
|
|
1545
|
-
if (!fs.existsSync(fp)) return;
|
|
1546
|
-
const rel = path.relative(dir, fp);
|
|
1547
|
-
let mtime = 0;
|
|
1548
|
-
try {
|
|
1545
|
+
function searchFile(fp) {
|
|
1546
|
+
if (!fs.existsSync(fp)) return;
|
|
1547
|
+
const rel = path.relative(dir, fp);
|
|
1548
|
+
let mtime = 0;
|
|
1549
|
+
try {
|
|
1550
|
+
const st = fs.statSync(fp);
|
|
1551
|
+
if (!isSearchableFile(fp, path.basename(fp), st, scope)) return;
|
|
1552
|
+
mtime = st.mtimeMs;
|
|
1553
|
+
} catch {}
|
|
1549
1554
|
const lines = fs.readFileSync(fp, 'utf8').split('\n');
|
|
1550
1555
|
lines.forEach((line, i) => {
|
|
1551
1556
|
if (line.toLowerCase().includes(query)) {
|
|
@@ -1560,8 +1565,10 @@ function runSearch(dir) {
|
|
|
1560
1565
|
for (const entry of fs.readdirSync(d)) {
|
|
1561
1566
|
const fp = path.join(d, entry);
|
|
1562
1567
|
try {
|
|
1563
|
-
|
|
1564
|
-
|
|
1568
|
+
const st = fs.statSync(fp);
|
|
1569
|
+
if (st.isDirectory()) {
|
|
1570
|
+
if (!shouldSkipSearchDir(entry)) walkDir(fp);
|
|
1571
|
+
} else if (isSearchableFile(fp, entry, st, scope)) searchFile(fp);
|
|
1565
1572
|
} catch {}
|
|
1566
1573
|
}
|
|
1567
1574
|
}
|
|
@@ -1595,7 +1602,44 @@ function runSearch(dir) {
|
|
|
1595
1602
|
console.log(`... ${snippets.length - limited.length} more matches. Use --all to show all, or --limit N.`);
|
|
1596
1603
|
}
|
|
1597
1604
|
}
|
|
1598
|
-
}
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
function memorySearchRoots(dir) {
|
|
1608
|
+
return [
|
|
1609
|
+
path.join(dir, '.memoc'),
|
|
1610
|
+
path.join(dir, 'skills'),
|
|
1611
|
+
path.join(dir, 'llms.txt'),
|
|
1612
|
+
path.join(dir, 'AGENTS.md'),
|
|
1613
|
+
path.join(dir, 'CLAUDE.md'),
|
|
1614
|
+
...Object.values(AGENT_REGISTRY).map(agent => path.join(dir, agent.file)),
|
|
1615
|
+
];
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
function shouldSkipSearchDir(name) {
|
|
1619
|
+
return new Set([
|
|
1620
|
+
'.git', 'node_modules', '.next', 'dist', 'build', 'out', 'coverage',
|
|
1621
|
+
'Saved', 'Intermediate', 'DerivedDataCache', 'Binaries',
|
|
1622
|
+
'.venv', 'venv', '__pycache__', '.pytest_cache',
|
|
1623
|
+
]).has(name);
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
function isSearchableFile(fp, name, st, scope = 'memory') {
|
|
1627
|
+
if (!st || !st.isFile()) return false;
|
|
1628
|
+
if (st.size > 1024 * 1024) return false;
|
|
1629
|
+
if (name === 'llms.txt' || name.endsWith('rules')) return true;
|
|
1630
|
+
const ext = path.extname(fp).toLowerCase();
|
|
1631
|
+
if (scope === 'memory') {
|
|
1632
|
+
return new Set(['.md', '.txt']).has(ext);
|
|
1633
|
+
}
|
|
1634
|
+
return new Set([
|
|
1635
|
+
'.md', '.txt', '.json', '.jsonc', '.yaml', '.yml', '.toml', '.ini', '.env',
|
|
1636
|
+
'.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs',
|
|
1637
|
+
'.py', '.rs', '.go', '.java', '.cs', '.cpp', '.cc', '.cxx', '.c', '.h', '.hpp', '.hxx',
|
|
1638
|
+
'.html', '.css', '.scss', '.sass', '.vue', '.svelte',
|
|
1639
|
+
'.sql', '.graphql', '.gql', '.sh', '.bash', '.zsh', '.ps1', '.bat', '.cmd',
|
|
1640
|
+
'.xml', '.gradle', '.kts', '.cmake',
|
|
1641
|
+
]).has(ext);
|
|
1642
|
+
}
|
|
1599
1643
|
|
|
1600
1644
|
// ═══════════════════════════════════════════════════════════════════
|
|
1601
1645
|
// TOKENS — estimate token cost of current memory state
|
|
@@ -1773,7 +1817,8 @@ if (!cmd || cmd === '--help' || cmd === '-h' || cmd === 'help') {
|
|
|
1773
1817
|
console.log(' tokens Estimate token cost of current memory files');
|
|
1774
1818
|
console.log(' compress Archive old log.md entries to keep file small');
|
|
1775
1819
|
console.log(' add <agent> Add entry file for a specific agent (run without args to list)');
|
|
1776
|
-
console.log(' search "<query>"
|
|
1820
|
+
console.log(' search "<query>" Search memory/agent docs (use --snippets for line matches)');
|
|
1821
|
+
console.log(' grep "<query>" Search project source/text files (use --snippets for line matches)');
|
|
1777
1822
|
console.log('\nSearch flags:');
|
|
1778
1823
|
console.log(' --files Show file names and match counts, sorted by relevance + recency (default)');
|
|
1779
1824
|
console.log(' --snippets Show matching lines');
|
|
@@ -1790,7 +1835,8 @@ if (cmd === 'summary') { runSummary(cwd); process.exit(0); }
|
|
|
1790
1835
|
if (cmd === 'tokens') { runTokens(cwd); process.exit(0); }
|
|
1791
1836
|
if (cmd === 'compress') { runCompress(cwd); process.exit(0); }
|
|
1792
1837
|
if (cmd === 'add') { runAdd(cwd); process.exit(0); }
|
|
1793
|
-
if (cmd === 'search') { runSearch(cwd);
|
|
1838
|
+
if (cmd === 'search') { runSearch(cwd, 'memory'); process.exit(0); }
|
|
1839
|
+
if (cmd === 'grep') { runSearch(cwd, 'project'); process.exit(0); }
|
|
1794
1840
|
|
|
1795
1841
|
console.error(`Unknown command: ${cmd}`);
|
|
1796
1842
|
console.error('Run "memoc --help" for usage.');
|