stackmem 1.0.2 → 1.0.3
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/cli.js +48 -0
- package/package.json +1 -1
- package/src/cli.ts +58 -0
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
2
|
import nodeFs from "node:fs";
|
|
3
|
+
import nodeOs from "node:os";
|
|
3
4
|
import nodePath from "node:path";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
5
6
|
import { createInterface } from "node:readline/promises";
|
|
@@ -14,6 +15,7 @@ const CLI_PATH = fileURLToPath(import.meta.url);
|
|
|
14
15
|
// directly — tsx's esbuild transform fails when invoked from inside a git
|
|
15
16
|
// hook's stripped-down shell environment.
|
|
16
17
|
const DIST_CLI_PATH = nodePath.join(nodePath.dirname(CLI_PATH), "..", "dist", "cli.js");
|
|
18
|
+
const DIST_INDEX_PATH = nodePath.join(nodePath.dirname(CLI_PATH), "..", "dist", "index.js");
|
|
17
19
|
const MEMORY_TYPES = ["decision", "rejection", "constraint", "discovery"];
|
|
18
20
|
const TYPE_LABELS = {
|
|
19
21
|
decision: "Decisions",
|
|
@@ -565,6 +567,50 @@ for (const item of savedItems) {
|
|
|
565
567
|
}
|
|
566
568
|
`;
|
|
567
569
|
}
|
|
570
|
+
function registerMcpServer(distIndexPath) {
|
|
571
|
+
const claudeConfigPath = nodePath.join(nodeOs.homedir(), ".claude.json");
|
|
572
|
+
let config = {};
|
|
573
|
+
if (nodeFs.existsSync(claudeConfigPath)) {
|
|
574
|
+
try {
|
|
575
|
+
config = JSON.parse(nodeFs.readFileSync(claudeConfigPath, "utf-8"));
|
|
576
|
+
}
|
|
577
|
+
catch {
|
|
578
|
+
config = {};
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
if (!config.mcpServers || typeof config.mcpServers !== "object") {
|
|
582
|
+
config.mcpServers = {};
|
|
583
|
+
}
|
|
584
|
+
if (config.mcpServers.stackmem) {
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
config.mcpServers.stackmem = {
|
|
588
|
+
command: "node",
|
|
589
|
+
args: [distIndexPath],
|
|
590
|
+
};
|
|
591
|
+
nodeFs.writeFileSync(claudeConfigPath, JSON.stringify(config, null, 2), "utf-8");
|
|
592
|
+
console.log("stackmem MCP server registered with Claude Code.");
|
|
593
|
+
}
|
|
594
|
+
function writeClaudeMd(project, resolvedPath) {
|
|
595
|
+
const claudeMdPath = nodePath.join(resolvedPath, "CLAUDE.md");
|
|
596
|
+
if (nodeFs.existsSync(claudeMdPath)) {
|
|
597
|
+
console.log("CLAUDE.md already exists — skipping.");
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
const content = `# stackmem
|
|
601
|
+
|
|
602
|
+
At the start of every session, the stackmem MCP server will automatically load memories for this project. The project name is "${project}".
|
|
603
|
+
|
|
604
|
+
If the MCP server is not connected, run:
|
|
605
|
+
cm start ${project}
|
|
606
|
+
and paste the output here before starting work.
|
|
607
|
+
|
|
608
|
+
When you make a decision, discover a constraint, reject an approach, or make a discovery during this session, save it with:
|
|
609
|
+
cm save ${project} <type> "<content>"
|
|
610
|
+
`;
|
|
611
|
+
nodeFs.writeFileSync(claudeMdPath, content, "utf-8");
|
|
612
|
+
console.log("CLAUDE.md written.");
|
|
613
|
+
}
|
|
568
614
|
async function cmdInit(project, targetPath) {
|
|
569
615
|
const resolvedPath = nodePath.resolve(targetPath);
|
|
570
616
|
const gitDir = nodePath.join(resolvedPath, ".git");
|
|
@@ -582,6 +628,8 @@ async function cmdInit(project, targetPath) {
|
|
|
582
628
|
nodeFs.writeFileSync(hookPath, `#!/bin/sh\nexec node "${hookLogicPath}" "$@"\n`, "utf-8");
|
|
583
629
|
nodeFs.chmodSync(hookPath, 0o755);
|
|
584
630
|
console.log(`coding-memory hook installed for project ${project} at ${targetPath}`);
|
|
631
|
+
registerMcpServer(DIST_INDEX_PATH);
|
|
632
|
+
writeClaudeMd(project, resolvedPath);
|
|
585
633
|
}
|
|
586
634
|
// --- cm context ------------------------------------------------------------
|
|
587
635
|
const CONTEXT_TYPE_ORDER = ["decision", "constraint", "rejection", "discovery"];
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
2
|
import nodeFs from "node:fs";
|
|
3
|
+
import nodeOs from "node:os";
|
|
3
4
|
import nodePath from "node:path";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
5
6
|
import { createInterface } from "node:readline/promises";
|
|
@@ -24,6 +25,7 @@ const CLI_PATH = fileURLToPath(import.meta.url);
|
|
|
24
25
|
// directly — tsx's esbuild transform fails when invoked from inside a git
|
|
25
26
|
// hook's stripped-down shell environment.
|
|
26
27
|
const DIST_CLI_PATH = nodePath.join(nodePath.dirname(CLI_PATH), "..", "dist", "cli.js");
|
|
28
|
+
const DIST_INDEX_PATH = nodePath.join(nodePath.dirname(CLI_PATH), "..", "dist", "index.js");
|
|
27
29
|
|
|
28
30
|
const MEMORY_TYPES = ["decision", "rejection", "constraint", "discovery"] as const;
|
|
29
31
|
type MemoryType = (typeof MEMORY_TYPES)[number];
|
|
@@ -648,6 +650,59 @@ for (const item of savedItems) {
|
|
|
648
650
|
`;
|
|
649
651
|
}
|
|
650
652
|
|
|
653
|
+
function registerMcpServer(distIndexPath: string): void {
|
|
654
|
+
const claudeConfigPath = nodePath.join(nodeOs.homedir(), ".claude.json");
|
|
655
|
+
|
|
656
|
+
let config: { mcpServers?: Record<string, unknown> } = {};
|
|
657
|
+
if (nodeFs.existsSync(claudeConfigPath)) {
|
|
658
|
+
try {
|
|
659
|
+
config = JSON.parse(nodeFs.readFileSync(claudeConfigPath, "utf-8"));
|
|
660
|
+
} catch {
|
|
661
|
+
config = {};
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
if (!config.mcpServers || typeof config.mcpServers !== "object") {
|
|
666
|
+
config.mcpServers = {};
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
if (config.mcpServers.stackmem) {
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
config.mcpServers.stackmem = {
|
|
674
|
+
command: "node",
|
|
675
|
+
args: [distIndexPath],
|
|
676
|
+
};
|
|
677
|
+
|
|
678
|
+
nodeFs.writeFileSync(claudeConfigPath, JSON.stringify(config, null, 2), "utf-8");
|
|
679
|
+
console.log("stackmem MCP server registered with Claude Code.");
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
function writeClaudeMd(project: string, resolvedPath: string): void {
|
|
683
|
+
const claudeMdPath = nodePath.join(resolvedPath, "CLAUDE.md");
|
|
684
|
+
|
|
685
|
+
if (nodeFs.existsSync(claudeMdPath)) {
|
|
686
|
+
console.log("CLAUDE.md already exists — skipping.");
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
const content = `# stackmem
|
|
691
|
+
|
|
692
|
+
At the start of every session, the stackmem MCP server will automatically load memories for this project. The project name is "${project}".
|
|
693
|
+
|
|
694
|
+
If the MCP server is not connected, run:
|
|
695
|
+
cm start ${project}
|
|
696
|
+
and paste the output here before starting work.
|
|
697
|
+
|
|
698
|
+
When you make a decision, discover a constraint, reject an approach, or make a discovery during this session, save it with:
|
|
699
|
+
cm save ${project} <type> "<content>"
|
|
700
|
+
`;
|
|
701
|
+
|
|
702
|
+
nodeFs.writeFileSync(claudeMdPath, content, "utf-8");
|
|
703
|
+
console.log("CLAUDE.md written.");
|
|
704
|
+
}
|
|
705
|
+
|
|
651
706
|
async function cmdInit(project: string, targetPath: string) {
|
|
652
707
|
const resolvedPath = nodePath.resolve(targetPath);
|
|
653
708
|
const gitDir = nodePath.join(resolvedPath, ".git");
|
|
@@ -671,6 +726,9 @@ async function cmdInit(project: string, targetPath: string) {
|
|
|
671
726
|
nodeFs.chmodSync(hookPath, 0o755);
|
|
672
727
|
|
|
673
728
|
console.log(`coding-memory hook installed for project ${project} at ${targetPath}`);
|
|
729
|
+
|
|
730
|
+
registerMcpServer(DIST_INDEX_PATH);
|
|
731
|
+
writeClaudeMd(project, resolvedPath);
|
|
674
732
|
}
|
|
675
733
|
|
|
676
734
|
// --- cm context ------------------------------------------------------------
|