stackmem 1.0.1 → 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.
Files changed (3) hide show
  1. package/dist/cli.js +49 -1
  2. package/package.json +1 -1
  3. package/src/cli.ts +59 -1
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",
@@ -399,7 +401,7 @@ function git(args) {
399
401
  }
400
402
 
401
403
  function cmSave(type, content) {
402
- execFileSync("node", [CLI_PATH, "save", PROJECT, type, content], {
404
+ execFileSync("node", [CLI_PATH, "save", PROJECT, type, content, "--force"], {
403
405
  stdio: "inherit",
404
406
  });
405
407
  }
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stackmem",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "type": "module",
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];
@@ -481,7 +483,7 @@ function git(args) {
481
483
  }
482
484
 
483
485
  function cmSave(type, content) {
484
- execFileSync("node", [CLI_PATH, "save", PROJECT, type, content], {
486
+ execFileSync("node", [CLI_PATH, "save", PROJECT, type, content, "--force"], {
485
487
  stdio: "inherit",
486
488
  });
487
489
  }
@@ -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 ------------------------------------------------------------