@fonlan/dsh-gitmemo 0.1.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/LICENSE +21 -0
- package/README.md +139 -0
- package/README.zh.md +133 -0
- package/cordis.patch.yml +14 -0
- package/lib/index.d.ts +94 -0
- package/lib/index.js +329 -0
- package/lib/mem.d.ts +106 -0
- package/lib/mem.js +562 -0
- package/package.json +62 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-gitmemo — Git-backed long-term memory for DeepSeek Harness.
|
|
3
|
+
*
|
|
4
|
+
* A Cordis plugin mirroring gitmemo (https://github.com/fonlan/gitmemo):
|
|
5
|
+
* the agent stores completed task outcomes as markdown entries in a local
|
|
6
|
+
* `.mem` git repository and searches them before starting new work.
|
|
7
|
+
*
|
|
8
|
+
* This plugin registers on the host plane:
|
|
9
|
+
* - five model-facing tools: `mem_init`, `mem_search`, `mem_read`,
|
|
10
|
+
* `mem_write`, `mem_delete` (backed by {@link GitMemo});
|
|
11
|
+
* - an always-on system-prompt section with the full memory workflow rules;
|
|
12
|
+
* - a per-session seed of the most recent memory titles.
|
|
13
|
+
*
|
|
14
|
+
* @module dsh-gitmemo
|
|
15
|
+
*/
|
|
16
|
+
import z from "@deepseek-ai/schemastery";
|
|
17
|
+
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
18
|
+
import { GitMemo } from "./mem.js";
|
|
19
|
+
/** Cordis plugin name. */
|
|
20
|
+
const name = "dsh-gitmemo";
|
|
21
|
+
/** Host services this plugin needs. */
|
|
22
|
+
const inject = ["tools", "systemPrompt"];
|
|
23
|
+
/** Plugin configuration (all optional). */
|
|
24
|
+
const Config = z.object({
|
|
25
|
+
/** Name of the memory repo directory at the project root. Default ".mem". */
|
|
26
|
+
memDirName: z.string().default(".mem"),
|
|
27
|
+
/** Max search hits per mem_search call. Default 20. */
|
|
28
|
+
searchLimit: z.number().default(20),
|
|
29
|
+
/** Align the .mem branch with the project branch on writes. Default true. */
|
|
30
|
+
branchAlign: z.boolean().default(true),
|
|
31
|
+
/** Number of most recent memory titles injected into each new session's system prompt (0 disables). Default 5. */
|
|
32
|
+
recentContextLimit: z.number().default(5),
|
|
33
|
+
/** Optional explicit project root; defaults to the calling session's cwd. */
|
|
34
|
+
projectRoot: z.string()
|
|
35
|
+
});
|
|
36
|
+
/** The calling agent's session workspace, when it has one. */
|
|
37
|
+
function sessionCwd(exec) {
|
|
38
|
+
return exec.agent?.session?.header?.cwd;
|
|
39
|
+
}
|
|
40
|
+
/** Build the engine for one tool call. */
|
|
41
|
+
function engineFor(exec, config) {
|
|
42
|
+
const cwd = sessionCwd(exec) ?? process.cwd();
|
|
43
|
+
const root = config.projectRoot ?? cwd;
|
|
44
|
+
const engineConfig = {
|
|
45
|
+
memDirName: config.memDirName,
|
|
46
|
+
searchLimit: config.searchLimit,
|
|
47
|
+
branchAlign: config.branchAlign
|
|
48
|
+
};
|
|
49
|
+
return new GitMemo(root, engineConfig);
|
|
50
|
+
}
|
|
51
|
+
const SEARCH_HIT = {
|
|
52
|
+
type: "object",
|
|
53
|
+
additionalProperties: false,
|
|
54
|
+
properties: {
|
|
55
|
+
hash: { type: "string", required: true, description: "Full commit hash of the memory entry." },
|
|
56
|
+
title: { type: "string", required: true, description: "Commit subject (the entry title)." },
|
|
57
|
+
date: { type: "string", required: true, description: "Commit date in ISO format." }
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
/** Render one tool output block as plain text. */
|
|
61
|
+
function textBlock(text) {
|
|
62
|
+
return [{ type: "text", text }];
|
|
63
|
+
}
|
|
64
|
+
/** Register every model-facing tool. */
|
|
65
|
+
function registerMemTools(ctx, config) {
|
|
66
|
+
void config;
|
|
67
|
+
ctx.tools.register(defineTool({
|
|
68
|
+
name: "mem_init",
|
|
69
|
+
description: "Initialize the gitmemo long-term memory repository (.mem git repo) at the project root. All other mem_* tools auto-initialize, so this is only needed to check or force initialization.",
|
|
70
|
+
parameters: {},
|
|
71
|
+
output: {
|
|
72
|
+
schema: {
|
|
73
|
+
type: "object",
|
|
74
|
+
additionalProperties: false,
|
|
75
|
+
properties: {
|
|
76
|
+
path: { type: "string", required: true, description: "Absolute path of the memory repository." }
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
render: (_args, value) => textBlock("OK: Memory repo ready at " + value.path)
|
|
80
|
+
},
|
|
81
|
+
isConcurrencySafe: () => false,
|
|
82
|
+
async execute(_args, exec) {
|
|
83
|
+
const memo = engineFor(exec, config);
|
|
84
|
+
const path = await memo.init();
|
|
85
|
+
return { path };
|
|
86
|
+
},
|
|
87
|
+
presentCall: () => ({ card: "generic", title: "Init gitmemo memory", kind: "other" })
|
|
88
|
+
}));
|
|
89
|
+
ctx.tools.register(defineTool({
|
|
90
|
+
name: "mem_search",
|
|
91
|
+
description: "Search the gitmemo long-term memory (.mem git repo) for past task outcomes. Call BEFORE starting work: extract 3-5 keywords from the user request, search, and reuse prior conclusions when relevant. Returns up to 20 hits formatted as `hash|title|date`; when nothing relevant appears, paginate with `skip` 20, 40, ...",
|
|
92
|
+
parameters: {
|
|
93
|
+
keywords: {
|
|
94
|
+
type: "string",
|
|
95
|
+
required: true,
|
|
96
|
+
description: "Comma-separated keywords (3-5 recommended), e.g. \"auth,rate-limit,login\"."
|
|
97
|
+
},
|
|
98
|
+
skip: {
|
|
99
|
+
type: "integer",
|
|
100
|
+
description: "Pagination offset (default 0)."
|
|
101
|
+
},
|
|
102
|
+
mode: {
|
|
103
|
+
type: "string",
|
|
104
|
+
enum: ["and", "or", "auto"],
|
|
105
|
+
description: "and=strict (all keywords), or=broad (any keyword), auto=AND first then OR fallback (default auto)."
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
output: {
|
|
109
|
+
schema: {
|
|
110
|
+
type: "object",
|
|
111
|
+
additionalProperties: false,
|
|
112
|
+
properties: {
|
|
113
|
+
mode: { type: "string", required: true, description: "The mode actually used (and or or)." },
|
|
114
|
+
results: { type: "array", required: true, items: SEARCH_HIT }
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
render: (_args, value) => {
|
|
118
|
+
const lines = value.results.map((hit) => hit.hash + "|" + hit.title + "|" + hit.date);
|
|
119
|
+
return textBlock(lines.length > 0 ? lines.join("\n") : "(no matching memories)");
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
isConcurrencySafe: () => true,
|
|
123
|
+
async execute(args, exec) {
|
|
124
|
+
const memo = engineFor(exec, config);
|
|
125
|
+
return await memo.search(args.keywords, args.skip ?? 0, args.mode ?? "auto");
|
|
126
|
+
},
|
|
127
|
+
presentCall: (args) => ({
|
|
128
|
+
card: "generic",
|
|
129
|
+
title: "Search memory: " + args.keywords,
|
|
130
|
+
kind: "other"
|
|
131
|
+
})
|
|
132
|
+
}));
|
|
133
|
+
ctx.tools.register(defineTool({
|
|
134
|
+
name: "mem_read",
|
|
135
|
+
description: "Read one gitmemo memory entry by commit hash (returned by mem_search). Select only the most relevant memories before reading — at most 5 when a search returns more.",
|
|
136
|
+
parameters: {
|
|
137
|
+
commit_hash: {
|
|
138
|
+
type: "string",
|
|
139
|
+
required: true,
|
|
140
|
+
description: "Commit hash of the memory entry to read."
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
output: {
|
|
144
|
+
schema: {
|
|
145
|
+
type: "object",
|
|
146
|
+
additionalProperties: false,
|
|
147
|
+
properties: {
|
|
148
|
+
commit_hash: { type: "string", required: true },
|
|
149
|
+
file: { type: "string", required: true, description: "Entry file path inside the memory repo." },
|
|
150
|
+
content: { type: "string", required: true, description: "Full markdown of the memory entry." }
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
render: (_args, value) => textBlock(value.content)
|
|
154
|
+
},
|
|
155
|
+
isConcurrencySafe: () => true,
|
|
156
|
+
async execute(args, exec) {
|
|
157
|
+
const memo = engineFor(exec, config);
|
|
158
|
+
const { file, content } = await memo.read(args.commit_hash);
|
|
159
|
+
return { commit_hash: args.commit_hash, file, content };
|
|
160
|
+
},
|
|
161
|
+
presentCall: (args) => ({
|
|
162
|
+
card: "generic",
|
|
163
|
+
title: "Read memory " + args.commit_hash.slice(0, 8),
|
|
164
|
+
kind: "read"
|
|
165
|
+
})
|
|
166
|
+
}));
|
|
167
|
+
ctx.tools.register(defineTool({
|
|
168
|
+
name: "mem_write",
|
|
169
|
+
description: "Store a completed task outcome in the gitmemo long-term memory (.mem git repo). Write ONLY when the task is complete AND repo-related AND the outcome is valuable/reusable OR the user explicitly asked to remember. Entry markdown goes through `content` (or `content_file`); `title` is a short \"[module] action + object\"; `body` is an optional 1-3 sentence commit body (never memory content). The entry is committed as `.mem/entries/<timestamp>-<slug>.md` and the .mem branch follows the project branch.",
|
|
170
|
+
parameters: {
|
|
171
|
+
title: {
|
|
172
|
+
type: "string",
|
|
173
|
+
required: true,
|
|
174
|
+
description: "Short \"[module] action + object\" title, e.g. \"[auth] add rate-limit for login\"."
|
|
175
|
+
},
|
|
176
|
+
content: {
|
|
177
|
+
type: "string",
|
|
178
|
+
description: "The memory entry markdown (YAML front matter + sections). Provide exactly one of content / content_file / file."
|
|
179
|
+
},
|
|
180
|
+
content_file: {
|
|
181
|
+
type: "string",
|
|
182
|
+
description: "Path to a file holding the entry markdown (alternative to content; temp files are deleted after a successful write)."
|
|
183
|
+
},
|
|
184
|
+
file: {
|
|
185
|
+
type: "string",
|
|
186
|
+
description: "An existing .mem/entries/... path to commit in place (alternative to content / content_file)."
|
|
187
|
+
},
|
|
188
|
+
body: {
|
|
189
|
+
type: "string",
|
|
190
|
+
description: "Optional commit body: 1-3 sentence summary + metadata. Not memory content."
|
|
191
|
+
},
|
|
192
|
+
body_file: {
|
|
193
|
+
type: "string",
|
|
194
|
+
description: "Path to a file holding the commit body (alternative to body)."
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
output: {
|
|
198
|
+
schema: {
|
|
199
|
+
type: "object",
|
|
200
|
+
additionalProperties: false,
|
|
201
|
+
properties: {
|
|
202
|
+
hash: { type: "string", required: true, description: "Commit hash of the new memory entry." },
|
|
203
|
+
file: { type: "string", required: true, description: "Entry file path inside the memory repo." }
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
render: (_args, value) => textBlock("OK: " + value.hash + "|" + value.file)
|
|
207
|
+
},
|
|
208
|
+
isConcurrencySafe: () => false,
|
|
209
|
+
async execute(args, exec) {
|
|
210
|
+
const memo = engineFor(exec, config);
|
|
211
|
+
return await memo.write({
|
|
212
|
+
title: args.title,
|
|
213
|
+
content: args.content,
|
|
214
|
+
contentFile: args.content_file,
|
|
215
|
+
file: args.file,
|
|
216
|
+
body: args.body,
|
|
217
|
+
bodyFile: args.body_file
|
|
218
|
+
});
|
|
219
|
+
},
|
|
220
|
+
presentCall: (args) => ({
|
|
221
|
+
card: "generic",
|
|
222
|
+
title: "Write memory: " + args.title,
|
|
223
|
+
kind: "other"
|
|
224
|
+
})
|
|
225
|
+
}));
|
|
226
|
+
ctx.tools.register(defineTool({
|
|
227
|
+
name: "mem_delete",
|
|
228
|
+
description: "Delete a gitmemo memory entry by commit hash. Use when the user is unsatisfied with a stored outcome: delete, redo the task from feedback, then mem_write a corrected entry.",
|
|
229
|
+
parameters: {
|
|
230
|
+
commit_hash: {
|
|
231
|
+
type: "string",
|
|
232
|
+
required: true,
|
|
233
|
+
description: "Commit hash of the memory entry to delete."
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
output: {
|
|
237
|
+
schema: {
|
|
238
|
+
type: "object",
|
|
239
|
+
additionalProperties: false,
|
|
240
|
+
properties: {
|
|
241
|
+
file: { type: "string", required: true, description: "Deleted entry file path." }
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
render: (_args, value) => textBlock("OK: deleted " + value.file)
|
|
245
|
+
},
|
|
246
|
+
isConcurrencySafe: () => false,
|
|
247
|
+
async execute(args, exec) {
|
|
248
|
+
const memo = engineFor(exec, config);
|
|
249
|
+
const file = await memo.delete(args.commit_hash);
|
|
250
|
+
return { file };
|
|
251
|
+
},
|
|
252
|
+
presentCall: (args) => ({
|
|
253
|
+
card: "generic",
|
|
254
|
+
title: "Delete memory " + args.commit_hash.slice(0, 8),
|
|
255
|
+
kind: "other"
|
|
256
|
+
})
|
|
257
|
+
}));
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Register the always-on memory workflow rules (the equivalent of gitmemo's
|
|
261
|
+
* agents-template.md). This section is part of every session's system prompt,
|
|
262
|
+
* so the rules cannot be missed; the mem_* tool descriptions carry the
|
|
263
|
+
* argument contract for each operation.
|
|
264
|
+
*/
|
|
265
|
+
function registerPromptSection(ctx) {
|
|
266
|
+
ctx.systemPrompt.section({
|
|
267
|
+
name: "memory:gitmemo",
|
|
268
|
+
order: 150,
|
|
269
|
+
text: [
|
|
270
|
+
"This deployment provides gitmemo long-term memory: a local .mem git repository at the project root stores past task outcomes as markdown entries; git is the only dependency. Use the dedicated tools only (mem_search / mem_read / mem_write / mem_delete — all auto-initialize); never shell out to git or read .mem files directly.",
|
|
271
|
+
"- BEFORE WORK — search: extract 3-5 keywords from the user request and run mem_search. If more than 5 relevant hits appear, select only the 5 most likely (keyword overlap, title specificity, recency) and mem_read only those; reuse their conclusions when appropriate. If nothing relevant, paginate with skip 20, 40, ...",
|
|
272
|
+
"- USER UNSATISFIED — delete and rewrite: mem_delete the entry's commit hash, redo the task from the feedback, then mem_write a corrected entry.",
|
|
273
|
+
"- END-OF-SESSION CHECKPOINT — the ONLY write path: when the conversation is ending, review the whole session and mem_write EVERY completed repo-related task that still lacks a memory and whose outcome is valuable and reusable OR was explicitly asked to be remembered. Never write for pure Q&A, incomplete tasks, non-repo work, or purely operational git actions (commit/push only). Never duplicate an already-written entry; if a stored outcome is outdated, mem_delete it first, then write the corrected entry. Entry title: \"[module] action + object\"; content: markdown with YAML front matter (date, status, repo_branch, mem_branch, related_paths, tags) and Original User Request / AI Understanding / Final Outcome sections."
|
|
274
|
+
].join("\n")
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Seed every new ROOT agent session with the most recent memory titles.
|
|
279
|
+
* Registered into the agent's own scope, so the block joins only that
|
|
280
|
+
* session's prompt; subagents (delegationDepth > 0) are skipped, the lookup
|
|
281
|
+
* is read-only (no .mem auto-init), and failures degrade to a log warning.
|
|
282
|
+
*/
|
|
283
|
+
function registerRecentContext(ctx, config) {
|
|
284
|
+
if (config.recentContextLimit <= 0)
|
|
285
|
+
return;
|
|
286
|
+
ctx.on("agent/created", ({ agent }) => {
|
|
287
|
+
const header = agent.session?.header;
|
|
288
|
+
if (header?.cwd === undefined || (header.delegationDepth ?? 0) > 0)
|
|
289
|
+
return;
|
|
290
|
+
try {
|
|
291
|
+
// Synchronous scan: registers the context before the first request assembles.
|
|
292
|
+
const memo = new GitMemo(config.projectRoot ?? header.cwd, {
|
|
293
|
+
memDirName: config.memDirName,
|
|
294
|
+
searchLimit: config.searchLimit,
|
|
295
|
+
branchAlign: config.branchAlign
|
|
296
|
+
});
|
|
297
|
+
const hits = memo.recentSync(config.recentContextLimit);
|
|
298
|
+
if (hits.length === 0)
|
|
299
|
+
return;
|
|
300
|
+
const lines = hits.map((hit) => hit.hash + "|" + hit.title + "|" + hit.date);
|
|
301
|
+
agent.ctx.systemPrompt.context({
|
|
302
|
+
name: "memory:gitmemo-recent",
|
|
303
|
+
order: 400,
|
|
304
|
+
text: "Recent gitmemo memories from previous sessions (mem_read <hash> for details, mem_search for targeted lookups):\n" + lines.join("\n")
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
catch (error) {
|
|
308
|
+
ctx.logger.warn(`dsh-gitmemo: recent-memory injection skipped for agent "${agent.id}": ${String(error)}`);
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Register the plugin: tools, always-on rules, and session-start seed.
|
|
314
|
+
* @param ctx - registrant context carrying the host tool/prompt services.
|
|
315
|
+
* @param config - plugin configuration (defaults applied by the loader).
|
|
316
|
+
*/
|
|
317
|
+
async function apply(ctx, config = {}) {
|
|
318
|
+
const resolved = {
|
|
319
|
+
memDirName: config.memDirName ?? ".mem",
|
|
320
|
+
searchLimit: config.searchLimit ?? 20,
|
|
321
|
+
branchAlign: config.branchAlign ?? true,
|
|
322
|
+
recentContextLimit: config.recentContextLimit ?? 5,
|
|
323
|
+
projectRoot: config.projectRoot
|
|
324
|
+
};
|
|
325
|
+
registerMemTools(ctx, resolved);
|
|
326
|
+
registerPromptSection(ctx);
|
|
327
|
+
registerRecentContext(ctx, resolved);
|
|
328
|
+
}
|
|
329
|
+
export { Config, apply, inject, name };
|
package/lib/mem.d.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/** Per-invocation engine options. */
|
|
2
|
+
export interface GitMemoConfig {
|
|
3
|
+
/** Name of the memory repository directory at the project root. Default ".mem". */
|
|
4
|
+
memDirName?: string;
|
|
5
|
+
/** Maximum number of search hits returned per call. Default 20. */
|
|
6
|
+
searchLimit?: number;
|
|
7
|
+
/** Whether `.mem` branch follows the project branch on write. Default true. */
|
|
8
|
+
branchAlign?: boolean;
|
|
9
|
+
/** Per git subprocess timeout in milliseconds. Default 60000. */
|
|
10
|
+
gitTimeoutMs?: number;
|
|
11
|
+
/** Cap on git-log batches scanned by one search call. Default 200. */
|
|
12
|
+
maxSearchBatches?: number;
|
|
13
|
+
}
|
|
14
|
+
/** One search hit, formatted `hash|title|date` like the original script. */
|
|
15
|
+
export interface SearchHit {
|
|
16
|
+
hash: string;
|
|
17
|
+
title: string;
|
|
18
|
+
date: string;
|
|
19
|
+
}
|
|
20
|
+
export interface WriteOptions {
|
|
21
|
+
/** Short "[module] action + object" title (required). */
|
|
22
|
+
title: string;
|
|
23
|
+
/** Entry markdown; provide exactly one of content / contentFile / file. */
|
|
24
|
+
content?: string;
|
|
25
|
+
/** Path to a file holding the entry markdown (temp file or an existing .mem/entries path). */
|
|
26
|
+
contentFile?: string;
|
|
27
|
+
/** Existing entry path to commit in place: `entries/foo.md`, `.mem/entries/foo.md`, or an absolute path under .mem. */
|
|
28
|
+
file?: string;
|
|
29
|
+
/** Optional single-line commit body. */
|
|
30
|
+
body?: string;
|
|
31
|
+
/** Optional path to a file holding the commit body. */
|
|
32
|
+
bodyFile?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface WriteResult {
|
|
35
|
+
hash: string;
|
|
36
|
+
file: string;
|
|
37
|
+
}
|
|
38
|
+
export interface SearchResult {
|
|
39
|
+
mode: "and" | "or";
|
|
40
|
+
results: SearchHit[];
|
|
41
|
+
}
|
|
42
|
+
/** True when a path points inside (or at) the memory entries directory. */
|
|
43
|
+
declare function isEntriesPath(memRoot: string, full: string): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Git-backed long-term memory engine operating on one project root.
|
|
46
|
+
*/
|
|
47
|
+
export declare class GitMemo {
|
|
48
|
+
readonly root: string;
|
|
49
|
+
readonly memDir: string;
|
|
50
|
+
private readonly config;
|
|
51
|
+
constructor(root: string, config?: GitMemoConfig);
|
|
52
|
+
/** The current branch of a git work tree, "main" when detached/unavailable. */
|
|
53
|
+
private currentBranch;
|
|
54
|
+
private projectBranch;
|
|
55
|
+
private memBranch;
|
|
56
|
+
/**
|
|
57
|
+
* Initialize the memory repo when missing (git init + .gitkeep commit).
|
|
58
|
+
* Idempotent; every other operation auto-initializes.
|
|
59
|
+
*/
|
|
60
|
+
init(): Promise<string>;
|
|
61
|
+
/** Align the memory repo branch with the project branch (create if needed). */
|
|
62
|
+
private syncBranch;
|
|
63
|
+
/**
|
|
64
|
+
* Search past memories.
|
|
65
|
+
* @param keywords - comma-separated keywords.
|
|
66
|
+
* @param skip - pagination offset (default 0).
|
|
67
|
+
* @param mode - "and" (strict), "or" (broad), or "auto" (AND first, OR fallback).
|
|
68
|
+
*/
|
|
69
|
+
search(keywords: string, skip?: number, mode?: "and" | "or" | "auto"): Promise<SearchResult>;
|
|
70
|
+
private runSearchMode;
|
|
71
|
+
/**
|
|
72
|
+
* List the most recent memory entries across all branches, newest first.
|
|
73
|
+
* Used to seed a new session's system prompt with a compact overview.
|
|
74
|
+
* @param limit - maximum number of entries to return (0 returns none).
|
|
75
|
+
*/
|
|
76
|
+
recent(limit: number): Promise<SearchHit[]>;
|
|
77
|
+
/** Active (non-deleted) entry files at HEAD. */
|
|
78
|
+
private activeEntries;
|
|
79
|
+
/** Shared git-log scan: keyword-grep optional, active-entry filtering, skip/limit. */
|
|
80
|
+
private scanLog;
|
|
81
|
+
/**
|
|
82
|
+
* Synchronous variant of {@link recent} for the session-start injection
|
|
83
|
+
* path: blocks until the memory repo is scanned so the system-prompt
|
|
84
|
+
* context can be registered before the first request assembles.
|
|
85
|
+
*/
|
|
86
|
+
recentSync(limit: number): SearchHit[];
|
|
87
|
+
private acceptRecord;
|
|
88
|
+
/** Resolve the entry file touched by a commit (first file under entries/). */
|
|
89
|
+
private entryFileFromCommit;
|
|
90
|
+
/** Read one memory entry by commit hash. */
|
|
91
|
+
read(commitHash: string): Promise<{
|
|
92
|
+
file: string;
|
|
93
|
+
content: string;
|
|
94
|
+
}>;
|
|
95
|
+
/**
|
|
96
|
+
* Write a memory entry.
|
|
97
|
+
* Mirrors mem.sh write: commit a markdown entry under entries/ with an
|
|
98
|
+
* optional body, aligning the .mem branch with the project branch first.
|
|
99
|
+
*/
|
|
100
|
+
write(options: WriteOptions): Promise<WriteResult>;
|
|
101
|
+
/** Delete a memory entry by commit hash. */
|
|
102
|
+
delete(commitHash: string): Promise<string>;
|
|
103
|
+
}
|
|
104
|
+
/** Initialize the memory repo when missing. */
|
|
105
|
+
export declare function ensureInit(memDir: string, gitTimeoutMs?: number): Promise<void>;
|
|
106
|
+
export { isEntriesPath };
|