claude-recall 0.20.16 → 0.21.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/.claude/skills/auto-preferences/SKILL.md +4 -4
- package/.claude/skills/auto-preferences/manifest.json +7 -7
- package/README.md +23 -0
- package/dist/cli/claude-recall-cli.js +116 -0
- package/dist/mcp/tools/memory-tools.js +85 -4
- package/dist/memory/storage.js +45 -0
- package/dist/pi/extension.js +81 -2
- package/dist/services/memory.js +18 -0
- package/package.json +1 -1
|
@@ -12,10 +12,10 @@ Auto-generated from 5 memories. Last updated: 2026-04-10.
|
|
|
12
12
|
|
|
13
13
|
## Rules
|
|
14
14
|
|
|
15
|
-
- Session test preference
|
|
16
|
-
- Test preference
|
|
17
|
-
- Test preference
|
|
18
|
-
- Test preference
|
|
15
|
+
- Session test preference 1775856590823
|
|
16
|
+
- Test preference 1775856590766-2
|
|
17
|
+
- Test preference 1775856590766-1
|
|
18
|
+
- Test preference 1775856590766-0
|
|
19
19
|
- Test memory content
|
|
20
20
|
|
|
21
21
|
---
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"topicId": "preferences",
|
|
3
|
-
"sourceHash": "
|
|
3
|
+
"sourceHash": "bc008faff7f86df3f887d5949481aad102da2261a2872bb1b030bc4279eee9fd",
|
|
4
4
|
"memoryCount": 5,
|
|
5
|
-
"generatedAt": "2026-04-
|
|
5
|
+
"generatedAt": "2026-04-10T21:29:50.846Z",
|
|
6
6
|
"memoryKeys": [
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
7
|
+
"memory_1775856590824_6gpdsqsh0",
|
|
8
|
+
"memory_1775856590800_fv6xg43wx",
|
|
9
|
+
"memory_1775856590782_kwl352n83",
|
|
10
|
+
"memory_1775856590768_crx4xtq3i",
|
|
11
|
+
"memory_1775856590726_t9ap1te0i"
|
|
12
12
|
]
|
|
13
13
|
}
|
package/README.md
CHANGED
|
@@ -180,6 +180,24 @@ claude-recall import backup.json # Import memories from JSON
|
|
|
180
180
|
claude-recall clear --force # Delete all memories (irreversible)
|
|
181
181
|
```
|
|
182
182
|
|
|
183
|
+
### Task Checkpoints
|
|
184
|
+
|
|
185
|
+
Persistent "where I left off" snapshots — one per project, replaces previous on save. Not loaded as a rule; `load_rules` only hints that one exists.
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
claude-recall checkpoint save \
|
|
189
|
+
--completed "inference layer, domain layer" \
|
|
190
|
+
--remaining "wire server.js, strip 3GPP URNs" \
|
|
191
|
+
--blockers "none" \
|
|
192
|
+
--notes "see inference/README.md"
|
|
193
|
+
|
|
194
|
+
claude-recall checkpoint load # Show the latest checkpoint
|
|
195
|
+
claude-recall checkpoint load --json # Machine-readable
|
|
196
|
+
claude-recall checkpoint clear # Delete the checkpoint
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Agents can also save/load checkpoints via MCP tools (`mcp__claude-recall__save_checkpoint` / `mcp__claude-recall__load_checkpoint`) or Pi tools (`recall_save_checkpoint` / `recall_load_checkpoint`).
|
|
200
|
+
|
|
183
201
|
### Troubleshooting
|
|
184
202
|
|
|
185
203
|
```bash
|
|
@@ -246,6 +264,11 @@ claude-recall outcomes --section stats # Retrieval/helpfulness stats
|
|
|
246
264
|
claude-recall outcomes --limit 20 # More items per section
|
|
247
265
|
claude-recall monitor # Memory search monitoring stats
|
|
248
266
|
|
|
267
|
+
# ── Task Checkpoints ────────────────────────────────────────────────
|
|
268
|
+
claude-recall checkpoint save --completed <text> --remaining <text> [--blockers <text>] [--notes <text>] [--project <id>]
|
|
269
|
+
claude-recall checkpoint load [--project <id>] [--json]
|
|
270
|
+
claude-recall checkpoint clear [--project <id>]
|
|
271
|
+
|
|
249
272
|
# ── Skills ───────────────────────────────────────────────────────────
|
|
250
273
|
claude-recall skills generate # Generate skills from memories
|
|
251
274
|
claude-recall skills generate --dry-run # Preview without writing
|
|
@@ -500,6 +500,80 @@ class ClaudeRecallCLI {
|
|
|
500
500
|
process.exit(1);
|
|
501
501
|
}
|
|
502
502
|
}
|
|
503
|
+
/**
|
|
504
|
+
* Save a task checkpoint for the current (or specified) project.
|
|
505
|
+
*/
|
|
506
|
+
checkpointSave(opts) {
|
|
507
|
+
try {
|
|
508
|
+
const projectId = opts.project || config_1.ConfigService.getInstance().getProjectId();
|
|
509
|
+
this.memoryService.saveCheckpoint(projectId, {
|
|
510
|
+
completed: opts.completed,
|
|
511
|
+
remaining: opts.remaining,
|
|
512
|
+
blockers: opts.blockers || 'none',
|
|
513
|
+
notes: opts.notes,
|
|
514
|
+
});
|
|
515
|
+
console.log(`\n✅ Checkpoint saved for project: ${projectId}\n`);
|
|
516
|
+
console.log(` Completed: ${opts.completed}`);
|
|
517
|
+
console.log(` Remaining: ${opts.remaining}`);
|
|
518
|
+
console.log(` Blockers: ${opts.blockers || 'none'}`);
|
|
519
|
+
if (opts.notes)
|
|
520
|
+
console.log(` Notes: ${opts.notes}`);
|
|
521
|
+
console.log('');
|
|
522
|
+
}
|
|
523
|
+
catch (error) {
|
|
524
|
+
console.error('❌ Checkpoint save failed:', error);
|
|
525
|
+
process.exit(1);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Load the latest task checkpoint for the current (or specified) project.
|
|
530
|
+
*/
|
|
531
|
+
checkpointLoad(opts) {
|
|
532
|
+
try {
|
|
533
|
+
const projectId = opts.project || config_1.ConfigService.getInstance().getProjectId();
|
|
534
|
+
const checkpoint = this.memoryService.loadCheckpoint(projectId);
|
|
535
|
+
if (!checkpoint) {
|
|
536
|
+
console.log(`\nNo checkpoint found for project: ${projectId}\n`);
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
if (opts.json) {
|
|
540
|
+
console.log(JSON.stringify({ projectId, ...checkpoint }, null, 2));
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
const updatedDate = new Date(checkpoint.updated_at).toLocaleString();
|
|
544
|
+
console.log(`\n📌 Checkpoint for project: ${projectId}`);
|
|
545
|
+
console.log(` Updated: ${updatedDate}\n`);
|
|
546
|
+
console.log(` Completed: ${checkpoint.completed}`);
|
|
547
|
+
console.log(` Remaining: ${checkpoint.remaining}`);
|
|
548
|
+
console.log(` Blockers: ${checkpoint.blockers}`);
|
|
549
|
+
if (checkpoint.notes)
|
|
550
|
+
console.log(` Notes: ${checkpoint.notes}`);
|
|
551
|
+
console.log('');
|
|
552
|
+
}
|
|
553
|
+
catch (error) {
|
|
554
|
+
console.error('❌ Checkpoint load failed:', error);
|
|
555
|
+
process.exit(1);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Delete the task checkpoint for the current (or specified) project.
|
|
560
|
+
*/
|
|
561
|
+
checkpointClear(opts) {
|
|
562
|
+
try {
|
|
563
|
+
const projectId = opts.project || config_1.ConfigService.getInstance().getProjectId();
|
|
564
|
+
const deleted = this.memoryService.deleteCheckpoint(projectId);
|
|
565
|
+
if (deleted) {
|
|
566
|
+
console.log(`\n✅ Checkpoint cleared for project: ${projectId}\n`);
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
console.log(`\nNo checkpoint to clear for project: ${projectId}\n`);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
catch (error) {
|
|
573
|
+
console.error('❌ Checkpoint clear failed:', error);
|
|
574
|
+
process.exit(1);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
503
577
|
/**
|
|
504
578
|
* Show system status
|
|
505
579
|
*/
|
|
@@ -1394,6 +1468,48 @@ async function main() {
|
|
|
1394
1468
|
await cli.clear(options);
|
|
1395
1469
|
process.exit(0);
|
|
1396
1470
|
});
|
|
1471
|
+
// Checkpoint command group
|
|
1472
|
+
const checkpoint = program
|
|
1473
|
+
.command('checkpoint')
|
|
1474
|
+
.description('Save and load task checkpoints (work-in-progress snapshots)');
|
|
1475
|
+
checkpoint
|
|
1476
|
+
.command('save')
|
|
1477
|
+
.description('Save a task checkpoint for the current project (replaces previous)')
|
|
1478
|
+
.requiredOption('--completed <text>', 'What is done')
|
|
1479
|
+
.requiredOption('--remaining <text>', 'What is left to do')
|
|
1480
|
+
.option('--blockers <text>', 'Current blockers (default: "none")')
|
|
1481
|
+
.option('--notes <text>', 'Free-form notes, file refs, etc.')
|
|
1482
|
+
.option('--project <id>', 'Project ID (default: current)')
|
|
1483
|
+
.action((options) => {
|
|
1484
|
+
const cli = new ClaudeRecallCLI(program.opts());
|
|
1485
|
+
cli.checkpointSave({
|
|
1486
|
+
project: options.project,
|
|
1487
|
+
completed: options.completed,
|
|
1488
|
+
remaining: options.remaining,
|
|
1489
|
+
blockers: options.blockers,
|
|
1490
|
+
notes: options.notes,
|
|
1491
|
+
});
|
|
1492
|
+
process.exit(0);
|
|
1493
|
+
});
|
|
1494
|
+
checkpoint
|
|
1495
|
+
.command('load')
|
|
1496
|
+
.description('Load the latest task checkpoint for the current project')
|
|
1497
|
+
.option('--project <id>', 'Project ID (default: current)')
|
|
1498
|
+
.option('--json', 'Output as JSON')
|
|
1499
|
+
.action((options) => {
|
|
1500
|
+
const cli = new ClaudeRecallCLI(program.opts());
|
|
1501
|
+
cli.checkpointLoad({ project: options.project, json: options.json });
|
|
1502
|
+
process.exit(0);
|
|
1503
|
+
});
|
|
1504
|
+
checkpoint
|
|
1505
|
+
.command('clear')
|
|
1506
|
+
.description('Delete the task checkpoint for the current project')
|
|
1507
|
+
.option('--project <id>', 'Project ID (default: current)')
|
|
1508
|
+
.action((options) => {
|
|
1509
|
+
const cli = new ClaudeRecallCLI(program.opts());
|
|
1510
|
+
cli.checkpointClear({ project: options.project });
|
|
1511
|
+
process.exit(0);
|
|
1512
|
+
});
|
|
1397
1513
|
// Status command
|
|
1398
1514
|
program
|
|
1399
1515
|
.command('status')
|
|
@@ -162,7 +162,34 @@ class MemoryTools {
|
|
|
162
162
|
required: ['id']
|
|
163
163
|
},
|
|
164
164
|
handler: this.handleDeleteMemory.bind(this)
|
|
165
|
-
}
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: 'mcp__claude-recall__save_checkpoint',
|
|
168
|
+
description: 'Save a task checkpoint — a structured snapshot of work in progress (completed/remaining/blockers/notes). Replaces any previous checkpoint for this project. Call when ending a work session or pausing on a task.',
|
|
169
|
+
inputSchema: {
|
|
170
|
+
type: 'object',
|
|
171
|
+
properties: {
|
|
172
|
+
completed: { type: 'string', description: 'What has been finished in this work stream' },
|
|
173
|
+
remaining: { type: 'string', description: 'What is left to do' },
|
|
174
|
+
blockers: { type: 'string', description: 'Current blockers (use "none" if none)' },
|
|
175
|
+
notes: { type: 'string', description: 'Optional free-form notes, file references, etc.' },
|
|
176
|
+
projectId: { type: 'string', description: 'Optional project ID override. Defaults to current project.' },
|
|
177
|
+
},
|
|
178
|
+
required: ['completed', 'remaining', 'blockers'],
|
|
179
|
+
},
|
|
180
|
+
handler: this.handleSaveCheckpoint.bind(this),
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
name: 'mcp__claude-recall__load_checkpoint',
|
|
184
|
+
description: 'Load the latest task checkpoint for the current project. Returns null if none exists. Call at the start of a session to recall where you left off — load_rules will hint when one exists.',
|
|
185
|
+
inputSchema: {
|
|
186
|
+
type: 'object',
|
|
187
|
+
properties: {
|
|
188
|
+
projectId: { type: 'string', description: 'Optional project ID override. Defaults to current project.' },
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
handler: this.handleLoadCheckpoint.bind(this),
|
|
192
|
+
},
|
|
166
193
|
];
|
|
167
194
|
}
|
|
168
195
|
/**
|
|
@@ -349,15 +376,30 @@ class MemoryTools {
|
|
|
349
376
|
catch {
|
|
350
377
|
// Non-critical
|
|
351
378
|
}
|
|
379
|
+
// Checkpoint hint — surface existence without dumping content
|
|
380
|
+
let checkpointHint = '';
|
|
381
|
+
try {
|
|
382
|
+
const project = projectId || context.projectId || config_1.ConfigService.getInstance().getProjectId();
|
|
383
|
+
if (this.memoryService.hasCheckpoint(project)) {
|
|
384
|
+
const cp = this.memoryService.loadCheckpoint(project);
|
|
385
|
+
if (cp) {
|
|
386
|
+
const updatedDate = new Date(cp.updated_at).toLocaleString();
|
|
387
|
+
checkpointHint = `📌 You have an unfinished task checkpoint from ${updatedDate} — call \`load_checkpoint\` to see completed/remaining/blockers before starting work.\n\n`;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
catch {
|
|
392
|
+
// Non-critical
|
|
393
|
+
}
|
|
352
394
|
let rulesText;
|
|
353
395
|
if (sections.length > 0) {
|
|
354
396
|
const body = sections.join('\n\n');
|
|
355
397
|
rulesText = directive
|
|
356
|
-
? `${directive}\n\n---\n\n${body}`
|
|
357
|
-
: body
|
|
398
|
+
? `${directive}\n\n${checkpointHint}---\n\n${body}`
|
|
399
|
+
: `${checkpointHint}${body}`;
|
|
358
400
|
}
|
|
359
401
|
else {
|
|
360
|
-
rulesText = 'No active rules found. This may be a new project.';
|
|
402
|
+
rulesText = checkpointHint || 'No active rules found. This may be a new project.';
|
|
361
403
|
}
|
|
362
404
|
return {
|
|
363
405
|
rules: rulesText,
|
|
@@ -462,6 +504,45 @@ class MemoryTools {
|
|
|
462
504
|
throw error;
|
|
463
505
|
}
|
|
464
506
|
}
|
|
507
|
+
async handleSaveCheckpoint(input, context) {
|
|
508
|
+
try {
|
|
509
|
+
const { completed, remaining, blockers, notes, projectId } = input;
|
|
510
|
+
if (typeof completed !== 'string' || typeof remaining !== 'string' || typeof blockers !== 'string') {
|
|
511
|
+
throw new Error('completed, remaining, and blockers are required string fields');
|
|
512
|
+
}
|
|
513
|
+
const project = projectId || config_1.ConfigService.getInstance().getProjectId();
|
|
514
|
+
this.memoryService.saveCheckpoint(project, { completed, remaining, blockers, notes });
|
|
515
|
+
return {
|
|
516
|
+
success: true,
|
|
517
|
+
projectId: project,
|
|
518
|
+
message: `Checkpoint saved for project: ${project}`,
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
catch (error) {
|
|
522
|
+
this.logger.error('MemoryTools', 'Failed to save checkpoint', error);
|
|
523
|
+
throw error;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
async handleLoadCheckpoint(input, context) {
|
|
527
|
+
try {
|
|
528
|
+
const { projectId } = input || {};
|
|
529
|
+
const project = projectId || config_1.ConfigService.getInstance().getProjectId();
|
|
530
|
+
const checkpoint = this.memoryService.loadCheckpoint(project);
|
|
531
|
+
if (!checkpoint) {
|
|
532
|
+
return { found: false, projectId: project };
|
|
533
|
+
}
|
|
534
|
+
return {
|
|
535
|
+
found: true,
|
|
536
|
+
projectId: project,
|
|
537
|
+
...checkpoint,
|
|
538
|
+
updated_at_iso: new Date(checkpoint.updated_at).toISOString(),
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
catch (error) {
|
|
542
|
+
this.logger.error('MemoryTools', 'Failed to load checkpoint', error);
|
|
543
|
+
throw error;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
465
546
|
getTools() {
|
|
466
547
|
return this.tools;
|
|
467
548
|
}
|
package/dist/memory/storage.js
CHANGED
|
@@ -329,6 +329,51 @@ class MemoryStorage {
|
|
|
329
329
|
// This ensures that other processes (like CLI) can see the changes immediately
|
|
330
330
|
this.db.pragma('wal_checkpoint(TRUNCATE)');
|
|
331
331
|
}
|
|
332
|
+
// --- Task checkpoint methods ---
|
|
333
|
+
checkpointKey(projectId) {
|
|
334
|
+
return `task-checkpoint:${projectId}`;
|
|
335
|
+
}
|
|
336
|
+
saveCheckpoint(projectId, input) {
|
|
337
|
+
const checkpoint = {
|
|
338
|
+
completed: input.completed,
|
|
339
|
+
remaining: input.remaining,
|
|
340
|
+
blockers: input.blockers,
|
|
341
|
+
notes: input.notes,
|
|
342
|
+
updated_at: Date.now(),
|
|
343
|
+
};
|
|
344
|
+
// Use a deterministic key per project so INSERT OR REPLACE replaces the previous one.
|
|
345
|
+
// Direct INSERT OR REPLACE bypasses fuzzy/hash dedup since they check `key != ?`.
|
|
346
|
+
const stmt = this.db.prepare(`
|
|
347
|
+
INSERT OR REPLACE INTO memories
|
|
348
|
+
(key, value, type, project_id, file_path, timestamp, relevance_score, access_count,
|
|
349
|
+
preference_key, is_active, superseded_by, superseded_at, confidence_score, sophistication_level, scope, content_hash)
|
|
350
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
351
|
+
`);
|
|
352
|
+
const value = JSON.stringify(checkpoint);
|
|
353
|
+
const contentHash = this.computeContentHash(checkpoint, 'task-checkpoint');
|
|
354
|
+
stmt.run(this.checkpointKey(projectId), value, 'task-checkpoint', projectId, null, checkpoint.updated_at, 1.0, 0, null, 1, null, null, null, 1, null, contentHash);
|
|
355
|
+
this.db.pragma('wal_checkpoint(TRUNCATE)');
|
|
356
|
+
}
|
|
357
|
+
loadCheckpoint(projectId) {
|
|
358
|
+
const row = this.db.prepare('SELECT value FROM memories WHERE key = ? AND type = ?').get(this.checkpointKey(projectId), 'task-checkpoint');
|
|
359
|
+
if (!row)
|
|
360
|
+
return null;
|
|
361
|
+
try {
|
|
362
|
+
return JSON.parse(row.value);
|
|
363
|
+
}
|
|
364
|
+
catch {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
hasCheckpoint(projectId) {
|
|
369
|
+
const row = this.db.prepare('SELECT 1 FROM memories WHERE key = ? AND type = ?').get(this.checkpointKey(projectId), 'task-checkpoint');
|
|
370
|
+
return !!row;
|
|
371
|
+
}
|
|
372
|
+
deleteCheckpoint(projectId) {
|
|
373
|
+
const result = this.db.prepare('DELETE FROM memories WHERE key = ? AND type = ?').run(this.checkpointKey(projectId), 'task-checkpoint');
|
|
374
|
+
this.db.pragma('wal_checkpoint(TRUNCATE)');
|
|
375
|
+
return result.changes > 0;
|
|
376
|
+
}
|
|
332
377
|
retrieve(key) {
|
|
333
378
|
const stmt = this.db.prepare('SELECT * FROM memories WHERE key = ?');
|
|
334
379
|
const row = stmt.get(key);
|
package/dist/pi/extension.js
CHANGED
|
@@ -217,9 +217,21 @@ function default_1(pi) {
|
|
|
217
217
|
os.recordRetrieval(m.key);
|
|
218
218
|
}
|
|
219
219
|
catch { /* non-critical */ }
|
|
220
|
+
// Checkpoint hint — surface existence without dumping content
|
|
221
|
+
let checkpointHint = '';
|
|
222
|
+
try {
|
|
223
|
+
if (ms.hasCheckpoint(projectId)) {
|
|
224
|
+
const cp = ms.loadCheckpoint(projectId);
|
|
225
|
+
if (cp) {
|
|
226
|
+
const updatedDate = new Date(cp.updated_at).toLocaleString();
|
|
227
|
+
checkpointHint = `📌 You have an unfinished task checkpoint from ${updatedDate} — call \`recall_load_checkpoint\` to see completed/remaining/blockers before starting work.\n\n`;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
catch { /* non-critical */ }
|
|
220
232
|
const text = body
|
|
221
|
-
? `${LOAD_RULES_DIRECTIVE}\n\n---\n\n${body}`
|
|
222
|
-
: 'No active rules found. This may be a new project.';
|
|
233
|
+
? `${LOAD_RULES_DIRECTIVE}\n\n${checkpointHint}---\n\n${body}`
|
|
234
|
+
: (checkpointHint || 'No active rules found. This may be a new project.');
|
|
223
235
|
return {
|
|
224
236
|
content: [{ type: 'text', text }],
|
|
225
237
|
};
|
|
@@ -333,6 +345,73 @@ function default_1(pi) {
|
|
|
333
345
|
}
|
|
334
346
|
},
|
|
335
347
|
});
|
|
348
|
+
// --- Tool: recall_save_checkpoint ---
|
|
349
|
+
pi.registerTool({
|
|
350
|
+
name: 'recall_save_checkpoint',
|
|
351
|
+
label: 'Save Task Checkpoint',
|
|
352
|
+
description: 'Save a structured snapshot of work in progress (completed/remaining/blockers/notes). Replaces any previous checkpoint for this project. Call when ending a session or pausing on a task.',
|
|
353
|
+
promptSnippet: 'Save a task checkpoint with what is done, what remains, and any blockers',
|
|
354
|
+
parameters: {},
|
|
355
|
+
async execute(_id, params, _signal, _onUpdate, _ctx) {
|
|
356
|
+
try {
|
|
357
|
+
const { completed, remaining, blockers, notes } = params || {};
|
|
358
|
+
if (typeof completed !== 'string' || typeof remaining !== 'string' || typeof blockers !== 'string') {
|
|
359
|
+
return {
|
|
360
|
+
content: [{ type: 'text', text: 'Error: completed, remaining, and blockers are required string fields' }],
|
|
361
|
+
isError: true,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
const ms = memory_1.MemoryService.getInstance();
|
|
365
|
+
ms.saveCheckpoint(projectId, { completed, remaining, blockers, notes });
|
|
366
|
+
return {
|
|
367
|
+
content: [{ type: 'text', text: JSON.stringify({
|
|
368
|
+
success: true,
|
|
369
|
+
projectId,
|
|
370
|
+
message: `Checkpoint saved for project: ${projectId}`,
|
|
371
|
+
}) }],
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
catch (err) {
|
|
375
|
+
return {
|
|
376
|
+
content: [{ type: 'text', text: `Failed to save checkpoint: ${err.message}` }],
|
|
377
|
+
isError: true,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
});
|
|
382
|
+
// --- Tool: recall_load_checkpoint ---
|
|
383
|
+
pi.registerTool({
|
|
384
|
+
name: 'recall_load_checkpoint',
|
|
385
|
+
label: 'Load Task Checkpoint',
|
|
386
|
+
description: 'Load the latest task checkpoint for the current project. Returns null if none exists. Call at session start to recall where you left off.',
|
|
387
|
+
promptSnippet: 'Load the saved task checkpoint to see what was in progress',
|
|
388
|
+
parameters: {},
|
|
389
|
+
async execute(_id, _params, _signal, _onUpdate, _ctx) {
|
|
390
|
+
try {
|
|
391
|
+
const ms = memory_1.MemoryService.getInstance();
|
|
392
|
+
const checkpoint = ms.loadCheckpoint(projectId);
|
|
393
|
+
if (!checkpoint) {
|
|
394
|
+
return {
|
|
395
|
+
content: [{ type: 'text', text: JSON.stringify({ found: false, projectId }) }],
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
return {
|
|
399
|
+
content: [{ type: 'text', text: JSON.stringify({
|
|
400
|
+
found: true,
|
|
401
|
+
projectId,
|
|
402
|
+
...checkpoint,
|
|
403
|
+
updated_at_iso: new Date(checkpoint.updated_at).toISOString(),
|
|
404
|
+
}) }],
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
catch (err) {
|
|
408
|
+
return {
|
|
409
|
+
content: [{ type: 'text', text: `Failed to load checkpoint: ${err.message}` }],
|
|
410
|
+
isError: true,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
},
|
|
414
|
+
});
|
|
336
415
|
// --- Tool: recall_delete_memory ---
|
|
337
416
|
pi.registerTool({
|
|
338
417
|
name: 'recall_delete_memory',
|
package/dist/services/memory.js
CHANGED
|
@@ -527,6 +527,24 @@ class MemoryService {
|
|
|
527
527
|
getDatabase() {
|
|
528
528
|
return this.storage.getDatabase();
|
|
529
529
|
}
|
|
530
|
+
// --- Task checkpoint methods ---
|
|
531
|
+
saveCheckpoint(projectId, input) {
|
|
532
|
+
this.storage.saveCheckpoint(projectId, input);
|
|
533
|
+
this.logger.info('MemoryService', `Checkpoint saved for project: ${projectId}`);
|
|
534
|
+
}
|
|
535
|
+
loadCheckpoint(projectId) {
|
|
536
|
+
return this.storage.loadCheckpoint(projectId);
|
|
537
|
+
}
|
|
538
|
+
hasCheckpoint(projectId) {
|
|
539
|
+
return this.storage.hasCheckpoint(projectId);
|
|
540
|
+
}
|
|
541
|
+
deleteCheckpoint(projectId) {
|
|
542
|
+
const deleted = this.storage.deleteCheckpoint(projectId);
|
|
543
|
+
if (deleted) {
|
|
544
|
+
this.logger.info('MemoryService', `Checkpoint deleted for project: ${projectId}`);
|
|
545
|
+
}
|
|
546
|
+
return deleted;
|
|
547
|
+
}
|
|
530
548
|
/**
|
|
531
549
|
* Check if database is connected
|
|
532
550
|
*/
|
package/package.json
CHANGED