myagentmemory 0.4.5 → 0.4.6

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 CHANGED
@@ -23,8 +23,7 @@ bun run build:cli
23
23
  agent-memory init
24
24
 
25
25
  # Install skill files for Claude Code, Codex, Cursor, and Agent
26
- bash scripts/install-skills.sh
27
- pwsh -File scripts/install-skills.ps1
26
+ agent-memory install-skills
28
27
  ```
29
28
 
30
29
  This installs:
@@ -84,6 +83,7 @@ The memory directory defaults to `~/.agent-memory/`. Override with `AGENT_MEMORY
84
83
  | `agent-memory read --target <long_term\|scratchpad\|daily\|list> [--date YYYY-MM-DD]` | Read memory files |
85
84
  | `agent-memory scratchpad <add\|done\|undo\|clear_done\|list> [--text <text>]` | Manage checklist |
86
85
  | `agent-memory search --query <text> [--mode keyword\|semantic\|deep] [--limit N]` | Search via qmd |
86
+ | `agent-memory install-skills` | Install bundled SKILL.md files into local agent directories |
87
87
  | `agent-memory init` | Create dirs, detect qmd, setup collection |
88
88
  | `agent-memory status` | Show config, qmd status, file counts |
89
89
 
@@ -186,8 +186,7 @@ bun run build:cli
186
186
  agent-memory write --target long_term --content "test" && agent-memory read --target long_term
187
187
 
188
188
  # Install skills
