@csuwl/opencode-memory-plugin 1.0.0
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.npm.md +57 -0
- package/agents/memory-automation.md +121 -0
- package/agents/memory-consolidate.md +267 -0
- package/bin/install.js +354 -0
- package/index.js +47 -0
- package/memory/AGENTS.md +73 -0
- package/memory/BOOT.md +35 -0
- package/memory/BOOTSTRAP.md +105 -0
- package/memory/HEARTBEAT.md +26 -0
- package/memory/IDENTITY.md +28 -0
- package/memory/MEMORY.md +21 -0
- package/memory/SOUL.md +28 -0
- package/memory/TOOLS.md +91 -0
- package/memory/USER.md +37 -0
- package/package.json +45 -0
- package/scripts/docker-init.sh +154 -0
- package/scripts/init.sh +338 -0
- package/scripts/test-memory-functions.sh +131 -0
- package/tools/memory.ts +308 -0
- package/tools/vector-memory.ts +428 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
# Memory Tools Function Test
|
|
4
|
+
# Tests memory tools functionality directly without OpenCode
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
GREEN='\033[0;32m'
|
|
9
|
+
YELLOW='\033[1;33m'
|
|
10
|
+
BLUE='\033[0;34m'
|
|
11
|
+
RED='\033[0;31m'
|
|
12
|
+
NC='\033[0m'
|
|
13
|
+
|
|
14
|
+
echo -e "${BLUE}๐งช Memory Tools Function Test${NC}"
|
|
15
|
+
echo -e "${BLUE}=================================${NC}"
|
|
16
|
+
echo ""
|
|
17
|
+
|
|
18
|
+
# Test 1: File operations (simulating memory_write)
|
|
19
|
+
echo -e "${YELLOW}Test 1: Memory write simulation...${NC}"
|
|
20
|
+
MEMORY_DIR="/root/.opencode/memory"
|
|
21
|
+
TODAY=$(date +%Y-%m-%d)
|
|
22
|
+
DAILY_FILE="$MEMORY_DIR/daily/$TODAY.md"
|
|
23
|
+
|
|
24
|
+
if [ -f "$DAILY_FILE" ]; then
|
|
25
|
+
TEST_ENTRY="
|
|
26
|
+
## Test Entry - $(date +%Y-%m-%dT%H:%M:%S)
|
|
27
|
+
|
|
28
|
+
This is a test memory entry that simulates what would be saved by memory_write tool.
|
|
29
|
+
|
|
30
|
+
- Test timestamp: $(date)
|
|
31
|
+
- Test content: Important information to remember
|
|
32
|
+
"
|
|
33
|
+
|
|
34
|
+
echo "$TEST_ENTRY" >> "$DAILY_FILE"
|
|
35
|
+
echo -e " ${GREEN}โ${NC} Memory write simulation successful"
|
|
36
|
+
else
|
|
37
|
+
echo -e " ${RED}โ${NC} Daily log not found"
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
echo ""
|
|
41
|
+
|
|
42
|
+
# Test 2: File read (simulating memory_read)
|
|
43
|
+
echo -e "${YELLOW}Test 2: Memory read simulation...${NC}"
|
|
44
|
+
if [ -f "$MEMORY_DIR/SOUL.md" ]; then
|
|
45
|
+
SOUL_CONTENT=$(head -5 "$MEMORY_DIR/SOUL.md")
|
|
46
|
+
echo -e " ${GREEN}โ${NC} Read SOUL.md (first 5 lines):"
|
|
47
|
+
echo "$SOUL_CONTENT" | sed 's/^/ /'
|
|
48
|
+
else
|
|
49
|
+
echo -e " ${RED}โ${NC} SOUL.md not found"
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
echo ""
|
|
53
|
+
|
|
54
|
+
# Test 3: Keyword search (simulating memory_search)
|
|
55
|
+
echo -e "${YELLOW}Test 3: Keyword search simulation...${NC}"
|
|
56
|
+
if grep -q "Assistant" "$MEMORY_DIR/SOUL.md" 2>/dev/null; then
|
|
57
|
+
echo -e " ${GREEN}โ${NC} Found 'Assistant' in SOUL.md"
|
|
58
|
+
else
|
|
59
|
+
echo -e " ${RED}โ${NC} 'Assistant' not found in SOUL.md"
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
if grep -q "memory" "$MEMORY_DIR/AGENTS.md" 2>/dev/null; then
|
|
63
|
+
echo -e " ${GREEN}โ${NC} Found 'memory' in AGENTS.md"
|
|
64
|
+
else
|
|
65
|
+
echo -e " ${RED}โ${NC} 'memory' not found in AGENTS.md"
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
echo ""
|
|
69
|
+
|
|
70
|
+
# Test 4: Daily log list (simulating list_daily)
|
|
71
|
+
echo -e "${YELLOW}Test 4: Daily log list simulation...${NC}"
|
|
72
|
+
DAILY_COUNT=$(ls -1 "$MEMORY_DIR/daily" 2>/dev/null | wc -l)
|
|
73
|
+
echo -e " ${GREEN}โ${NC} Found $DAILY_COUNT daily log file(s):"
|
|
74
|
+
ls -1 "$MEMORY_DIR/daily" 2>/dev/null | sed 's/^/ - /'
|
|
75
|
+
|
|
76
|
+
echo ""
|
|
77
|
+
|
|
78
|
+
# Test 5: Archive simulation
|
|
79
|
+
echo -e "${YELLOW}Test 5: Archive simulation...${NC}"
|
|
80
|
+
ARCHIVE_DIR="$MEMORY_DIR/archive/weekly"
|
|
81
|
+
if [ -d "$ARCHIVE_DIR" ]; then
|
|
82
|
+
echo -e " ${GREEN}โ${NC} Archive directory exists"
|
|
83
|
+
ARCHIVE_COUNT=$(ls -1 "$ARCHIVE_DIR" 2>/dev/null | wc -l)
|
|
84
|
+
echo -e " Empty (as expected): $ARCHIVE_COUNT files"
|
|
85
|
+
else
|
|
86
|
+
echo -e " ${RED}โ${NC} Archive directory not found"
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
echo ""
|
|
90
|
+
|
|
91
|
+
# Test 6: Configuration check
|
|
92
|
+
echo -e "${YELLOW}Test 6: Memory configuration...${NC}"
|
|
93
|
+
CONFIG_FILE="$MEMORY_DIR/memory-config.json"
|
|
94
|
+
if [ -f "$CONFIG_FILE" ]; then
|
|
95
|
+
echo -e " ${GREEN}โ${NC} Configuration file exists"
|
|
96
|
+
|
|
97
|
+
# Check key settings
|
|
98
|
+
if grep -q '"version"' "$CONFIG_FILE"; then
|
|
99
|
+
echo -e " ${GREEN}โ${NC} Has version"
|
|
100
|
+
fi
|
|
101
|
+
if grep -q '"vector_search"' "$CONFIG_FILE"; then
|
|
102
|
+
echo -e " ${GREEN}โ${NC} Has vector_search config"
|
|
103
|
+
fi
|
|
104
|
+
if grep -q '"consolidation"' "$CONFIG_FILE"; then
|
|
105
|
+
echo -e " ${GREEN}โ${NC} Has consolidation config"
|
|
106
|
+
fi
|
|
107
|
+
else
|
|
108
|
+
echo -e " ${RED}โ${NC} Configuration file not found"
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
echo ""
|
|
112
|
+
|
|
113
|
+
# Summary
|
|
114
|
+
echo -e "${BLUE}=================================${NC}"
|
|
115
|
+
echo -e "${GREEN}โ Memory tools function test complete${NC}"
|
|
116
|
+
echo -e "${BLUE}=================================${NC}"
|
|
117
|
+
echo ""
|
|
118
|
+
echo -e "${YELLOW}Results:${NC}"
|
|
119
|
+
echo -e " โ
File operations work (write/read)"
|
|
120
|
+
echo -e " โ
Keyword search works"
|
|
121
|
+
echo -e " โ
Daily log management works"
|
|
122
|
+
echo -e " โ
Archive system ready"
|
|
123
|
+
echo -e " โ
Configuration valid"
|
|
124
|
+
echo ""
|
|
125
|
+
echo -e "${YELLOW}System Status:${NC}"
|
|
126
|
+
echo -e " Memory files: $(ls -1 $MEMORY_DIR | wc -l | tr -d ' ')"
|
|
127
|
+
echo -e " Daily logs: $DAILY_COUNT"
|
|
128
|
+
echo -e " Archive dirs: $(ls -1 $MEMORY_DIR/archive 2>/dev/null | wc -l | tr -d ' ')"
|
|
129
|
+
echo ""
|
|
130
|
+
echo -e "${GREEN}๐ Memory system is functional!${NC}"
|
|
131
|
+
echo ""
|
package/tools/memory.ts
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { tool } from "@opencode-ai/plugin"
|
|
2
|
+
import path from "path"
|
|
3
|
+
import { readFile, writeFile, mkdir, readdir, stat, exists } from "fs/promises"
|
|
4
|
+
|
|
5
|
+
const MEMORY_DIR = path.join(process.env.HOME || "", ".opencode", "memory")
|
|
6
|
+
const DAILY_DIR = path.join(MEMORY_DIR, "daily")
|
|
7
|
+
|
|
8
|
+
// Helper: Ensure memory directory structure exists
|
|
9
|
+
async function ensureMemoryDirs() {
|
|
10
|
+
await mkdir(MEMORY_DIR, { recursive: true })
|
|
11
|
+
await mkdir(DAILY_DIR, { recursive: true })
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Helper: Get today's date string
|
|
15
|
+
function getTodayDate() {
|
|
16
|
+
return new Date().toISOString().split('T')[0]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Helper: Format timestamp for memory entries
|
|
20
|
+
function formatTimestamp() {
|
|
21
|
+
return new Date().toISOString()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Helper: Get file path by memory type
|
|
25
|
+
function getMemoryFilePath(type: string, date?: string): string {
|
|
26
|
+
switch (type) {
|
|
27
|
+
case "long-term":
|
|
28
|
+
return path.join(MEMORY_DIR, "MEMORY.md")
|
|
29
|
+
case "preference":
|
|
30
|
+
return path.join(MEMORY_DIR, "PREFERENCES.md")
|
|
31
|
+
case "personality":
|
|
32
|
+
return path.join(MEMORY_DIR, "SOUL.md")
|
|
33
|
+
case "context":
|
|
34
|
+
return path.join(MEMORY_DIR, "CONTEXT.md")
|
|
35
|
+
case "tools":
|
|
36
|
+
return path.join(MEMORY_DIR, "TOOLS.md")
|
|
37
|
+
case "identity":
|
|
38
|
+
return path.join(MEMORY_DIR, "IDENTITY.md")
|
|
39
|
+
case "user":
|
|
40
|
+
return path.join(MEMORY_DIR, "USER.md")
|
|
41
|
+
case "daily":
|
|
42
|
+
const dateStr = date || getTodayDate()
|
|
43
|
+
return path.join(DAILY_DIR, `${dateStr}.md`)
|
|
44
|
+
default:
|
|
45
|
+
throw new Error(`Unknown memory type: ${type}`)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Tool 1: Write memory
|
|
50
|
+
export const write = tool({
|
|
51
|
+
description: "Write a memory entry to the memory system. Use this to store important information that should be remembered across sessions and projects. Types: long-term (MEMORY.md), daily (today's log), preference (PREFERENCES.md), personality (SOUL.md), context (CONTEXT.md), tools (TOOLS.md), identity (IDENTITY.md), user (USER.md).",
|
|
52
|
+
args: {
|
|
53
|
+
content: tool.schema.string().describe("The memory content to write. Include as much context as possible."),
|
|
54
|
+
type: tool.schema.enum(["long-term", "daily", "preference", "personality", "context", "tools", "identity", "user"]).describe("Type of memory to write to"),
|
|
55
|
+
tags: tool.schema.array(tool.schema.string()).optional().describe("Optional tags for categorization (e.g., ['code-style', 'project-xyz'])"),
|
|
56
|
+
},
|
|
57
|
+
async execute(args) {
|
|
58
|
+
await ensureMemoryDirs()
|
|
59
|
+
|
|
60
|
+
const filePath = getMemoryFilePath(args.type)
|
|
61
|
+
const timestamp = formatTimestamp()
|
|
62
|
+
let entry = ""
|
|
63
|
+
|
|
64
|
+
// Format entry with metadata
|
|
65
|
+
if (args.tags && args.tags.length > 0) {
|
|
66
|
+
entry += `\n\n## ${timestamp} ${args.tags.map((t) => `#${t}`).join(' ')}\n`
|
|
67
|
+
} else {
|
|
68
|
+
entry += `\n\n## ${timestamp}\n`
|
|
69
|
+
}
|
|
70
|
+
entry += `${args.content}\n`
|
|
71
|
+
|
|
72
|
+
// Append to file
|
|
73
|
+
try {
|
|
74
|
+
if (await exists(filePath)) {
|
|
75
|
+
await writeFile(filePath, entry, { flag: "a" })
|
|
76
|
+
} else {
|
|
77
|
+
await writeFile(filePath, entry)
|
|
78
|
+
}
|
|
79
|
+
return `โ Memory saved to ${path.basename(filePath)}`
|
|
80
|
+
} catch (error) {
|
|
81
|
+
return `โ Failed to write memory: ${(error as Error).message}`
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
// Tool 2: Read memory
|
|
87
|
+
export const read = tool({
|
|
88
|
+
description: "Read memory from the memory system. Use this to retrieve stored preferences, long-term memory, daily logs, or configuration files.",
|
|
89
|
+
args: {
|
|
90
|
+
type: tool.schema.enum(["long-term", "daily", "preference", "personality", "context", "tools", "identity", "user"]).describe("Type of memory to read"),
|
|
91
|
+
date: tool.schema.string().optional().describe("Specific date for daily memory (YYYY-MM-DD format). Defaults to today."),
|
|
92
|
+
lines: tool.schema.number().optional().describe("Number of lines to return. Defaults to all lines."),
|
|
93
|
+
},
|
|
94
|
+
async execute(args) {
|
|
95
|
+
await ensureMemoryDirs()
|
|
96
|
+
|
|
97
|
+
const filePath = getMemoryFilePath(args.type, args.date)
|
|
98
|
+
const limit = args.lines
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
let content = await readFile(filePath, "utf-8")
|
|
102
|
+
|
|
103
|
+
// Truncate if limit specified
|
|
104
|
+
if (limit && content.split('\n').length > limit) {
|
|
105
|
+
const lines = content.split('\n')
|
|
106
|
+
content = lines.slice(-limit).join('\n')
|
|
107
|
+
content += `\n\n[... Showed last ${limit} lines. Use read without limit to see full content.]\n`
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return content
|
|
111
|
+
} catch (error) {
|
|
112
|
+
return `Memory file not found: ${path.basename(filePath)}. You can create it using the write tool.`
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
// Tool 3: Search memory (keyword-based)
|
|
118
|
+
export const search = tool({
|
|
119
|
+
description: "Search memory files for relevant information using keywords and simple pattern matching. Returns matching entries with file paths and line numbers. For semantic search, use vector_memory_search.",
|
|
120
|
+
args: {
|
|
121
|
+
query: tool.schema.string().describe("Search query - use keywords to find relevant memories. Multiple keywords can be separated by spaces."),
|
|
122
|
+
scope: tool.schema.enum(["all", "long-term", "daily", "preference", "personality", "context", "tools", "identity", "user"]).describe("Search scope: all memory files or specific type"),
|
|
123
|
+
days: tool.schema.number().optional().describe("Number of recent daily files to search. Defaults to 7 (last 7 days)."),
|
|
124
|
+
limit: tool.schema.number().optional().describe("Maximum number of results per file to return. Defaults to 5."),
|
|
125
|
+
},
|
|
126
|
+
async execute(args) {
|
|
127
|
+
await ensureMemoryDirs()
|
|
128
|
+
|
|
129
|
+
const filesToSearch: string[] = []
|
|
130
|
+
const keywords = args.query.toLowerCase().split(/\s+/).filter(kw => kw.length > 0)
|
|
131
|
+
|
|
132
|
+
if (keywords.length === 0) {
|
|
133
|
+
return "Please provide at least one keyword to search for."
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Determine files to search
|
|
137
|
+
if (args.scope === "all" || args.scope === "long-term") {
|
|
138
|
+
filesToSearch.push(getMemoryFilePath("long-term"))
|
|
139
|
+
}
|
|
140
|
+
if (args.scope === "all" || args.scope === "preference") {
|
|
141
|
+
filesToSearch.push(getMemoryFilePath("preference"))
|
|
142
|
+
}
|
|
143
|
+
if (args.scope === "all" || args.scope === "personality") {
|
|
144
|
+
filesToSearch.push(getMemoryFilePath("personality"))
|
|
145
|
+
}
|
|
146
|
+
if (args.scope === "all" || args.scope === "context") {
|
|
147
|
+
filesToSearch.push(getMemoryFilePath("context"))
|
|
148
|
+
}
|
|
149
|
+
if (args.scope === "all" || args.scope === "tools") {
|
|
150
|
+
filesToSearch.push(getMemoryFilePath("tools"))
|
|
151
|
+
}
|
|
152
|
+
if (args.scope === "all" || args.scope === "identity") {
|
|
153
|
+
filesToSearch.push(getMemoryFilePath("identity"))
|
|
154
|
+
}
|
|
155
|
+
if (args.scope === "all" || args.scope === "user") {
|
|
156
|
+
filesToSearch.push(getMemoryFilePath("user"))
|
|
157
|
+
}
|
|
158
|
+
if (args.scope === "all" || args.scope === "daily") {
|
|
159
|
+
const daysToSearch = args.days || 7
|
|
160
|
+
for (let i = 0; i < daysToSearch; i++) {
|
|
161
|
+
const date = new Date()
|
|
162
|
+
date.setDate(date.getDate() - i)
|
|
163
|
+
const dateStr = date.toISOString().split('T')[0]
|
|
164
|
+
filesToSearch.push(getMemoryFilePath("daily", dateStr))
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const results: { file: string; matches: string[]; count: number }[] = []
|
|
169
|
+
|
|
170
|
+
// Search each file
|
|
171
|
+
for (const filePath of filesToSearch) {
|
|
172
|
+
try {
|
|
173
|
+
const content = await readFile(filePath, "utf-8")
|
|
174
|
+
const lines = content.split('\n')
|
|
175
|
+
const matches: string[] = []
|
|
176
|
+
|
|
177
|
+
for (let i = 0; i < lines.length; i++) {
|
|
178
|
+
const line = lines[i].toLowerCase()
|
|
179
|
+
const matchedKeywords = keywords.filter(kw => line.includes(kw))
|
|
180
|
+
|
|
181
|
+
// Only count as match if at least one keyword matches
|
|
182
|
+
if (matchedKeywords.length > 0) {
|
|
183
|
+
// Get context (2 lines before and after)
|
|
184
|
+
const start = Math.max(0, i - 2)
|
|
185
|
+
const end = Math.min(lines.length, i + 3)
|
|
186
|
+
const context = lines.slice(start, end).join('\n')
|
|
187
|
+
|
|
188
|
+
// Add match with line number
|
|
189
|
+
matches.push(`Line ${i + 1}: ${context.trim()}`)
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (matches.length > 0) {
|
|
194
|
+
results.push({
|
|
195
|
+
file: path.basename(filePath),
|
|
196
|
+
matches: matches.slice(0, args.limit || 5),
|
|
197
|
+
count: matches.length,
|
|
198
|
+
})
|
|
199
|
+
}
|
|
200
|
+
} catch {
|
|
201
|
+
// File doesn't exist, skip
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (results.length === 0) {
|
|
206
|
+
return `No matches found for: "${args.query}"\n\nSearched ${filesToSearch.length} file(s). Try different keywords or a broader scope.`
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Format output
|
|
210
|
+
let output = `Found ${results.length} file(s) with matches:\n\n`
|
|
211
|
+
for (const result of results) {
|
|
212
|
+
output += `### ${result.file} (${result.count} match(es))\n`
|
|
213
|
+
output += result.matches.join('\n') + '\n\n'
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return output.trim()
|
|
217
|
+
},
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
// Tool 4: List daily logs
|
|
221
|
+
export const list_daily = tool({
|
|
222
|
+
description: "List available daily memory log files. Useful for finding recent activity and managing daily memory.",
|
|
223
|
+
args: {
|
|
224
|
+
days: tool.schema.number().optional().describe("Number of recent days to list. Defaults to 30 (last 30 days)."),
|
|
225
|
+
},
|
|
226
|
+
async execute(args) {
|
|
227
|
+
await ensureMemoryDirs()
|
|
228
|
+
|
|
229
|
+
const daysToList = args.days || 30
|
|
230
|
+
const dailyFiles: { date: string; size: number; exists: boolean }[] = []
|
|
231
|
+
|
|
232
|
+
for (let i = 0; i < daysToList; i++) {
|
|
233
|
+
const date = new Date()
|
|
234
|
+
date.setDate(date.getDate() - i)
|
|
235
|
+
const dateStr = date.toISOString().split('T')[0]
|
|
236
|
+
const filePath = getMemoryFilePath("daily", dateStr)
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
const stats = await stat(filePath)
|
|
240
|
+
dailyFiles.push({
|
|
241
|
+
date: dateStr,
|
|
242
|
+
size: stats.size,
|
|
243
|
+
exists: true,
|
|
244
|
+
})
|
|
245
|
+
} catch {
|
|
246
|
+
dailyFiles.push({
|
|
247
|
+
date: dateStr,
|
|
248
|
+
size: 0,
|
|
249
|
+
exists: false,
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Format output
|
|
255
|
+
const existingFiles = dailyFiles.filter((f) => f.exists)
|
|
256
|
+
if (existingFiles.length === 0) {
|
|
257
|
+
return "No daily memory files found yet. Start by writing to daily memory!"
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
let output = `Daily Memory Files (last ${daysToList} days):\n\n`
|
|
261
|
+
for (const file of existingFiles) {
|
|
262
|
+
const sizeKB = (file.size / 1024).toFixed(2)
|
|
263
|
+
output += `๐ ${file.date} (${sizeKB} KB)\n`
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
output += `\nTotal: ${existingFiles.length} file(s)`
|
|
267
|
+
return output
|
|
268
|
+
},
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
// Tool 5: Initialize daily log
|
|
272
|
+
export const init_daily = tool({
|
|
273
|
+
description: "Initialize today's daily memory log file. Automatically called at start of sessions. Creates a new daily file with header if it doesn't exist.",
|
|
274
|
+
args: {},
|
|
275
|
+
async execute() {
|
|
276
|
+
await ensureMemoryDirs()
|
|
277
|
+
|
|
278
|
+
const today = getTodayDate()
|
|
279
|
+
const filePath = getMemoryFilePath("daily", today)
|
|
280
|
+
|
|
281
|
+
try {
|
|
282
|
+
if (!(await exists(filePath))) {
|
|
283
|
+
const header = `# Daily Memory Log - ${today}\n\n`
|
|
284
|
+
header += `*Session starts: ${formatTimestamp()}*\n\n`
|
|
285
|
+
header += `## Notes\n\n\n`
|
|
286
|
+
header += `## Tasks\n\n\n`
|
|
287
|
+
header += `## Learnings\n\n`
|
|
288
|
+
header += `---\n`
|
|
289
|
+
|
|
290
|
+
await writeFile(filePath, header)
|
|
291
|
+
return `โ Created daily memory file: ${today}.md`
|
|
292
|
+
} else {
|
|
293
|
+
return `โ Daily memory file already exists: ${today}.md`
|
|
294
|
+
}
|
|
295
|
+
} catch (error) {
|
|
296
|
+
return `โ Failed to initialize daily log: ${(error as Error).message}`
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
// Export default tool for backward compatibility
|
|
302
|
+
export default {
|
|
303
|
+
write,
|
|
304
|
+
read,
|
|
305
|
+
search,
|
|
306
|
+
list_daily,
|
|
307
|
+
init_daily,
|
|
308
|
+
}
|