myagentmemory 0.4.4 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-memory +0 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +84 -1
- package/dist/core.d.ts +31 -1
- package/dist/core.js +141 -2
- package/package.json +2 -2
- package/skills/agent/SKILL.md +102 -53
- package/skills/claude-code/SKILL.md +98 -51
- package/skills/codex/SKILL.md +100 -53
- package/skills/cursor/SKILL.md +102 -53
- package/src/cli.ts +95 -0
- package/src/core.ts +167 -2
package/dist/agent-memory
CHANGED
|
Binary file
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* agent-memory CLI
|
|
4
4
|
*
|
|
5
5
|
* Subcommands:
|
|
6
|
+
* version — Print binary version
|
|
6
7
|
* context — Build & print context injection string to stdout
|
|
7
8
|
* write — Write to memory files
|
|
8
9
|
* read — Read memory files
|
|
@@ -16,7 +17,8 @@
|
|
|
16
17
|
* --json Machine-readable JSON output
|
|
17
18
|
*/
|
|
18
19
|
import * as fs from "node:fs";
|
|
19
|
-
|
|
20
|
+
const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : "dev";
|
|
21
|
+
import { _setBaseDir, buildMemoryContext, checkCollection, dailyPath, detectQmd, ensureDirs, ensureQmdAvailableForSync, ensureQmdAvailableForUpdate, getCollectionName, getDailyDir, getMemoryDir, getMemoryFile, getQmdEmbedMode, getQmdHealth, getQmdResultPath, getQmdResultText, getScratchpadFile, nowTimestamp, parseScratchpad, readFileSafe, runQmdEmbedDetached, runQmdSearch, runQmdSync, runQmdUpdateNow, scheduleQmdUpdate, searchRelevantMemories, serializeScratchpad, setupQmdCollection, todayStr, } from "./core.js";
|
|
20
22
|
function parseArgs(argv) {
|
|
21
23
|
const flags = {};
|
|
22
24
|
const positional = [];
|
|
@@ -319,18 +321,60 @@ async function cmdSearch(flags) {
|
|
|
319
321
|
exitError(`Search failed: ${err instanceof Error ? err.message : String(err)}`, json);
|
|
320
322
|
}
|
|
321
323
|
}
|
|
324
|
+
async function cmdSync(flags) {
|
|
325
|
+
const json = hasFlag(flags, "json");
|
|
326
|
+
ensureDirs();
|
|
327
|
+
const qmdFound = await ensureQmdAvailableForSync();
|
|
328
|
+
if (!qmdFound) {
|
|
329
|
+
exitError("qmd is not installed. Install: bun install -g https://github.com/tobi/qmd", json);
|
|
330
|
+
}
|
|
331
|
+
const collName = getCollectionName();
|
|
332
|
+
const hasCollection = await checkCollection(collName);
|
|
333
|
+
if (!hasCollection) {
|
|
334
|
+
exitError(`qmd collection '${collName}' not found. Run: agent-memory init`, json);
|
|
335
|
+
}
|
|
336
|
+
const result = await runQmdSync();
|
|
337
|
+
if (json) {
|
|
338
|
+
output({ ok: result.updateOk && result.embedOk, updateOk: result.updateOk, embedOk: result.embedOk }, true);
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
if (result.updateOk) {
|
|
342
|
+
console.log("qmd update: ok");
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
console.log("qmd update: failed");
|
|
346
|
+
}
|
|
347
|
+
if (result.embedOk) {
|
|
348
|
+
console.log("qmd embed: ok");
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
console.log("qmd embed: failed");
|
|
352
|
+
}
|
|
353
|
+
if (result.updateOk && result.embedOk) {
|
|
354
|
+
console.log("\nIndex fully synced.");
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
322
358
|
async function cmdInit(flags) {
|
|
323
359
|
const json = hasFlag(flags, "json");
|
|
324
360
|
ensureDirs();
|
|
325
361
|
const dir = getMemoryDir();
|
|
326
362
|
const qmdFound = await detectQmd();
|
|
327
363
|
let collectionCreated = false;
|
|
364
|
+
let indexUpdated = false;
|
|
365
|
+
let embedStarted = false;
|
|
328
366
|
if (qmdFound) {
|
|
329
367
|
const collName = getCollectionName();
|
|
330
368
|
const hasCollection = await checkCollection(collName);
|
|
331
369
|
if (!hasCollection) {
|
|
332
370
|
collectionCreated = await setupQmdCollection();
|
|
333
371
|
}
|
|
372
|
+
// Run initial index update + start background embed
|
|
373
|
+
await ensureQmdAvailableForUpdate();
|
|
374
|
+
await runQmdUpdateNow();
|
|
375
|
+
indexUpdated = true;
|
|
376
|
+
const child = runQmdEmbedDetached();
|
|
377
|
+
embedStarted = child !== null;
|
|
334
378
|
}
|
|
335
379
|
if (json) {
|
|
336
380
|
output({
|
|
@@ -338,6 +382,8 @@ async function cmdInit(flags) {
|
|
|
338
382
|
directory: dir,
|
|
339
383
|
qmd: qmdFound,
|
|
340
384
|
collectionCreated,
|
|
385
|
+
indexUpdated,
|
|
386
|
+
embedStarted,
|
|
341
387
|
}, true);
|
|
342
388
|
}
|
|
343
389
|
else {
|
|
@@ -350,6 +396,12 @@ async function cmdInit(flags) {
|
|
|
350
396
|
else {
|
|
351
397
|
console.log(` qmd collection '${getCollectionName()}' already exists.`);
|
|
352
398
|
}
|
|
399
|
+
if (indexUpdated) {
|
|
400
|
+
console.log(` Index updated.`);
|
|
401
|
+
}
|
|
402
|
+
if (embedStarted) {
|
|
403
|
+
console.log(` Embedding started in background.`);
|
|
404
|
+
}
|
|
353
405
|
}
|
|
354
406
|
else {
|
|
355
407
|
console.log(` qmd not found — search features unavailable.`);
|
|
@@ -375,9 +427,15 @@ async function cmdStatus(flags) {
|
|
|
375
427
|
}
|
|
376
428
|
const qmdFound = await detectQmd();
|
|
377
429
|
let hasCollection = false;
|
|
430
|
+
let health = null;
|
|
378
431
|
if (qmdFound) {
|
|
379
432
|
hasCollection = await checkCollection();
|
|
433
|
+
if (hasCollection) {
|
|
434
|
+
await ensureQmdAvailableForSync();
|
|
435
|
+
health = await getQmdHealth();
|
|
436
|
+
}
|
|
380
437
|
}
|
|
438
|
+
const embedMode = getQmdEmbedMode();
|
|
381
439
|
if (json) {
|
|
382
440
|
output({
|
|
383
441
|
directory: dir,
|
|
@@ -395,7 +453,9 @@ async function cmdStatus(flags) {
|
|
|
395
453
|
qmd: {
|
|
396
454
|
available: qmdFound,
|
|
397
455
|
collection: hasCollection ? getCollectionName() : null,
|
|
456
|
+
health,
|
|
398
457
|
},
|
|
458
|
+
embedMode,
|
|
399
459
|
}, true);
|
|
400
460
|
}
|
|
401
461
|
else {
|
|
@@ -421,6 +481,19 @@ async function cmdStatus(flags) {
|
|
|
421
481
|
if (qmdFound) {
|
|
422
482
|
console.log(`qmd: available`);
|
|
423
483
|
console.log(`Collection '${getCollectionName()}': ${hasCollection ? "configured" : "not configured — run: agent-memory init"}`);
|
|
484
|
+
console.log(`Embed mode: ${embedMode}`);
|
|
485
|
+
if (health) {
|
|
486
|
+
if (health.totalFiles !== null)
|
|
487
|
+
console.log(`Files indexed: ${health.totalFiles}`);
|
|
488
|
+
if (health.vectorsEmbedded !== null)
|
|
489
|
+
console.log(`Vectors embedded: ${health.vectorsEmbedded}`);
|
|
490
|
+
if (health.pendingEmbed !== null && health.pendingEmbed > 0) {
|
|
491
|
+
console.log(`Pending embeds: ${health.pendingEmbed}`);
|
|
492
|
+
console.log(` run: agent-memory sync`);
|
|
493
|
+
}
|
|
494
|
+
if (health.lastUpdated)
|
|
495
|
+
console.log(`Last updated: ${health.lastUpdated}`);
|
|
496
|
+
}
|
|
424
497
|
}
|
|
425
498
|
else {
|
|
426
499
|
console.log("qmd: not installed");
|
|
@@ -437,11 +510,13 @@ Usage:
|
|
|
437
510
|
agent-memory <command> [options]
|
|
438
511
|
|
|
439
512
|
Commands:
|
|
513
|
+
version Show binary version
|
|
440
514
|
context Build & print context injection string
|
|
441
515
|
write Write to memory files
|
|
442
516
|
read Read memory files
|
|
443
517
|
scratchpad Manage checklist items
|
|
444
518
|
search Search across memory files (requires qmd)
|
|
519
|
+
sync Re-index and embed all files (requires qmd)
|
|
445
520
|
init Initialize memory directory and qmd collection
|
|
446
521
|
status Show configuration and status
|
|
447
522
|
|
|
@@ -461,6 +536,7 @@ Examples:
|
|
|
461
536
|
agent-memory scratchpad done --text "PR #42"
|
|
462
537
|
agent-memory search --query "database choice" --mode keyword
|
|
463
538
|
agent-memory context --no-search
|
|
539
|
+
agent-memory sync
|
|
464
540
|
agent-memory status --json`);
|
|
465
541
|
}
|
|
466
542
|
// ---------------------------------------------------------------------------
|
|
@@ -474,6 +550,10 @@ async function main() {
|
|
|
474
550
|
if (dir) {
|
|
475
551
|
_setBaseDir(dir);
|
|
476
552
|
}
|
|
553
|
+
if (command === "version" || hasFlag(flags, "version")) {
|
|
554
|
+
output(json ? { version: VERSION } : VERSION, json);
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
477
557
|
if (!command || command === "help" || hasFlag(flags, "help")) {
|
|
478
558
|
printUsage();
|
|
479
559
|
return;
|
|
@@ -494,6 +574,9 @@ async function main() {
|
|
|
494
574
|
case "search":
|
|
495
575
|
await cmdSearch(flags);
|
|
496
576
|
break;
|
|
577
|
+
case "sync":
|
|
578
|
+
await cmdSync(flags);
|
|
579
|
+
break;
|
|
497
580
|
case "init":
|
|
498
581
|
await cmdInit(flags);
|
|
499
582
|
break;
|
package/dist/core.d.ts
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* Core logic for agent-memory CLI and skills.
|
|
5
5
|
* Zero pi peer dependencies — only node:fs, node:path, node:child_process.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import type { ChildProcess } from "node:child_process";
|
|
8
|
+
import { execFile, spawn } from "node:child_process";
|
|
8
9
|
/** Override base directory (for testing or platform-specific defaults). */
|
|
9
10
|
export declare function _setBaseDir(baseDir: string): void;
|
|
10
11
|
/** Reset to default paths. */
|
|
@@ -59,10 +60,15 @@ export declare function parseScratchpad(content: string): ScratchpadItem[];
|
|
|
59
60
|
export declare function serializeScratchpad(items: ScratchpadItem[]): string;
|
|
60
61
|
export declare function buildMemoryContext(searchResults?: string): string;
|
|
61
62
|
type ExecFileFn = typeof execFile;
|
|
63
|
+
type SpawnFn = typeof spawn;
|
|
62
64
|
/** Override execFile implementation (for testing). */
|
|
63
65
|
export declare function _setExecFileForTest(fn: ExecFileFn): void;
|
|
64
66
|
/** Reset execFile implementation (for testing). */
|
|
65
67
|
export declare function _resetExecFileForTest(): void;
|
|
68
|
+
/** Override spawn implementation (for testing). */
|
|
69
|
+
export declare function _setSpawnForTest(fn: SpawnFn): void;
|
|
70
|
+
/** Reset spawn implementation (for testing). */
|
|
71
|
+
export declare function _resetSpawnForTest(): void;
|
|
66
72
|
/** Set qmd availability flag (for testing). */
|
|
67
73
|
export declare function _setQmdAvailable(value: boolean): void;
|
|
68
74
|
/** Get current qmd availability flag. */
|
|
@@ -71,6 +77,10 @@ export declare function _getQmdAvailable(): boolean;
|
|
|
71
77
|
export declare function _getUpdateTimer(): ReturnType<typeof setTimeout> | null;
|
|
72
78
|
/** Clear the update timer (for testing). */
|
|
73
79
|
export declare function _clearUpdateTimer(): void;
|
|
80
|
+
/** Get current embed timer (for testing). */
|
|
81
|
+
export declare function _getEmbedTimer(): ReturnType<typeof setTimeout> | null;
|
|
82
|
+
/** Clear the embed timer (for testing). */
|
|
83
|
+
export declare function _clearEmbedTimer(): void;
|
|
74
84
|
/** Get the current QMD collection name. */
|
|
75
85
|
export declare function getCollectionName(): string;
|
|
76
86
|
/** Set the QMD collection name (for platform-specific overrides). */
|
|
@@ -83,8 +93,28 @@ export declare function detectQmd(): Promise<boolean>;
|
|
|
83
93
|
export declare function checkCollection(name?: string): Promise<boolean>;
|
|
84
94
|
export declare function getQmdUpdateMode(): "background" | "manual" | "off";
|
|
85
95
|
export declare function ensureQmdAvailableForUpdate(): Promise<boolean>;
|
|
96
|
+
export declare function getQmdEmbedMode(): "background" | "manual" | "off";
|
|
97
|
+
export declare function runQmdEmbedDetached(): ChildProcess | null;
|
|
98
|
+
export declare function scheduleQmdEmbed(): void;
|
|
86
99
|
export declare function scheduleQmdUpdate(): void;
|
|
87
100
|
export declare function runQmdUpdateNow(): Promise<void>;
|
|
101
|
+
export declare function runQmdEmbedNow(): Promise<boolean>;
|
|
102
|
+
export declare function ensureQmdAvailableForSync(): Promise<boolean>;
|
|
103
|
+
export declare function runQmdSync(): Promise<{
|
|
104
|
+
updateOk: boolean;
|
|
105
|
+
embedOk: boolean;
|
|
106
|
+
}>;
|
|
107
|
+
export interface QmdHealthInfo {
|
|
108
|
+
totalFiles: number | null;
|
|
109
|
+
vectorsEmbedded: number | null;
|
|
110
|
+
pendingEmbed: number | null;
|
|
111
|
+
lastUpdated: string | null;
|
|
112
|
+
collectionFiles: number | null;
|
|
113
|
+
collectionUpdated: string | null;
|
|
114
|
+
embedMode: string;
|
|
115
|
+
}
|
|
116
|
+
export declare function parseQmdStatus(stdout: string, collectionName: string): QmdHealthInfo;
|
|
117
|
+
export declare function getQmdHealth(): Promise<QmdHealthInfo | null>;
|
|
88
118
|
/** Search for memories relevant to the user's prompt. Returns formatted markdown or empty string on error. */
|
|
89
119
|
export declare function searchRelevantMemories(prompt: string): Promise<string>;
|
|
90
120
|
export interface QmdSearchResult {
|
package/dist/core.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Core logic for agent-memory CLI and skills.
|
|
5
5
|
* Zero pi peer dependencies — only node:fs, node:path, node:child_process.
|
|
6
6
|
*/
|
|
7
|
-
import { execFile } from "node:child_process";
|
|
7
|
+
import { execFile, spawn } from "node:child_process";
|
|
8
8
|
import * as fs from "node:fs";
|
|
9
9
|
import * as path from "node:path";
|
|
10
10
|
// ---------------------------------------------------------------------------
|
|
@@ -280,8 +280,10 @@ export function buildMemoryContext(searchResults) {
|
|
|
280
280
|
return context;
|
|
281
281
|
}
|
|
282
282
|
let execFileFn = execFile;
|
|
283
|
+
let spawnFn = spawn;
|
|
283
284
|
let qmdAvailable = false;
|
|
284
285
|
let updateTimer = null;
|
|
286
|
+
let embedTimer = null;
|
|
285
287
|
/** QMD collection name — configurable per platform. */
|
|
286
288
|
let QMD_COLLECTION_NAME = "agent-memory";
|
|
287
289
|
/** Override execFile implementation (for testing). */
|
|
@@ -292,6 +294,14 @@ export function _setExecFileForTest(fn) {
|
|
|
292
294
|
export function _resetExecFileForTest() {
|
|
293
295
|
execFileFn = execFile;
|
|
294
296
|
}
|
|
297
|
+
/** Override spawn implementation (for testing). */
|
|
298
|
+
export function _setSpawnForTest(fn) {
|
|
299
|
+
spawnFn = fn;
|
|
300
|
+
}
|
|
301
|
+
/** Reset spawn implementation (for testing). */
|
|
302
|
+
export function _resetSpawnForTest() {
|
|
303
|
+
spawnFn = spawn;
|
|
304
|
+
}
|
|
295
305
|
/** Set qmd availability flag (for testing). */
|
|
296
306
|
export function _setQmdAvailable(value) {
|
|
297
307
|
qmdAvailable = value;
|
|
@@ -311,6 +321,17 @@ export function _clearUpdateTimer() {
|
|
|
311
321
|
updateTimer = null;
|
|
312
322
|
}
|
|
313
323
|
}
|
|
324
|
+
/** Get current embed timer (for testing). */
|
|
325
|
+
export function _getEmbedTimer() {
|
|
326
|
+
return embedTimer;
|
|
327
|
+
}
|
|
328
|
+
/** Clear the embed timer (for testing). */
|
|
329
|
+
export function _clearEmbedTimer() {
|
|
330
|
+
if (embedTimer) {
|
|
331
|
+
clearTimeout(embedTimer);
|
|
332
|
+
embedTimer = null;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
314
335
|
/** Get the current QMD collection name. */
|
|
315
336
|
export function getCollectionName() {
|
|
316
337
|
return QMD_COLLECTION_NAME;
|
|
@@ -425,6 +446,39 @@ export async function ensureQmdAvailableForUpdate() {
|
|
|
425
446
|
qmdAvailable = await detectQmd();
|
|
426
447
|
return qmdAvailable;
|
|
427
448
|
}
|
|
449
|
+
export function getQmdEmbedMode() {
|
|
450
|
+
const mode = (process.env.AGENT_MEMORY_QMD_EMBED ?? "background").toLowerCase();
|
|
451
|
+
if (mode === "manual" || mode === "off" || mode === "background") {
|
|
452
|
+
return mode;
|
|
453
|
+
}
|
|
454
|
+
return "background";
|
|
455
|
+
}
|
|
456
|
+
export function runQmdEmbedDetached() {
|
|
457
|
+
if (!qmdAvailable)
|
|
458
|
+
return null;
|
|
459
|
+
const child = spawnFn("qmd", ["embed"], {
|
|
460
|
+
detached: true,
|
|
461
|
+
stdio: "ignore",
|
|
462
|
+
});
|
|
463
|
+
child.unref();
|
|
464
|
+
return child;
|
|
465
|
+
}
|
|
466
|
+
export function scheduleQmdEmbed() {
|
|
467
|
+
if (getQmdEmbedMode() !== "background")
|
|
468
|
+
return;
|
|
469
|
+
if (!qmdAvailable)
|
|
470
|
+
return;
|
|
471
|
+
if (embedTimer)
|
|
472
|
+
clearTimeout(embedTimer);
|
|
473
|
+
embedTimer = setTimeout(() => {
|
|
474
|
+
embedTimer = null;
|
|
475
|
+
runQmdEmbedDetached();
|
|
476
|
+
}, 5_000);
|
|
477
|
+
// Don't prevent process exit while waiting to embed
|
|
478
|
+
if (embedTimer && typeof embedTimer === "object" && "unref" in embedTimer) {
|
|
479
|
+
embedTimer.unref();
|
|
480
|
+
}
|
|
481
|
+
}
|
|
428
482
|
export function scheduleQmdUpdate() {
|
|
429
483
|
if (getQmdUpdateMode() !== "background")
|
|
430
484
|
return;
|
|
@@ -434,7 +488,9 @@ export function scheduleQmdUpdate() {
|
|
|
434
488
|
clearTimeout(updateTimer);
|
|
435
489
|
updateTimer = setTimeout(() => {
|
|
436
490
|
updateTimer = null;
|
|
437
|
-
execFileFn("qmd", ["update"], { timeout: 30_000 }, () => {
|
|
491
|
+
execFileFn("qmd", ["update"], { timeout: 30_000 }, () => {
|
|
492
|
+
scheduleQmdEmbed();
|
|
493
|
+
});
|
|
438
494
|
}, 500);
|
|
439
495
|
}
|
|
440
496
|
export async function runQmdUpdateNow() {
|
|
@@ -446,6 +502,89 @@ export async function runQmdUpdateNow() {
|
|
|
446
502
|
execFileFn("qmd", ["update"], { timeout: 30_000 }, () => resolve());
|
|
447
503
|
});
|
|
448
504
|
}
|
|
505
|
+
export async function runQmdEmbedNow() {
|
|
506
|
+
if (!qmdAvailable)
|
|
507
|
+
return false;
|
|
508
|
+
return new Promise((resolve) => {
|
|
509
|
+
execFileFn("qmd", ["embed"], { timeout: 120_000 }, (err) => {
|
|
510
|
+
resolve(!err);
|
|
511
|
+
});
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
export async function ensureQmdAvailableForSync() {
|
|
515
|
+
if (qmdAvailable)
|
|
516
|
+
return true;
|
|
517
|
+
qmdAvailable = await detectQmd();
|
|
518
|
+
return qmdAvailable;
|
|
519
|
+
}
|
|
520
|
+
export async function runQmdSync() {
|
|
521
|
+
if (!qmdAvailable)
|
|
522
|
+
return { updateOk: false, embedOk: false };
|
|
523
|
+
const updateOk = await new Promise((resolve) => {
|
|
524
|
+
execFileFn("qmd", ["update"], { timeout: 30_000 }, (err) => {
|
|
525
|
+
resolve(!err);
|
|
526
|
+
});
|
|
527
|
+
});
|
|
528
|
+
const embedOk = await runQmdEmbedNow();
|
|
529
|
+
return { updateOk, embedOk };
|
|
530
|
+
}
|
|
531
|
+
export function parseQmdStatus(stdout, collectionName) {
|
|
532
|
+
const result = {
|
|
533
|
+
totalFiles: null,
|
|
534
|
+
vectorsEmbedded: null,
|
|
535
|
+
pendingEmbed: null,
|
|
536
|
+
lastUpdated: null,
|
|
537
|
+
collectionFiles: null,
|
|
538
|
+
collectionUpdated: null,
|
|
539
|
+
embedMode: getQmdEmbedMode(),
|
|
540
|
+
};
|
|
541
|
+
if (!stdout.trim())
|
|
542
|
+
return result;
|
|
543
|
+
// Total files across all collections
|
|
544
|
+
const totalFilesMatch = stdout.match(/(\d+)\s+(?:total\s+)?files?/i);
|
|
545
|
+
if (totalFilesMatch) {
|
|
546
|
+
result.totalFiles = Number.parseInt(totalFilesMatch[1], 10);
|
|
547
|
+
}
|
|
548
|
+
// Vectors / embeddings
|
|
549
|
+
const vectorsMatch = stdout.match(/(\d+)\s+(?:vectors?|embeddings?)/i);
|
|
550
|
+
if (vectorsMatch) {
|
|
551
|
+
result.vectorsEmbedded = Number.parseInt(vectorsMatch[1], 10);
|
|
552
|
+
}
|
|
553
|
+
// Pending embed
|
|
554
|
+
const pendingMatch = stdout.match(/(\d+)\s+pending/i);
|
|
555
|
+
if (pendingMatch) {
|
|
556
|
+
result.pendingEmbed = Number.parseInt(pendingMatch[1], 10);
|
|
557
|
+
}
|
|
558
|
+
// If we have totalFiles and vectorsEmbedded but no explicit pending, infer it
|
|
559
|
+
if (result.pendingEmbed === null && result.totalFiles !== null && result.vectorsEmbedded !== null) {
|
|
560
|
+
result.pendingEmbed = Math.max(0, result.totalFiles - result.vectorsEmbedded);
|
|
561
|
+
}
|
|
562
|
+
// Last updated timestamp
|
|
563
|
+
const updatedMatch = stdout.match(/(?:last\s+)?updated:?\s+(\d{4}-\d{2}-\d{2}[\sT]\d{2}:\d{2}[:\d]*)/i);
|
|
564
|
+
if (updatedMatch) {
|
|
565
|
+
result.lastUpdated = updatedMatch[1];
|
|
566
|
+
}
|
|
567
|
+
// Collection-specific info — look for collection name section
|
|
568
|
+
const collectionPattern = new RegExp(`${collectionName}[:\\s]*(?:.*?)(\\d+)\\s+files?`, "i");
|
|
569
|
+
const collMatch = stdout.match(collectionPattern);
|
|
570
|
+
if (collMatch) {
|
|
571
|
+
result.collectionFiles = Number.parseInt(collMatch[1], 10);
|
|
572
|
+
}
|
|
573
|
+
return result;
|
|
574
|
+
}
|
|
575
|
+
export async function getQmdHealth() {
|
|
576
|
+
if (!qmdAvailable)
|
|
577
|
+
return null;
|
|
578
|
+
return new Promise((resolve) => {
|
|
579
|
+
execFileFn("qmd", ["status"], { timeout: 10_000 }, (err, stdout) => {
|
|
580
|
+
if (err) {
|
|
581
|
+
resolve(null);
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
resolve(parseQmdStatus(stdout ?? "", QMD_COLLECTION_NAME));
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
}
|
|
449
588
|
/** Search for memories relevant to the user's prompt. Returns formatted markdown or empty string on error. */
|
|
450
589
|
export async function searchRelevantMemories(prompt) {
|
|
451
590
|
if (!qmdAvailable || !prompt.trim())
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "myagentmemory",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "Persistent memory for coding agents (Claude Code, Codex, Cursor, Agent) with qmd-powered semantic search across daily logs, long-term memory, and scratchpad",
|
|
5
5
|
"main": "./dist/core.js",
|
|
6
6
|
"types": "./dist/core.d.ts",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"postinstall": "node scripts/postinstall.cjs",
|
|
53
53
|
"build": "tsc -p tsconfig.json --noEmit",
|
|
54
54
|
"build:lib": "tsc -p tsconfig.build.json",
|
|
55
|
-
"build:cli": "bun build src/cli.ts --compile --outfile dist/agent-memory",
|
|
55
|
+
"build:cli": "bun build src/cli.ts --compile --outfile dist/agent-memory --define __VERSION__=\"'$(node -p \"require('./package.json').version\")'\"",
|
|
56
56
|
"prepack": "npm run build:lib && bun run build:cli",
|
|
57
57
|
"lint": "biome check .",
|
|
58
58
|
"test": "bun test test/unit.test.ts",
|