189
- bash scripts/install-skills.sh
190
- pwsh -File scripts/install-skills.ps1
189
+ agent-memory install-skills
191
190
  ```
192
191
 
193
192
  ## Publishing (maintainers)
package/dist/agent-memory CHANGED
Binary file
package/dist/cli.d.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  *
5
5
  * Subcommands:
6
6
  * version — Print binary version
7
+ * install-skills — Install SKILL.md files into local agent directories
7
8
  * context — Build & print context injection string to stdout
8
9
  * write — Write to memory files
9
10
  * read — Read memory files
package/dist/cli.js CHANGED
@@ -4,6 +4,7 @@
4
4
  *
5
5
  * Subcommands:
6
6
  * version — Print binary version
7
+ * install-skills — Install SKILL.md files into local agent directories
7
8
  * context — Build & print context injection string to stdout
8
9
  * write — Write to memory files
9
10
  * read — Read memory files
@@ -18,7 +19,7 @@
18
19
  */
19
20
  import * as fs from "node:fs";
20
21
  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";
22
+ import { _setBaseDir, buildMemoryContext, checkCollection, dailyPath, detectQmd, ensureDirs, ensureQmdAvailableForSync, ensureQmdAvailableForUpdate, getCollectionName, getDailyDir, getMemoryDir, getMemoryFile, getQmdEmbedMode, getQmdHealth, getQmdResultPath, getQmdResultText, getScratchpadFile, installSkills, nowTimestamp, parseScratchpad, readFileSafe, runQmdEmbedDetached, runQmdSearch, runQmdSync, runQmdUpdateNow, scheduleQmdUpdate, searchRelevantMemories, serializeScratchpad, setupQmdCollection, todayStr, } from "./core.js";
22
23
  function parseArgs(argv) {
23
24
  const flags = {};
24
25
  const positional = [];
@@ -321,6 +322,37 @@ async function cmdSearch(flags) {
321
322
  exitError(`Search failed: ${err instanceof Error ? err.message : String(err)}`, json);
322
323
  }
323
324
  }
325
+ function cmdInstallSkills(flags) {
326
+ const json = hasFlag(flags, "json");
327
+ const report = installSkills();
328
+ if (!report.ok) {
329
+ exitError(report.error ?? "Failed to install skills.", json);
330
+ }
331
+ if (json) {
332
+ output(report, true);
333
+ return;
334
+ }
335
+ if (report.detected.length === 0) {
336
+ console.log("No supported agent installations detected.");
337
+ }
338
+ else {
339
+ const detectedLabels = report.detected.map((item) => item.label).join(", ");
340
+ console.log(`Detected: ${detectedLabels}`);
341
+ }
342
+ if (report.installed.length === 0) {
343
+ console.log("No skills installed.");
344
+ }
345
+ else {
346
+ for (const item of report.installed) {
347
+ console.log(`Installed ${item.label}: ${item.path}`);
348
+ }
349
+ }
350
+ if (report.skipped.length > 0) {
351
+ for (const item of report.skipped) {
352
+ console.log(`Skipped ${item.label} (${item.reason})`);
353
+ }
354
+ }
355
+ }
324
356
  async function cmdSync(flags) {
325
357
  const json = hasFlag(flags, "json");
326
358
  ensureDirs();
@@ -511,6 +543,7 @@ Usage:
511
543
 
512
544
  Commands:
513
545
  version Show binary version
546
+ install-skills Install bundled skills into local agent directories
514
547
  context Build & print context injection string
515
548
  write Write to memory files
516
549
  read Read memory files
@@ -574,6 +607,9 @@ async function main() {
574
607
  case "search":
575
608
  await cmdSearch(flags);
576
609
  break;
610
+ case "install-skills":
611
+ cmdInstallSkills(flags);
612
+ break;
577
613
  case "sync":
578
614
  await cmdSync(flags);
579
615
  break;
package/dist/core.d.ts CHANGED
@@ -65,6 +65,10 @@ type SpawnFn = typeof spawn;
65
65
  export declare function _setExecFileForTest(fn: ExecFileFn): void;
66
66
  /** Reset execFile implementation (for testing). */
67
67
  export declare function _resetExecFileForTest(): void;
68
+ /** Override skills root directory (for testing). */
69
+ export declare function _setSkillsRootForTest(dir: string | null): void;
70
+ /** Override home directory (for testing). */
71
+ export declare function _setHomeDirForTest(dir: string | null): void;
68
72
  /** Override spawn implementation (for testing). */
69
73
  export declare function _setSpawnForTest(fn: SpawnFn): void;
70
74
  /** Reset spawn implementation (for testing). */
@@ -104,6 +108,25 @@ export declare function runQmdSync(): Promise<{
104
108
  updateOk: boolean;
105
109
  embedOk: boolean;
106
110
  }>;
111
+ export interface InstallSkillsReport {
112
+ ok: boolean;
113
+ projectDir?: string;
114
+ homeDir?: string;
115
+ detected: Array<{
116
+ label: string;
117
+ homeMarker: string;
118
+ }>;
119
+ installed: Array<{
120
+ label: string;
121
+ path: string;
122
+ }>;
123
+ skipped: Array<{
124
+ label: string;
125
+ reason: string;
126
+ }>;
127
+ error?: string;
128
+ }
129
+ export declare function installSkills(): InstallSkillsReport;
107
130
  export interface QmdHealthInfo {
108
131
  totalFiles: number | null;
109
132
  vectorsEmbedded: number | null;
package/dist/core.js CHANGED
@@ -284,6 +284,8 @@ let spawnFn = spawn;
284
284
  let qmdAvailable = false;
285
285
  let updateTimer = null;
286
286
  let embedTimer = null;
287
+ let skillsRootOverride = null;
288
+ let homeDirOverride = null;
287
289
  /** QMD collection name — configurable per platform. */
288
290
  let QMD_COLLECTION_NAME = "agent-memory";
289
291
  /** Override execFile implementation (for testing). */
@@ -294,6 +296,14 @@ export function _setExecFileForTest(fn) {
294
296
  export function _resetExecFileForTest() {
295
297
  execFileFn = execFile;
296
298
  }
299
+ /** Override skills root directory (for testing). */
300
+ export function _setSkillsRootForTest(dir) {
301
+ skillsRootOverride = dir;
302
+ }
303
+ /** Override home directory (for testing). */
304
+ export function _setHomeDirForTest(dir) {
305
+ homeDirOverride = dir;
306
+ }
297
307
  /** Override spawn implementation (for testing). */
298
308
  export function _setSpawnForTest(fn) {
299
309
  spawnFn = fn;
@@ -332,6 +342,40 @@ export function _clearEmbedTimer() {
332
342
  embedTimer = null;
333
343
  }
334
344
  }
345
+ function resolveHomeDir() {
346
+ if (homeDirOverride !== null)
347
+ return homeDirOverride;
348
+ return process.env.HOME ?? process.env.USERPROFILE ?? null;
349
+ }
350
+ function findSkillsRoot() {
351
+ const envRoot = process.env.AGENT_MEMORY_SKILLS_ROOT;
352
+ if (envRoot)
353
+ return envRoot;
354
+ if (skillsRootOverride)
355
+ return skillsRootOverride;
356
+ const scanUp = (startDir) => {
357
+ let dir = startDir;
358
+ while (true) {
359
+ if (fs.existsSync(path.join(dir, "skills")))
360
+ return dir;
361
+ const parent = path.dirname(dir);
362
+ if (parent === dir)
363
+ return null;
364
+ dir = parent;
365
+ }
366
+ };
367
+ const argvPath = process.argv[1];
368
+ if (argvPath) {
369
+ const found = scanUp(path.resolve(path.dirname(argvPath)));
370
+ if (found)
371
+ return found;
372
+ }
373
+ const execDir = path.dirname(process.execPath);
374
+ const found = scanUp(path.resolve(execDir));
375
+ if (found)
376
+ return found;
377
+ return scanUp(path.resolve(process.cwd()));
378
+ }
335
379
  /** Get the current QMD collection name. */
336
380
  export function getCollectionName() {
337
381
  return QMD_COLLECTION_NAME;
@@ -528,6 +572,93 @@ export async function runQmdSync() {
528
572
  const embedOk = await runQmdEmbedNow();
529
573
  return { updateOk, embedOk };
530
574
  }
575
+ export function installSkills() {
576
+ const homeDir = resolveHomeDir();
577
+ if (!homeDir) {
578
+ return {
579
+ ok: false,
580
+ detected: [],
581
+ installed: [],
582
+ skipped: [],
583
+ error: "Home directory not found. Set HOME (or USERPROFILE on Windows) and retry.",
584
+ };
585
+ }
586
+ const projectDir = findSkillsRoot();
587
+ if (!projectDir) {
588
+ return {
589
+ ok: false,
590
+ homeDir,
591
+ detected: [],
592
+ installed: [],
593
+ skipped: [],
594
+ error: "Could not locate the skills directory. Ensure the package includes skills/ (reinstall if needed).",
595
+ };
596
+ }
597
+ const skillsDir = path.join(projectDir, "skills");
598
+ if (!fs.existsSync(skillsDir)) {
599
+ return {
600
+ ok: false,
601
+ projectDir,
602
+ homeDir,
603
+ detected: [],
604
+ installed: [],
605
+ skipped: [],
606
+ error: `Skills directory not found: ${skillsDir}`,
607
+ };
608
+ }
609
+ const targets = [
610
+ {
611
+ label: "Claude Code skill",
612
+ srcDir: path.join(skillsDir, "claude-code"),
613
+ destDir: path.join(homeDir, ".claude", "skills", "agent-memory"),
614
+ homeMarker: path.join(homeDir, ".claude"),
615
+ },
616
+ {
617
+ label: "Codex skill",
618
+ srcDir: path.join(skillsDir, "codex"),
619
+ destDir: path.join(homeDir, ".codex", "skills", "agent-memory"),
620
+ homeMarker: path.join(homeDir, ".codex"),
621
+ },
622
+ {
623
+ label: "Cursor skill",
624
+ srcDir: path.join(skillsDir, "cursor"),
625
+ destDir: path.join(homeDir, ".cursor", "skills", "agent-memory"),
626
+ homeMarker: path.join(homeDir, ".cursor"),
627
+ },
628
+ {
629
+ label: "Agent CLI skill",
630
+ srcDir: path.join(skillsDir, "agent"),
631
+ destDir: path.join(homeDir, ".agents", "skills", "agent-memory"),
632
+ homeMarker: path.join(homeDir, ".agents"),
633
+ },
634
+ ];
635
+ const detected = [];
636
+ const installed = [];
637
+ const skipped = [];
638
+ for (const target of targets) {
639
+ if (!fs.existsSync(target.homeMarker)) {
640
+ skipped.push({ label: target.label, reason: `${target.homeMarker} not found` });
641
+ continue;
642
+ }
643
+ detected.push({ label: target.label, homeMarker: target.homeMarker });
644
+ const skillFile = path.join(target.srcDir, "SKILL.md");
645
+ if (!fs.existsSync(skillFile)) {
646
+ skipped.push({ label: target.label, reason: `${skillFile} not found` });
647
+ continue;
648
+ }
649
+ fs.mkdirSync(target.destDir, { recursive: true });
650
+ fs.copyFileSync(skillFile, path.join(target.destDir, "SKILL.md"));
651
+ installed.push({ label: target.label, path: path.join(target.destDir, "SKILL.md") });
652
+ }
653
+ return {
654
+ ok: true,
655
+ projectDir,
656
+ homeDir,
657
+ detected,
658
+ installed,
659
+ skipped,
660
+ };
661
+ }
531
662
  export function parseQmdStatus(stdout, collectionName) {
532
663
  const result = {
533
664
  totalFiles: null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myagentmemory",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
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",
package/src/cli.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  *
5
5
  * Subcommands:
6
6
  * version — Print binary version
7
+ * install-skills — Install SKILL.md files into local agent directories
7
8
  * context — Build & print context injection string to stdout
8
9
  * write — Write to memory files
9
10
  * read — Read memory files
@@ -40,6 +41,7 @@ import {
40
41
  getQmdResultPath,
41
42
  getQmdResultText,
42
43
  getScratchpadFile,
44
+ installSkills,
43
45
  nowTimestamp,
44
46
  parseScratchpad,
45
47
  readFileSafe,
@@ -398,6 +400,41 @@ async function cmdSearch(flags: Record<string, string | boolean>) {
398
400
  }
399
401
  }
400
402
 
403
+ function cmdInstallSkills(flags: Record<string, string | boolean>) {
404
+ const json = hasFlag(flags, "json");
405
+ const report = installSkills();
406
+
407
+ if (!report.ok) {
408
+ exitError(report.error ?? "Failed to install skills.", json);
409
+ }
410
+
411
+ if (json) {
412
+ output(report, true);
413
+ return;
414
+ }
415
+
416
+ if (report.detected.length === 0) {
417
+ console.log("No supported agent installations detected.");
418
+ } else {
419
+ const detectedLabels = report.detected.map((item) => item.label).join(", ");
420
+ console.log(`Detected: ${detectedLabels}`);
421
+ }
422
+
423
+ if (report.installed.length === 0) {
424
+ console.log("No skills installed.");
425
+ } else {
426
+ for (const item of report.installed) {
427
+ console.log(`Installed ${item.label}: ${item.path}`);
428
+ }
429
+ }
430
+
431
+ if (report.skipped.length > 0) {
432
+ for (const item of report.skipped) {
433
+ console.log(`Skipped ${item.label} (${item.reason})`);
434
+ }
435
+ }
436
+ }
437
+
401
438
  async function cmdSync(flags: Record<string, string | boolean>) {
402
439
  const json = hasFlag(flags, "json");
403
440
 
@@ -602,6 +639,7 @@ Usage:
602
639
 
603
640
  Commands:
604
641
  version Show binary version
642
+ install-skills Install bundled skills into local agent directories
605
643
  context Build & print context injection string
606
644
  write Write to memory files
607
645
  read Read memory files
@@ -671,6 +709,9 @@ async function main() {
671
709
  case "search":
672
710
  await cmdSearch(flags);
673
711
  break;
712
+ case "install-skills":
713
+ cmdInstallSkills(flags);
714
+ break;
674
715
  case "sync":
675
716
  await cmdSync(flags);
676
717
  break;
package/src/core.ts CHANGED
@@ -399,6 +399,8 @@ let spawnFn: SpawnFn = spawn;
399
399
  let qmdAvailable = false;
400
400
  let updateTimer: ReturnType<typeof setTimeout> | null = null;
401
401
  let embedTimer: ReturnType<typeof setTimeout> | null = null;
402
+ let skillsRootOverride: string | null = null;
403
+ let homeDirOverride: string | null = null;
402
404
 
403
405
  /** QMD collection name — configurable per platform. */
404
406
  let QMD_COLLECTION_NAME = "agent-memory";
@@ -413,6 +415,16 @@ export function _resetExecFileForTest() {
413
415
  execFileFn = execFile;
414
416
  }
415
417
 
418
+ /** Override skills root directory (for testing). */
419
+ export function _setSkillsRootForTest(dir: string | null) {
420
+ skillsRootOverride = dir;
421
+ }
422
+
423
+ /** Override home directory (for testing). */
424
+ export function _setHomeDirForTest(dir: string | null) {
425
+ homeDirOverride = dir;
426
+ }
427
+
416
428
  /** Override spawn implementation (for testing). */
417
429
  export function _setSpawnForTest(fn: SpawnFn) {
418
430
  spawnFn = fn;
@@ -459,6 +471,39 @@ export function _clearEmbedTimer() {
459
471
  }
460
472
  }
461
473
 
474
+ function resolveHomeDir(): string | null {
475
+ if (homeDirOverride !== null) return homeDirOverride;
476
+ return process.env.HOME ?? process.env.USERPROFILE ?? null;
477
+ }
478
+
479
+ function findSkillsRoot(): string | null {
480
+ const envRoot = process.env.AGENT_MEMORY_SKILLS_ROOT;
481
+ if (envRoot) return envRoot;
482
+ if (skillsRootOverride) return skillsRootOverride;
483
+
484
+ const scanUp = (startDir: string): string | null => {
485
+ let dir = startDir;
486
+ while (true) {
487
+ if (fs.existsSync(path.join(dir, "skills"))) return dir;
488
+ const parent = path.dirname(dir);
489
+ if (parent === dir) return null;
490
+ dir = parent;
491
+ }
492
+ };
493
+
494
+ const argvPath = process.argv[1];
495
+ if (argvPath) {
496
+ const found = scanUp(path.resolve(path.dirname(argvPath)));
497
+ if (found) return found;
498
+ }
499
+
500
+ const execDir = path.dirname(process.execPath);
501
+ const found = scanUp(path.resolve(execDir));
502
+ if (found) return found;
503
+
504
+ return scanUp(path.resolve(process.cwd()));
505
+ }
506
+
462
507
  /** Get the current QMD collection name. */
463
508
  export function getCollectionName(): string {
464
509
  return QMD_COLLECTION_NAME;
@@ -669,6 +714,111 @@ export async function runQmdSync(): Promise<{ updateOk: boolean; embedOk: boolea
669
714
  return { updateOk, embedOk };
670
715
  }
671
716
 
717
+ export interface InstallSkillsReport {
718
+ ok: boolean;
719
+ projectDir?: string;
720
+ homeDir?: string;
721
+ detected: Array<{ label: string; homeMarker: string }>;
722
+ installed: Array<{ label: string; path: string }>;
723
+ skipped: Array<{ label: string; reason: string }>;
724
+ error?: string;
725
+ }
726
+
727
+ export function installSkills(): InstallSkillsReport {
728
+ const homeDir = resolveHomeDir();
729
+ if (!homeDir) {
730
+ return {
731
+ ok: false,
732
+ detected: [],
733
+ installed: [],
734
+ skipped: [],
735
+ error: "Home directory not found. Set HOME (or USERPROFILE on Windows) and retry.",
736
+ };
737
+ }
738
+
739
+ const projectDir = findSkillsRoot();
740
+ if (!projectDir) {
741
+ return {
742
+ ok: false,
743
+ homeDir,
744
+ detected: [],
745
+ installed: [],
746
+ skipped: [],
747
+ error: "Could not locate the skills directory. Ensure the package includes skills/ (reinstall if needed).",
748
+ };
749
+ }
750
+
751
+ const skillsDir = path.join(projectDir, "skills");
752
+ if (!fs.existsSync(skillsDir)) {
753
+ return {
754
+ ok: false,
755
+ projectDir,
756
+ homeDir,
757
+ detected: [],
758
+ installed: [],
759
+ skipped: [],
760
+ error: `Skills directory not found: ${skillsDir}`,
761
+ };
762
+ }
763
+ const targets = [
764
+ {
765
+ label: "Claude Code skill",
766
+ srcDir: path.join(skillsDir, "claude-code"),
767
+ destDir: path.join(homeDir, ".claude", "skills", "agent-memory"),
768
+ homeMarker: path.join(homeDir, ".claude"),
769
+ },
770
+ {
771
+ label: "Codex skill",
772
+ srcDir: path.join(skillsDir, "codex"),
773
+ destDir: path.join(homeDir, ".codex", "skills", "agent-memory"),
774
+ homeMarker: path.join(homeDir, ".codex"),
775
+ },
776
+ {
777
+ label: "Cursor skill",
778
+ srcDir: path.join(skillsDir, "cursor"),
779
+ destDir: path.join(homeDir, ".cursor", "skills", "agent-memory"),
780
+ homeMarker: path.join(homeDir, ".cursor"),
781
+ },
782
+ {
783
+ label: "Agent CLI skill",
784
+ srcDir: path.join(skillsDir, "agent"),
785
+ destDir: path.join(homeDir, ".agents", "skills", "agent-memory"),
786
+ homeMarker: path.join(homeDir, ".agents"),
787
+ },
788
+ ];
789
+
790
+ const detected: Array<{ label: string; homeMarker: string }> = [];
791
+ const installed: Array<{ label: string; path: string }> = [];
792
+ const skipped: Array<{ label: string; reason: string }> = [];
793
+
794
+ for (const target of targets) {
795
+ if (!fs.existsSync(target.homeMarker)) {
796
+ skipped.push({ label: target.label, reason: `${target.homeMarker} not found` });
797
+ continue;
798
+ }
799
+ detected.push({ label: target.label, homeMarker: target.homeMarker });
800
+
801
+ const skillFile = path.join(target.srcDir, "SKILL.md");
802
+ if (!fs.existsSync(skillFile)) {
803
+ skipped.push({ label: target.label, reason: `${skillFile} not found` });
804
+ continue;
805
+ }
806
+
807
+ fs.mkdirSync(target.destDir, { recursive: true });
808
+ fs.copyFileSync(skillFile, path.join(target.destDir, "SKILL.md"));
809
+ installed.push({ label: target.label, path: path.join(target.destDir, "SKILL.md") });
810
+ }
811
+
812
+ return {
813
+ ok: true,
814
+ projectDir,
815
+ homeDir,
816
+ detected,
817
+ installed,
818
+ skipped,
819
+ };
820
+ }
821
+
672
822
  export interface QmdHealthInfo {
673
823
  totalFiles: number | null;
674
824
  vectorsEmbedded: number | null;