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 +3 -4
- package/dist/agent-memory +0 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +37 -1
- package/dist/core.d.ts +23 -0
- package/dist/core.js +131 -0
- package/package.json +1 -1
- package/src/cli.ts +41 -0
- package/src/core.ts +150 -0
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
|
-
|
|
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
|
-
|
|
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
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.
|
|
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;
|