studiograph 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.md +18 -0
- package/dist/agent/orchestrator.d.ts +69 -0
- package/dist/agent/orchestrator.js +211 -0
- package/dist/agent/orchestrator.js.map +1 -0
- package/dist/agent/tools/graph-tools.d.ts +30 -0
- package/dist/agent/tools/graph-tools.js +536 -0
- package/dist/agent/tools/graph-tools.js.map +1 -0
- package/dist/auth/github.d.ts +53 -0
- package/dist/auth/github.js +180 -0
- package/dist/auth/github.js.map +1 -0
- package/dist/cli/commands/auth.d.ts +10 -0
- package/dist/cli/commands/auth.js +63 -0
- package/dist/cli/commands/auth.js.map +1 -0
- package/dist/cli/commands/init.d.ts +7 -0
- package/dist/cli/commands/init.js +299 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/join.d.ts +14 -0
- package/dist/cli/commands/join.js +230 -0
- package/dist/cli/commands/join.js.map +1 -0
- package/dist/cli/commands/members.d.ts +11 -0
- package/dist/cli/commands/members.js +230 -0
- package/dist/cli/commands/members.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +17 -0
- package/dist/cli/commands/serve.js +90 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/start.d.ts +7 -0
- package/dist/cli/commands/start.js +381 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/commands/sync.d.ts +10 -0
- package/dist/cli/commands/sync.js +121 -0
- package/dist/cli/commands/sync.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.js +31 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/graph.d.ts +169 -0
- package/dist/core/graph.js +558 -0
- package/dist/core/graph.js.map +1 -0
- package/dist/core/types.d.ts +216 -0
- package/dist/core/types.js +71 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/user-config.d.ts +31 -0
- package/dist/core/user-config.js +50 -0
- package/dist/core/user-config.js.map +1 -0
- package/dist/core/validation.d.ts +2371 -0
- package/dist/core/validation.js +432 -0
- package/dist/core/validation.js.map +1 -0
- package/dist/core/workspace-manager.d.ts +104 -0
- package/dist/core/workspace-manager.js +432 -0
- package/dist/core/workspace-manager.js.map +1 -0
- package/dist/core/workspace.d.ts +103 -0
- package/dist/core/workspace.js +306 -0
- package/dist/core/workspace.js.map +1 -0
- package/dist/server/index.d.ts +25 -0
- package/dist/server/index.js +84 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/plugin-loader.d.ts +31 -0
- package/dist/server/plugin-loader.js +81 -0
- package/dist/server/plugin-loader.js.map +1 -0
- package/dist/server/routes/chat.d.ts +11 -0
- package/dist/server/routes/chat.js +66 -0
- package/dist/server/routes/chat.js.map +1 -0
- package/dist/server/routes/graph-api.d.ts +9 -0
- package/dist/server/routes/graph-api.js +72 -0
- package/dist/server/routes/graph-api.js.map +1 -0
- package/dist/server/routes/webhook.d.ts +14 -0
- package/dist/server/routes/webhook.js +69 -0
- package/dist/server/routes/webhook.js.map +1 -0
- package/dist/services/assets/base.d.ts +69 -0
- package/dist/services/assets/base.js +113 -0
- package/dist/services/assets/base.js.map +1 -0
- package/dist/services/assets/index.d.ts +36 -0
- package/dist/services/assets/index.js +89 -0
- package/dist/services/assets/index.js.map +1 -0
- package/dist/services/assets/local.d.ts +42 -0
- package/dist/services/assets/local.js +161 -0
- package/dist/services/assets/local.js.map +1 -0
- package/dist/services/assets/r2.d.ts +36 -0
- package/dist/services/assets/r2.js +182 -0
- package/dist/services/assets/r2.js.map +1 -0
- package/dist/services/csv-service.d.ts +36 -0
- package/dist/services/csv-service.js +143 -0
- package/dist/services/csv-service.js.map +1 -0
- package/dist/services/git.d.ts +99 -0
- package/dist/services/git.js +306 -0
- package/dist/services/git.js.map +1 -0
- package/dist/services/github-provisioner.d.ts +30 -0
- package/dist/services/github-provisioner.js +89 -0
- package/dist/services/github-provisioner.js.map +1 -0
- package/dist/services/markdown.d.ts +82 -0
- package/dist/services/markdown.js +338 -0
- package/dist/services/markdown.js.map +1 -0
- package/dist/services/memory-service.d.ts +74 -0
- package/dist/services/memory-service.js +183 -0
- package/dist/services/memory-service.js.map +1 -0
- package/dist/utils/git.d.ts +28 -0
- package/dist/utils/git.js +55 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/preflight.d.ts +44 -0
- package/dist/utils/preflight.js +95 -0
- package/dist/utils/preflight.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown service for Studiograph
|
|
3
|
+
*
|
|
4
|
+
* Handles parsing and writing markdown files with YAML frontmatter,
|
|
5
|
+
* extracting wikilinks, and validating relationships.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
|
|
8
|
+
import { dirname, join } from 'path';
|
|
9
|
+
import matter from 'gray-matter';
|
|
10
|
+
import { glob } from 'glob';
|
|
11
|
+
export class MarkdownService {
|
|
12
|
+
/**
|
|
13
|
+
* Parse markdown file from path
|
|
14
|
+
*/
|
|
15
|
+
parseFile(filePath) {
|
|
16
|
+
if (!existsSync(filePath)) {
|
|
17
|
+
throw new Error(`File not found: ${filePath}`);
|
|
18
|
+
}
|
|
19
|
+
const fileContent = readFileSync(filePath, 'utf-8');
|
|
20
|
+
return this.parseContent(fileContent);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Parse markdown content string
|
|
24
|
+
*/
|
|
25
|
+
parseContent(content) {
|
|
26
|
+
const { data, content: markdownContent } = matter(content);
|
|
27
|
+
// Extract wikilinks from content
|
|
28
|
+
const wikilinks = this.extractWikilinks(markdownContent, data);
|
|
29
|
+
return {
|
|
30
|
+
frontmatter: data,
|
|
31
|
+
content: markdownContent,
|
|
32
|
+
wikilinks: [...new Set(wikilinks)], // Dedupe
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Extract wikilinks from markdown content and frontmatter
|
|
37
|
+
*/
|
|
38
|
+
extractWikilinks(content, frontmatter) {
|
|
39
|
+
const wikilinks = [];
|
|
40
|
+
// Extract from content: [[entity-id]] or [[entity-id|Display Name]]
|
|
41
|
+
const wikilinkRegex = /\[\[([^\]|]+)(?:\|[^\]]+)?\]\]/g;
|
|
42
|
+
let match;
|
|
43
|
+
while ((match = wikilinkRegex.exec(content)) !== null) {
|
|
44
|
+
wikilinks.push(match[1]);
|
|
45
|
+
}
|
|
46
|
+
// Extract from frontmatter (check string values and arrays)
|
|
47
|
+
this.extractWikilinksFromObject(frontmatter, wikilinks);
|
|
48
|
+
return wikilinks;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Recursively extract wikilinks from object (frontmatter)
|
|
52
|
+
*/
|
|
53
|
+
extractWikilinksFromObject(obj, wikilinks) {
|
|
54
|
+
if (!obj || typeof obj !== 'object') {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (Array.isArray(obj)) {
|
|
58
|
+
obj.forEach(item => {
|
|
59
|
+
if (typeof item === 'string') {
|
|
60
|
+
const match = item.match(/\[\[([^\]|]+)(?:\|[^\]]+)?\]\]/);
|
|
61
|
+
if (match) {
|
|
62
|
+
wikilinks.push(match[1]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
this.extractWikilinksFromObject(item, wikilinks);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
Object.values(obj).forEach(value => {
|
|
72
|
+
if (typeof value === 'string') {
|
|
73
|
+
const match = value.match(/\[\[([^\]|]+)(?:\|[^\]]+)?\]\]/);
|
|
74
|
+
if (match) {
|
|
75
|
+
wikilinks.push(match[1]);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
this.extractWikilinksFromObject(value, wikilinks);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Write markdown file with frontmatter
|
|
86
|
+
*/
|
|
87
|
+
writeFile(filePath, doc) {
|
|
88
|
+
const { frontmatter, content } = doc;
|
|
89
|
+
// Generate markdown with frontmatter
|
|
90
|
+
const output = matter.stringify(content, frontmatter);
|
|
91
|
+
// Ensure directory exists
|
|
92
|
+
const dir = dirname(filePath);
|
|
93
|
+
if (!existsSync(dir)) {
|
|
94
|
+
mkdirSync(dir, { recursive: true });
|
|
95
|
+
}
|
|
96
|
+
// Write file
|
|
97
|
+
writeFileSync(filePath, output, 'utf-8');
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Write markdown content from separate frontmatter and content
|
|
101
|
+
*/
|
|
102
|
+
write(filePath, frontmatter, content) {
|
|
103
|
+
this.writeFile(filePath, { frontmatter, content, wikilinks: [] });
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Validate wikilinks against a repo or set of repos
|
|
107
|
+
*/
|
|
108
|
+
validateWikilinks(wikilinks, searchPaths) {
|
|
109
|
+
const valid = [];
|
|
110
|
+
const broken = [];
|
|
111
|
+
for (const link of wikilinks) {
|
|
112
|
+
// Try to find the entity file
|
|
113
|
+
const found = this.findEntity(link, searchPaths);
|
|
114
|
+
if (found) {
|
|
115
|
+
valid.push(link);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
broken.push(link);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return { valid, broken };
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Find entity file by entity ID across multiple search paths
|
|
125
|
+
*/
|
|
126
|
+
findEntity(entityId, searchPaths) {
|
|
127
|
+
// Clean entity ID (remove repo prefix if present)
|
|
128
|
+
// Format: [[repo/entity-id]] or [[entity-id]]
|
|
129
|
+
const parts = entityId.split('/');
|
|
130
|
+
const cleanId = parts.length === 2 ? parts[1] : parts[0];
|
|
131
|
+
// Search for {entityId}.md in all search paths
|
|
132
|
+
for (const searchPath of searchPaths) {
|
|
133
|
+
if (!existsSync(searchPath)) {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
// Try direct match first (faster)
|
|
137
|
+
const directPath = join(searchPath, `${cleanId}.md`);
|
|
138
|
+
if (existsSync(directPath)) {
|
|
139
|
+
return directPath;
|
|
140
|
+
}
|
|
141
|
+
// Search recursively
|
|
142
|
+
const pattern = `**/${cleanId}.md`;
|
|
143
|
+
const files = glob.sync(pattern, {
|
|
144
|
+
cwd: searchPath,
|
|
145
|
+
absolute: true,
|
|
146
|
+
nodir: true,
|
|
147
|
+
});
|
|
148
|
+
if (files.length > 0) {
|
|
149
|
+
return files[0]; // Return first match
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Find all entities of a given type in a directory
|
|
156
|
+
*/
|
|
157
|
+
findEntitiesByType(searchPath, entityType) {
|
|
158
|
+
if (!existsSync(searchPath)) {
|
|
159
|
+
return [];
|
|
160
|
+
}
|
|
161
|
+
const files = [];
|
|
162
|
+
// Recursively search for markdown files
|
|
163
|
+
const pattern = '**/*.md';
|
|
164
|
+
const allFiles = glob.sync(pattern, {
|
|
165
|
+
cwd: searchPath,
|
|
166
|
+
absolute: true,
|
|
167
|
+
nodir: true,
|
|
168
|
+
});
|
|
169
|
+
// Filter by entity type in frontmatter
|
|
170
|
+
for (const file of allFiles) {
|
|
171
|
+
try {
|
|
172
|
+
const doc = this.parseFile(file);
|
|
173
|
+
if (doc.frontmatter.entity_type === entityType) {
|
|
174
|
+
files.push(file);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// Skip files that can't be parsed
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return files;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Find all markdown files in a directory (recursive)
|
|
186
|
+
*/
|
|
187
|
+
findAllEntities(searchPath) {
|
|
188
|
+
if (!existsSync(searchPath)) {
|
|
189
|
+
return [];
|
|
190
|
+
}
|
|
191
|
+
const pattern = '**/*.md';
|
|
192
|
+
return glob.sync(pattern, {
|
|
193
|
+
cwd: searchPath,
|
|
194
|
+
absolute: true,
|
|
195
|
+
nodir: true,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Search entities by content or frontmatter
|
|
200
|
+
*/
|
|
201
|
+
search(searchPaths, query, options = {}) {
|
|
202
|
+
const { entityType, caseSensitive = false, searchContent = true, searchFrontmatter = true, limit = 100, } = options;
|
|
203
|
+
const results = [];
|
|
204
|
+
const pattern = caseSensitive ? query : query.toLowerCase();
|
|
205
|
+
// Search all paths
|
|
206
|
+
for (const searchPath of searchPaths) {
|
|
207
|
+
if (!existsSync(searchPath)) {
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
const files = this.findAllEntities(searchPath);
|
|
211
|
+
for (const file of files) {
|
|
212
|
+
if (results.length >= limit) {
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
try {
|
|
216
|
+
const doc = this.parseFile(file);
|
|
217
|
+
// Filter by entity type if specified
|
|
218
|
+
if (entityType && doc.frontmatter.entity_type !== entityType) {
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
// Search frontmatter
|
|
222
|
+
let found = false;
|
|
223
|
+
if (searchFrontmatter) {
|
|
224
|
+
const frontmatterStr = JSON.stringify(doc.frontmatter);
|
|
225
|
+
const searchStr = caseSensitive ? frontmatterStr : frontmatterStr.toLowerCase();
|
|
226
|
+
if (searchStr.includes(pattern)) {
|
|
227
|
+
found = true;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// Search content
|
|
231
|
+
if (!found && searchContent) {
|
|
232
|
+
const searchStr = caseSensitive ? doc.content : doc.content.toLowerCase();
|
|
233
|
+
if (searchStr.includes(pattern)) {
|
|
234
|
+
found = true;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if (found) {
|
|
238
|
+
results.push(doc);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
// Skip files that can't be parsed
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (results.length >= limit) {
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return results;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Get entity relationships (entities that link to this entity)
|
|
254
|
+
*/
|
|
255
|
+
findBacklinks(entityId, searchPaths) {
|
|
256
|
+
const backlinks = [];
|
|
257
|
+
for (const searchPath of searchPaths) {
|
|
258
|
+
if (!existsSync(searchPath)) {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
const files = this.findAllEntities(searchPath);
|
|
262
|
+
for (const file of files) {
|
|
263
|
+
try {
|
|
264
|
+
const doc = this.parseFile(file);
|
|
265
|
+
// Check if this document links to the target entity
|
|
266
|
+
const linksToTarget = doc.wikilinks.some(link => {
|
|
267
|
+
const cleanLink = link.split('/').pop() || link;
|
|
268
|
+
return cleanLink === entityId;
|
|
269
|
+
});
|
|
270
|
+
if (linksToTarget) {
|
|
271
|
+
backlinks.push({ file, doc });
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
// Skip files that can't be parsed
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return backlinks;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Update wikilinks in a file (useful for refactoring entity IDs)
|
|
284
|
+
*/
|
|
285
|
+
updateWikilinks(filePath, oldEntityId, newEntityId) {
|
|
286
|
+
if (!existsSync(filePath)) {
|
|
287
|
+
throw new Error(`File not found: ${filePath}`);
|
|
288
|
+
}
|
|
289
|
+
const doc = this.parseFile(filePath);
|
|
290
|
+
// Update content
|
|
291
|
+
let updatedContent = doc.content;
|
|
292
|
+
const wikilinkPattern = new RegExp(`\\[\\[${escapeRegex(oldEntityId)}(\\|[^\\]]+)?\\]\\]`, 'g');
|
|
293
|
+
updatedContent = updatedContent.replace(wikilinkPattern, `[[${newEntityId}$1]]`);
|
|
294
|
+
// Update frontmatter (recursively)
|
|
295
|
+
const updatedFrontmatter = this.updateWikilinksInObject(doc.frontmatter, oldEntityId, newEntityId);
|
|
296
|
+
// Write back
|
|
297
|
+
this.writeFile(filePath, {
|
|
298
|
+
frontmatter: updatedFrontmatter,
|
|
299
|
+
content: updatedContent,
|
|
300
|
+
wikilinks: [],
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Recursively update wikilinks in an object (frontmatter)
|
|
305
|
+
*/
|
|
306
|
+
updateWikilinksInObject(obj, oldEntityId, newEntityId) {
|
|
307
|
+
if (!obj || typeof obj !== 'object') {
|
|
308
|
+
return obj;
|
|
309
|
+
}
|
|
310
|
+
if (Array.isArray(obj)) {
|
|
311
|
+
return obj.map(item => {
|
|
312
|
+
if (typeof item === 'string') {
|
|
313
|
+
const wikilinkPattern = new RegExp(`\\[\\[${escapeRegex(oldEntityId)}(\\|[^\\]]+)?\\]\\]`, 'g');
|
|
314
|
+
return item.replace(wikilinkPattern, `[[${newEntityId}$1]]`);
|
|
315
|
+
}
|
|
316
|
+
return this.updateWikilinksInObject(item, oldEntityId, newEntityId);
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
const updated = {};
|
|
320
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
321
|
+
if (typeof value === 'string') {
|
|
322
|
+
const wikilinkPattern = new RegExp(`\\[\\[${escapeRegex(oldEntityId)}(\\|[^\\]]+)?\\]\\]`, 'g');
|
|
323
|
+
updated[key] = value.replace(wikilinkPattern, `[[${newEntityId}$1]]`);
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
updated[key] = this.updateWikilinksInObject(value, oldEntityId, newEntityId);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return updated;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Escape special regex characters
|
|
334
|
+
*/
|
|
335
|
+
function escapeRegex(str) {
|
|
336
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
337
|
+
}
|
|
338
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/services/markdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory service for Studiograph
|
|
3
|
+
*
|
|
4
|
+
* Manages daily memory files similar to OpenClaw:
|
|
5
|
+
* - memory/YYYY-MM-DD.md for each day
|
|
6
|
+
* - Loads today + yesterday at session start
|
|
7
|
+
* - Appends conversation context throughout the day
|
|
8
|
+
*/
|
|
9
|
+
export interface MemoryEntry {
|
|
10
|
+
timestamp: Date;
|
|
11
|
+
type: 'conversation' | 'note' | 'decision';
|
|
12
|
+
content: string;
|
|
13
|
+
metadata?: Record<string, any>;
|
|
14
|
+
}
|
|
15
|
+
export declare class MemoryService {
|
|
16
|
+
private workspacePath;
|
|
17
|
+
private memoryDir;
|
|
18
|
+
constructor(workspacePath: string);
|
|
19
|
+
/**
|
|
20
|
+
* Ensure memory directory exists
|
|
21
|
+
*/
|
|
22
|
+
private ensureMemoryDir;
|
|
23
|
+
/**
|
|
24
|
+
* Get daily memory file path for a given date
|
|
25
|
+
*/
|
|
26
|
+
private getDailyMemoryPath;
|
|
27
|
+
/**
|
|
28
|
+
* Format timestamp for memory entry
|
|
29
|
+
*/
|
|
30
|
+
private formatTimestamp;
|
|
31
|
+
/**
|
|
32
|
+
* Write entry to today's memory file
|
|
33
|
+
*/
|
|
34
|
+
writeMemory(entry: MemoryEntry): void;
|
|
35
|
+
/**
|
|
36
|
+
* Read memory for a specific date
|
|
37
|
+
*/
|
|
38
|
+
readMemory(date: Date): string | null;
|
|
39
|
+
/**
|
|
40
|
+
* Read today's memory
|
|
41
|
+
*/
|
|
42
|
+
readToday(): string | null;
|
|
43
|
+
/**
|
|
44
|
+
* Read yesterday's memory
|
|
45
|
+
*/
|
|
46
|
+
readYesterday(): string | null;
|
|
47
|
+
/**
|
|
48
|
+
* Load recent memory (today + yesterday)
|
|
49
|
+
*/
|
|
50
|
+
loadRecentMemory(): string;
|
|
51
|
+
/**
|
|
52
|
+
* List all memory files
|
|
53
|
+
*/
|
|
54
|
+
listMemoryFiles(): string[];
|
|
55
|
+
/**
|
|
56
|
+
* Search memory files for a keyword
|
|
57
|
+
*/
|
|
58
|
+
searchMemory(keyword: string, limit?: number): Array<{
|
|
59
|
+
date: string;
|
|
60
|
+
snippet: string;
|
|
61
|
+
}>;
|
|
62
|
+
/**
|
|
63
|
+
* Save session summary to memory
|
|
64
|
+
*/
|
|
65
|
+
saveSessionSummary(summary: string, metadata?: Record<string, any>): void;
|
|
66
|
+
/**
|
|
67
|
+
* Save a note to memory
|
|
68
|
+
*/
|
|
69
|
+
saveNote(note: string, metadata?: Record<string, any>): void;
|
|
70
|
+
/**
|
|
71
|
+
* Save a decision to memory
|
|
72
|
+
*/
|
|
73
|
+
saveDecision(decision: string, metadata?: Record<string, any>): void;
|
|
74
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory service for Studiograph
|
|
3
|
+
*
|
|
4
|
+
* Manages daily memory files similar to OpenClaw:
|
|
5
|
+
* - memory/YYYY-MM-DD.md for each day
|
|
6
|
+
* - Loads today + yesterday at session start
|
|
7
|
+
* - Appends conversation context throughout the day
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync, appendFileSync, writeFileSync, readdirSync } from 'fs';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
export class MemoryService {
|
|
12
|
+
workspacePath;
|
|
13
|
+
memoryDir;
|
|
14
|
+
constructor(workspacePath) {
|
|
15
|
+
this.workspacePath = workspacePath;
|
|
16
|
+
this.memoryDir = join(workspacePath, '.studiograph', 'memory');
|
|
17
|
+
this.ensureMemoryDir();
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Ensure memory directory exists
|
|
21
|
+
*/
|
|
22
|
+
ensureMemoryDir() {
|
|
23
|
+
if (!existsSync(this.memoryDir)) {
|
|
24
|
+
mkdirSync(this.memoryDir, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Get daily memory file path for a given date
|
|
29
|
+
*/
|
|
30
|
+
getDailyMemoryPath(date) {
|
|
31
|
+
const dateStr = date.toISOString().split('T')[0]; // YYYY-MM-DD
|
|
32
|
+
return join(this.memoryDir, `${dateStr}.md`);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Format timestamp for memory entry
|
|
36
|
+
*/
|
|
37
|
+
formatTimestamp(date) {
|
|
38
|
+
return date.toISOString().replace('T', ' ').split('.')[0] + ' UTC';
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Write entry to today's memory file
|
|
42
|
+
*/
|
|
43
|
+
writeMemory(entry) {
|
|
44
|
+
const memoryPath = this.getDailyMemoryPath(entry.timestamp);
|
|
45
|
+
const timestamp = this.formatTimestamp(entry.timestamp);
|
|
46
|
+
// Format entry as markdown
|
|
47
|
+
const lines = [
|
|
48
|
+
`## ${timestamp} - ${entry.type}`,
|
|
49
|
+
'',
|
|
50
|
+
entry.content,
|
|
51
|
+
'',
|
|
52
|
+
];
|
|
53
|
+
// Add metadata if present
|
|
54
|
+
if (entry.metadata) {
|
|
55
|
+
lines.push('**Metadata:**');
|
|
56
|
+
for (const [key, value] of Object.entries(entry.metadata)) {
|
|
57
|
+
lines.push(`- **${key}**: ${value}`);
|
|
58
|
+
}
|
|
59
|
+
lines.push('');
|
|
60
|
+
}
|
|
61
|
+
lines.push('---', '');
|
|
62
|
+
const entryText = lines.join('\n');
|
|
63
|
+
// Append to file (or create if doesn't exist)
|
|
64
|
+
if (!existsSync(memoryPath)) {
|
|
65
|
+
const header = `# Memory - ${entry.timestamp.toISOString().split('T')[0]}\n\n`;
|
|
66
|
+
writeFileSync(memoryPath, header + entryText, 'utf-8');
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
appendFileSync(memoryPath, entryText, 'utf-8');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Read memory for a specific date
|
|
74
|
+
*/
|
|
75
|
+
readMemory(date) {
|
|
76
|
+
const memoryPath = this.getDailyMemoryPath(date);
|
|
77
|
+
if (!existsSync(memoryPath)) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
return readFileSync(memoryPath, 'utf-8');
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Read today's memory
|
|
84
|
+
*/
|
|
85
|
+
readToday() {
|
|
86
|
+
return this.readMemory(new Date());
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Read yesterday's memory
|
|
90
|
+
*/
|
|
91
|
+
readYesterday() {
|
|
92
|
+
const yesterday = new Date();
|
|
93
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
94
|
+
return this.readMemory(yesterday);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Load recent memory (today + yesterday)
|
|
98
|
+
*/
|
|
99
|
+
loadRecentMemory() {
|
|
100
|
+
const parts = [];
|
|
101
|
+
const yesterday = this.readYesterday();
|
|
102
|
+
if (yesterday) {
|
|
103
|
+
parts.push('# Yesterday\n', yesterday, '\n');
|
|
104
|
+
}
|
|
105
|
+
const today = this.readToday();
|
|
106
|
+
if (today) {
|
|
107
|
+
parts.push('# Today\n', today, '\n');
|
|
108
|
+
}
|
|
109
|
+
if (parts.length === 0) {
|
|
110
|
+
return '# No recent memory\n\nNo memory entries from today or yesterday.';
|
|
111
|
+
}
|
|
112
|
+
return parts.join('\n');
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* List all memory files
|
|
116
|
+
*/
|
|
117
|
+
listMemoryFiles() {
|
|
118
|
+
if (!existsSync(this.memoryDir)) {
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
return readdirSync(this.memoryDir)
|
|
122
|
+
.filter(file => file.endsWith('.md'))
|
|
123
|
+
.sort()
|
|
124
|
+
.reverse(); // Most recent first
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Search memory files for a keyword
|
|
128
|
+
*/
|
|
129
|
+
searchMemory(keyword, limit = 10) {
|
|
130
|
+
const files = this.listMemoryFiles().slice(0, limit);
|
|
131
|
+
const results = [];
|
|
132
|
+
for (const file of files) {
|
|
133
|
+
const filePath = join(this.memoryDir, file);
|
|
134
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
135
|
+
if (content.toLowerCase().includes(keyword.toLowerCase())) {
|
|
136
|
+
// Extract snippet around keyword
|
|
137
|
+
const lines = content.split('\n');
|
|
138
|
+
const matchingLines = lines.filter(line => line.toLowerCase().includes(keyword.toLowerCase()));
|
|
139
|
+
if (matchingLines.length > 0) {
|
|
140
|
+
results.push({
|
|
141
|
+
date: file.replace('.md', ''),
|
|
142
|
+
snippet: matchingLines.slice(0, 3).join('\n'),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return results;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Save session summary to memory
|
|
151
|
+
*/
|
|
152
|
+
saveSessionSummary(summary, metadata) {
|
|
153
|
+
this.writeMemory({
|
|
154
|
+
timestamp: new Date(),
|
|
155
|
+
type: 'conversation',
|
|
156
|
+
content: summary,
|
|
157
|
+
metadata,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Save a note to memory
|
|
162
|
+
*/
|
|
163
|
+
saveNote(note, metadata) {
|
|
164
|
+
this.writeMemory({
|
|
165
|
+
timestamp: new Date(),
|
|
166
|
+
type: 'note',
|
|
167
|
+
content: note,
|
|
168
|
+
metadata,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Save a decision to memory
|
|
173
|
+
*/
|
|
174
|
+
saveDecision(decision, metadata) {
|
|
175
|
+
this.writeMemory({
|
|
176
|
+
timestamp: new Date(),
|
|
177
|
+
type: 'decision',
|
|
178
|
+
content: decision,
|
|
179
|
+
metadata,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=memory-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-service.js","sourceRoot":"","sources":["../../src/services/memory-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin wrappers around git shell operations.
|
|
3
|
+
* Extracted so tests can mock them without mocking the built-in child_process.
|
|
4
|
+
*/
|
|
5
|
+
export type PullResult = 'updated' | 'up-to-date' | 'conflict';
|
|
6
|
+
export type PushResult = 'pushed' | 'nothing-to-push';
|
|
7
|
+
/**
|
|
8
|
+
* Pull the latest changes in a local git repo.
|
|
9
|
+
* Returns 'updated', 'up-to-date', or 'conflict'.
|
|
10
|
+
* Throws on hard errors (no remote, auth failure, etc.).
|
|
11
|
+
*/
|
|
12
|
+
export declare function gitPull(repoPath: string): PullResult;
|
|
13
|
+
/**
|
|
14
|
+
* Push local commits in a git repo to its remote.
|
|
15
|
+
* Returns 'pushed' or 'nothing-to-push'.
|
|
16
|
+
* Throws on errors (no remote, auth failure, etc.).
|
|
17
|
+
*/
|
|
18
|
+
export declare function gitPush(repoPath: string): PushResult;
|
|
19
|
+
/**
|
|
20
|
+
* Clone a remote repository to a local path.
|
|
21
|
+
* Throws if the git command fails.
|
|
22
|
+
*/
|
|
23
|
+
export declare function gitClone(remoteUrl: string, localPath: string): void;
|
|
24
|
+
/**
|
|
25
|
+
* Read a git config value.
|
|
26
|
+
* Returns undefined if the key is not set.
|
|
27
|
+
*/
|
|
28
|
+
export declare function getGitConfig(key: string): string | undefined;
|