@bunkercache/opencode-memoir 0.2.3 → 0.3.1
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/dist/index.js +117 -63
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -161,12 +161,16 @@ function resolveStoragePaths(worktree, projectId, config) {
|
|
|
161
161
|
const relativePath = getGitignoreRelativePath(memoryDb.path, worktree);
|
|
162
162
|
if (relativePath) {
|
|
163
163
|
gitignorePaths.push(relativePath);
|
|
164
|
+
gitignorePaths.push(`${relativePath}-shm`);
|
|
165
|
+
gitignorePaths.push(`${relativePath}-wal`);
|
|
164
166
|
}
|
|
165
167
|
}
|
|
166
168
|
if (historyDb?.isLocal && historyDb.manageGitignore && !sharedDatabase) {
|
|
167
169
|
const relativePath = getGitignoreRelativePath(historyDb.path, worktree);
|
|
168
170
|
if (relativePath && !gitignorePaths.includes(relativePath)) {
|
|
169
171
|
gitignorePaths.push(relativePath);
|
|
172
|
+
gitignorePaths.push(`${relativePath}-shm`);
|
|
173
|
+
gitignorePaths.push(`${relativePath}-wal`);
|
|
170
174
|
}
|
|
171
175
|
}
|
|
172
176
|
return {
|
|
@@ -1616,6 +1620,37 @@ class ChunkService {
|
|
|
1616
1620
|
getRecentSummaryChunks(limit = 5) {
|
|
1617
1621
|
return this.repository.getRecentSummaryChunks(limit);
|
|
1618
1622
|
}
|
|
1623
|
+
getRecentChunks(options) {
|
|
1624
|
+
const limit = options?.limit ?? 10;
|
|
1625
|
+
let sql = `
|
|
1626
|
+
SELECT id, session_id, parent_id, depth, child_refs, content, summary,
|
|
1627
|
+
status, created_at, finalized_at, compacted_at, embedding
|
|
1628
|
+
FROM chunks
|
|
1629
|
+
`;
|
|
1630
|
+
const params = [];
|
|
1631
|
+
if (options?.sessionId) {
|
|
1632
|
+
sql += " WHERE session_id = ?";
|
|
1633
|
+
params.push(options.sessionId);
|
|
1634
|
+
}
|
|
1635
|
+
sql += " ORDER BY created_at DESC LIMIT ?";
|
|
1636
|
+
params.push(limit);
|
|
1637
|
+
const stmt = this.db.prepare(sql);
|
|
1638
|
+
const rows = stmt.all(...params);
|
|
1639
|
+
return rows.map((row) => ({
|
|
1640
|
+
id: row.id,
|
|
1641
|
+
sessionId: row.session_id,
|
|
1642
|
+
parentId: row.parent_id,
|
|
1643
|
+
depth: row.depth,
|
|
1644
|
+
childRefs: row.child_refs ? JSON.parse(row.child_refs) : null,
|
|
1645
|
+
content: JSON.parse(row.content),
|
|
1646
|
+
summary: row.summary,
|
|
1647
|
+
status: row.status,
|
|
1648
|
+
createdAt: row.created_at,
|
|
1649
|
+
finalizedAt: row.finalized_at,
|
|
1650
|
+
compactedAt: row.compacted_at,
|
|
1651
|
+
embedding: row.embedding
|
|
1652
|
+
}));
|
|
1653
|
+
}
|
|
1619
1654
|
}
|
|
1620
1655
|
var chunkService = null;
|
|
1621
1656
|
function initializeChunkService(db, config) {
|
|
@@ -1637,33 +1672,7 @@ var MEMORY_NUDGE_MESSAGE = `[MEMORY TRIGGER DETECTED]
|
|
|
1637
1672
|
The user wants you to remember something. Use the \`memoir\` tool with \`mode: "add"\` to save this information.
|
|
1638
1673
|
Extract the key information and save it as a concise, searchable memory.
|
|
1639
1674
|
Choose an appropriate type: "preference", "pattern", "gotcha", "fact", or "learned".`;
|
|
1640
|
-
function
|
|
1641
|
-
if (chunk.summary) {
|
|
1642
|
-
return chunk.summary;
|
|
1643
|
-
}
|
|
1644
|
-
const messageCount = chunk.content.messages.length;
|
|
1645
|
-
const files = chunk.content.metadata.files_modified?.length || 0;
|
|
1646
|
-
const tools = chunk.content.metadata.tools_used?.slice(0, 3).join(", ") || "none";
|
|
1647
|
-
return `${messageCount} messages, ${files} files modified, tools: ${tools}`;
|
|
1648
|
-
}
|
|
1649
|
-
function formatSessionHistory(chunks) {
|
|
1650
|
-
if (chunks.length === 0) {
|
|
1651
|
-
return "";
|
|
1652
|
-
}
|
|
1653
|
-
const lines = chunks.map((c) => {
|
|
1654
|
-
const date = new Date(c.createdAt * 1000).toLocaleDateString();
|
|
1655
|
-
return `- [${c.id}] (${date}): ${formatChunkSummary(c)}`;
|
|
1656
|
-
});
|
|
1657
|
-
return `
|
|
1658
|
-
## Recent Session History
|
|
1659
|
-
The following past work may be relevant:
|
|
1660
|
-
|
|
1661
|
-
${lines.join(`
|
|
1662
|
-
`)}
|
|
1663
|
-
|
|
1664
|
-
Use \`memoir_expand({ chunk_id: "ch_xxx" })\` to see full details of any chunk.`;
|
|
1665
|
-
}
|
|
1666
|
-
function formatContextInjection(memories, recentChunks) {
|
|
1675
|
+
function formatContextInjection(memories) {
|
|
1667
1676
|
const sections = [];
|
|
1668
1677
|
if (memories.length > 0) {
|
|
1669
1678
|
const memoryLines = memories.map((m) => `- [${m.type}] ${m.content}`);
|
|
@@ -1673,25 +1682,11 @@ The following memories are relevant to this conversation:
|
|
|
1673
1682
|
${memoryLines.join(`
|
|
1674
1683
|
`)}`);
|
|
1675
1684
|
}
|
|
1676
|
-
const historySection = formatSessionHistory(recentChunks);
|
|
1677
|
-
if (historySection) {
|
|
1678
|
-
sections.push(historySection);
|
|
1679
|
-
}
|
|
1680
1685
|
if (sections.length > 0) {
|
|
1681
1686
|
sections.push(`## Memoir Tools
|
|
1682
1687
|
- \`memoir\` - Add or search project memories
|
|
1683
|
-
- \`memoir_history\` -
|
|
1684
|
-
- \`memoir_expand\` - Expand a
|
|
1685
|
-
- Use \`preview_only: true\` to check size before full expansion
|
|
1686
|
-
|
|
1687
|
-
**Context Budget Tip**: Expanded chunks can be large (1000-10000+ tokens each).
|
|
1688
|
-
When exploring history or analyzing multiple chunks, consider delegating to a subagent:
|
|
1689
|
-
\`\`\`
|
|
1690
|
-
Task({
|
|
1691
|
-
prompt: "Use memoir_history and memoir_expand to find and analyze past work on [topic]",
|
|
1692
|
-
subagent_type: "explore"
|
|
1693
|
-
})
|
|
1694
|
-
\`\`\``);
|
|
1688
|
+
- \`memoir_history\` - Browse/search session history (current session by default, use all_sessions: true for past work)
|
|
1689
|
+
- \`memoir_expand\` - Expand a chunk ID to see full details`);
|
|
1695
1690
|
}
|
|
1696
1691
|
return sections.join(`
|
|
1697
1692
|
|
|
@@ -1722,13 +1717,8 @@ async function handleChatMessage(input, output) {
|
|
|
1722
1717
|
if (isFirstMessage) {
|
|
1723
1718
|
injectedSessions.add(sessionID);
|
|
1724
1719
|
const memories = memoryService2.searchRelevant(messageText);
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
const chunkService2 = getChunkService();
|
|
1728
|
-
recentChunks = chunkService2.getRecentSummaryChunks(5);
|
|
1729
|
-
} catch {}
|
|
1730
|
-
if (memories.length > 0 || recentChunks.length > 0) {
|
|
1731
|
-
const contextText = formatContextInjection(memories, recentChunks);
|
|
1720
|
+
if (memories.length > 0) {
|
|
1721
|
+
const contextText = formatContextInjection(memories);
|
|
1732
1722
|
const contextPart = createSyntheticPart(sessionID, messageID || "", contextText);
|
|
1733
1723
|
output.parts.unshift(contextPart);
|
|
1734
1724
|
}
|
|
@@ -14556,28 +14546,89 @@ function estimateTokens2(text) {
|
|
|
14556
14546
|
return Math.ceil(text.length / CHARS_PER_TOKEN2);
|
|
14557
14547
|
}
|
|
14558
14548
|
var historyTool = tool({
|
|
14559
|
-
description: `
|
|
14549
|
+
description: `Browse or search session history. Returns chunk summaries with IDs for memoir_expand.
|
|
14550
|
+
|
|
14551
|
+
DEFAULTS: Searches current session only. Returns recent chunks if no query provided.
|
|
14552
|
+
|
|
14553
|
+
OPTIONS:
|
|
14554
|
+
- query: Search text (omit to list recent chunks)
|
|
14555
|
+
- all_sessions: true to include past sessions
|
|
14556
|
+
- limit: Max results (default 10)
|
|
14560
14557
|
|
|
14561
|
-
|
|
14558
|
+
Use memoir_expand({ chunk_id }) to see full content of any chunk.`,
|
|
14562
14559
|
args: {
|
|
14563
|
-
query: tool.schema.string().describe("Search query
|
|
14564
|
-
|
|
14565
|
-
|
|
14566
|
-
|
|
14560
|
+
query: tool.schema.string().optional().describe("Search query (omit to list recent chunks without searching)"),
|
|
14561
|
+
all_sessions: tool.schema.boolean().optional().describe("Include past sessions (default: current session only)"),
|
|
14562
|
+
session_ids: tool.schema.array(tool.schema.string()).optional().describe("Search specific session IDs"),
|
|
14563
|
+
depth: tool.schema.number().optional().describe("Minimum chunk depth (0=original, 1+=summaries)"),
|
|
14564
|
+
limit: tool.schema.number().optional().describe("Max results (default: 10)")
|
|
14567
14565
|
},
|
|
14568
|
-
async execute(args) {
|
|
14566
|
+
async execute(args, context) {
|
|
14569
14567
|
const chunkService2 = getChunkService();
|
|
14570
|
-
|
|
14571
|
-
|
|
14568
|
+
let sessionId;
|
|
14569
|
+
let searchScope;
|
|
14570
|
+
if (args.session_ids && args.session_ids.length > 0) {
|
|
14571
|
+
sessionId = args.session_ids[0];
|
|
14572
|
+
searchScope = `sessions: ${args.session_ids.join(", ")}`;
|
|
14573
|
+
} else if (args.all_sessions) {
|
|
14574
|
+
sessionId = undefined;
|
|
14575
|
+
searchScope = "all sessions";
|
|
14576
|
+
} else {
|
|
14577
|
+
sessionId = context.sessionID;
|
|
14578
|
+
searchScope = "current session";
|
|
14579
|
+
}
|
|
14580
|
+
const limit = args.limit ?? 10;
|
|
14581
|
+
const query = args.query?.trim();
|
|
14582
|
+
if (!query) {
|
|
14583
|
+
const recentChunks = chunkService2.getRecentChunks({
|
|
14584
|
+
sessionId,
|
|
14585
|
+
limit
|
|
14586
|
+
});
|
|
14587
|
+
if (recentChunks.length === 0) {
|
|
14588
|
+
return JSON.stringify({
|
|
14589
|
+
success: true,
|
|
14590
|
+
count: 0,
|
|
14591
|
+
scope: searchScope,
|
|
14592
|
+
mode: "recent",
|
|
14593
|
+
message: `No chunks found in ${searchScope}`,
|
|
14594
|
+
hint: args.all_sessions ? undefined : "Try with all_sessions: true to see past sessions"
|
|
14595
|
+
});
|
|
14596
|
+
}
|
|
14597
|
+
const formatted2 = recentChunks.map((c) => ({
|
|
14598
|
+
id: c.id,
|
|
14599
|
+
sessionId: c.sessionId,
|
|
14600
|
+
depth: c.depth,
|
|
14601
|
+
status: c.status,
|
|
14602
|
+
summary: c.summary || `${c.content.messages.length} messages`,
|
|
14603
|
+
created: new Date(c.createdAt * 1000).toISOString(),
|
|
14604
|
+
stats: {
|
|
14605
|
+
messages: c.content.messages.length,
|
|
14606
|
+
files_modified: c.content.metadata.files_modified?.length || 0
|
|
14607
|
+
}
|
|
14608
|
+
}));
|
|
14609
|
+
return JSON.stringify({
|
|
14610
|
+
success: true,
|
|
14611
|
+
count: formatted2.length,
|
|
14612
|
+
scope: searchScope,
|
|
14613
|
+
mode: "recent",
|
|
14614
|
+
chunks: formatted2,
|
|
14615
|
+
hint: 'Use memoir_expand({ chunk_id: "ch_xxx" }) to see full content.'
|
|
14616
|
+
});
|
|
14617
|
+
}
|
|
14618
|
+
const results = chunkService2.search(query, {
|
|
14619
|
+
sessionId,
|
|
14572
14620
|
depth: args.depth,
|
|
14573
|
-
limit
|
|
14621
|
+
limit
|
|
14574
14622
|
});
|
|
14575
14623
|
if (results.length === 0) {
|
|
14576
14624
|
return JSON.stringify({
|
|
14577
14625
|
success: true,
|
|
14578
14626
|
count: 0,
|
|
14579
|
-
|
|
14580
|
-
|
|
14627
|
+
scope: searchScope,
|
|
14628
|
+
mode: "search",
|
|
14629
|
+
query,
|
|
14630
|
+
message: `No matches for "${query}" in ${searchScope}`,
|
|
14631
|
+
hint: args.all_sessions ? undefined : "Try with all_sessions: true to search past sessions"
|
|
14581
14632
|
});
|
|
14582
14633
|
}
|
|
14583
14634
|
const formatted = results.map((r) => {
|
|
@@ -14608,10 +14659,13 @@ CONTEXT BUDGET: Results are summaries (~50-200 tokens each). To view full chunk
|
|
|
14608
14659
|
const response = {
|
|
14609
14660
|
success: true,
|
|
14610
14661
|
count: results.length,
|
|
14662
|
+
scope: searchScope,
|
|
14663
|
+
mode: "search",
|
|
14664
|
+
query,
|
|
14611
14665
|
estimated_tokens: estimatedTokens,
|
|
14612
14666
|
estimated_expanded_tokens: estimatedExpandedTokens,
|
|
14613
14667
|
chunks: formatted,
|
|
14614
|
-
hint: 'Use memoir_expand({ chunk_id: "ch_xxx"
|
|
14668
|
+
hint: 'Use memoir_expand({ chunk_id: "ch_xxx" }) to see full content.'
|
|
14615
14669
|
};
|
|
14616
14670
|
if (estimatedExpandedTokens > LARGE_RESULT_TOKEN_THRESHOLD && results.length > 3) {
|
|
14617
14671
|
response.warning = `Expanding all ${results.length} results would use ~${estimatedExpandedTokens} tokens. Consider using memoir_expand with preview_only=true first, or delegate detailed analysis to a subagent.`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bunkercache/opencode-memoir",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "A smart memory management plugin for OpenCode that supports nested aggregation of memory, summaries, and file changes that compact in layers with upstream references for lookups.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Chris Tunbridge",
|