shelbymcp 0.1.0 → 0.2.0

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 (48) hide show
  1. package/README.md +20 -21
  2. package/dist/cli/forage.d.ts +2 -0
  3. package/dist/cli/forage.d.ts.map +1 -0
  4. package/dist/cli/forage.js +130 -0
  5. package/dist/cli/forage.js.map +1 -0
  6. package/dist/cli/help.d.ts +2 -0
  7. package/dist/cli/help.d.ts.map +1 -0
  8. package/dist/cli/help.js +34 -0
  9. package/dist/cli/help.js.map +1 -0
  10. package/dist/cli/protocol.d.ts +2 -0
  11. package/dist/cli/protocol.d.ts.map +1 -0
  12. package/dist/cli/protocol.js +48 -0
  13. package/dist/cli/protocol.js.map +1 -0
  14. package/dist/cli/setup.d.ts +2 -0
  15. package/dist/cli/setup.d.ts.map +1 -0
  16. package/dist/cli/setup.js +328 -0
  17. package/dist/cli/setup.js.map +1 -0
  18. package/dist/cli/uninstall.d.ts +2 -0
  19. package/dist/cli/uninstall.d.ts.map +1 -0
  20. package/dist/cli/uninstall.js +175 -0
  21. package/dist/cli/uninstall.js.map +1 -0
  22. package/dist/config.d.ts +6 -1
  23. package/dist/config.d.ts.map +1 -1
  24. package/dist/config.js +21 -0
  25. package/dist/config.js.map +1 -1
  26. package/dist/db/edges.d.ts.map +1 -1
  27. package/dist/db/edges.js +1 -1
  28. package/dist/db/edges.js.map +1 -1
  29. package/dist/db/fts.d.ts.map +1 -1
  30. package/dist/db/fts.js +1 -0
  31. package/dist/db/fts.js.map +1 -1
  32. package/dist/db/thoughts.d.ts +1 -0
  33. package/dist/db/thoughts.d.ts.map +1 -1
  34. package/dist/db/thoughts.js +6 -0
  35. package/dist/db/thoughts.js.map +1 -1
  36. package/dist/db/vectors.d.ts.map +1 -1
  37. package/dist/db/vectors.js +5 -3
  38. package/dist/db/vectors.js.map +1 -1
  39. package/dist/index.js +25 -0
  40. package/dist/index.js.map +1 -1
  41. package/dist/mcp/server.d.ts.map +1 -1
  42. package/dist/mcp/server.js +1 -0
  43. package/dist/mcp/server.js.map +1 -1
  44. package/dist/tools/list.d.ts.map +1 -1
  45. package/dist/tools/list.js +1 -0
  46. package/dist/tools/list.js.map +1 -1
  47. package/package.json +10 -2
  48. package/skills/shelby-forage/SKILL.md +92 -48
package/README.md CHANGED
@@ -74,15 +74,17 @@ Add to your `~/.claude/mcp.json`:
74
74
  }
75
75
  ```
76
76
 
77
- ### (Optional) Install the Forage Skill
77
+ ### Add the Memory Protocol
78
78
 
79
- The Forage skill runs on Claude Code's scheduler to continuously improve your memories:
79
+ The Memory Protocol tells your agent *when* to save and search memory. Without it, your agent has the tools but won't use them proactively.
80
80
 
81
- ```bash
82
- cp -r skills/shelby-forage ~/.claude/scheduled-tasks/shelby-forage
83
- ```
81
+ See [docs/AGENT-SETUP.md](docs/AGENT-SETUP.md#2-memory-protocol) for the copy-paste instructions for your agent.
82
+
83
+ ### (Optional) Install the Forage Skill
84
+
85
+ The Forage skill runs daily on your AI subscription to enrich, consolidate, and connect your memories. Works with Claude Desktop, Claude Code, Cursor, and more.
84
86
 
85
- That's it. Your AI now remembers.
87
+ See [docs/AGENT-SETUP.md](docs/AGENT-SETUP.md#3-forage-skill-optional) for setup instructions and platform compatibility.
86
88
 
87
89
  ---
88
90
 
@@ -164,21 +166,18 @@ ShelbyMCP ships with `shelby-forage`, a scheduled skill that runs on your existi
164
166
 
165
167
  | Task | Frequency | What it does |
166
168
  |---|---|---|
167
- | **Embed backfill** | Daily | Generate embeddings for thoughts that don't have them |
168
- | **Auto-classify** | Daily | Re-scan poorly tagged thoughts, improve metadata |
169
- | **Consolidation** | Daily | Find duplicate/similar thoughts, merge into rich summaries |
170
- | **Contradiction detection** | Daily | Flag conflicting memories for user resolution |
171
- | **Connection discovery** | Daily | Find related thoughts, create knowledge graph edges |
172
- | **Stale sweep** | Weekly | Flag old action items that fell through the cracks |
173
- | **Digest** | Weekly | Generate a summary of the week's thinking |
174
-
175
- ### Install
176
-
177
- ```bash
178
- cp -r skills/shelby-forage ~/.claude/scheduled-tasks/shelby-forage
179
- ```
180
-
181
- The skill runs daily by default. Edit the SKILL.md frontmatter to adjust the schedule.
169
+ | **Summary backfill** | Daily | Generate one-liners for thoughts missing summaries |
170
+ | **Auto-classify** | Daily | Improve type/topics/people on poorly tagged thoughts |
171
+ | **Consolidation** | Daily | Find and merge duplicate thoughts |
172
+ | **Contradiction detection** | Daily | Flag conflicting memories (tagged `needs-attention`) |
173
+ | **Connection discovery** | Daily | Create edges between related thoughts |
174
+ | **Stale sweep** | Weekly (Mon) | Flag forgotten action items (tagged `needs-attention`) |
175
+ | **Digest** | Weekly (Mon) | Summary of the week's thinking by project/topic |
176
+ | **Forage log** | Every run | Audit trail for continuity between runs |
177
+
178
+ ### Setup
179
+
180
+ See [docs/AGENT-SETUP.md](docs/AGENT-SETUP.md#3-forage-skill-optional) for full setup instructions, platform compatibility table, and gotchas for each agent.
182
181
 
183
182
  ### Without the Forage Skill
184
183
 
@@ -0,0 +1,2 @@
1
+ export declare function printForage(): void;
2
+ //# sourceMappingURL=forage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forage.d.ts","sourceRoot":"","sources":["../../src/cli/forage.ts"],"names":[],"mappings":"AA4HA,wBAAgB,WAAW,IAAI,IAAI,CAOlC"}
@@ -0,0 +1,130 @@
1
+ const FORAGE_PROMPT = `# Shelby Forage — Memory Maintenance Skill
2
+
3
+ You are the Forage agent for ShelbyMCP. Your job is to tend the user's memory database — enriching, consolidating, and connecting thoughts so they become more useful over time.
4
+
5
+ You have access to the ShelbyMCP memory tools. Run the tasks below in order, skipping any that have nothing to do. Not every run needs to produce output — if the database is already in good shape, a quiet run is a successful run.
6
+
7
+ ## Before You Start
8
+
9
+ 1. Determine today's date and day of the week. Tasks 6 and 7 only run on Mondays.
10
+ 2. Check the last forage log: use \`search_thoughts\` with query \`"Forage run"\` and \`limit: 1\` to find the most recent run. Read it with \`get_thought\` to see what was done last time — how many summaries were backfilled, what was consolidated, any notes about remaining work. Use this to pick up where the last run left off (e.g., if the log says "42 thoughts still missing summaries", prioritize the summary backfill).
11
+
12
+ ## Task 1: Summary Backfill
13
+
14
+ Summaries are critical — search results only show summaries, not full content. Find thoughts that are missing them and fill them in.
15
+
16
+ 1. Use \`list_thoughts\` with \`has_summary: false\` and \`limit: 50\` to find thoughts without summaries
17
+ 2. For each result, call \`get_thought\` to read the full content
18
+ 3. Write a one-line summary (under ~100 characters) that captures the essence — it should answer: "What is this about and why does it matter?"
19
+ 4. Use \`update_thought\` to set the \`summary\` field. Set \`source: "forage"\` if you're also correcting other fields
20
+ 5. If \`has_more\` is true, note the remaining count — you'll catch them on the next run
21
+
22
+ ## Task 2: Auto-Classify
23
+
24
+ Find thoughts with missing or sparse metadata and improve their classification.
25
+
26
+ 1. Use \`list_thoughts\` to find thoughts where \`type\` is \`"note"\` (the default), \`limit: 50\`
27
+ 2. For each, read the content via \`get_thought\` and determine:
28
+ - The correct type: \`decision\`, \`task\`, \`question\`, \`reference\`, \`insight\`, or leave as \`note\` if it genuinely is one
29
+ - Relevant topics (if the \`topics\` array is empty or incomplete)
30
+ - People mentioned (if the \`people\` array is empty)
31
+ 3. Use \`update_thought\` to apply the corrections — only update fields that actually need changing
32
+
33
+ ## Task 3: Consolidation
34
+
35
+ Find duplicate or very similar thoughts and merge them. Be conservative — only merge when thoughts are genuinely saying the same thing, not just related.
36
+
37
+ 1. Pick 5-10 recent thoughts and for each one, use \`search_thoughts\` with key terms from its content to look for near-duplicates
38
+ 2. If you find 2+ thoughts that contain essentially the same information (not just the same topic — the same *point*):
39
+ - Create a new consolidated thought using \`capture_thought\` that preserves all unique information from the originals. Set \`source: "forage"\`
40
+ - Use \`update_thought\` on each original to set \`consolidated_into\` to the new thought's ID
41
+ - Carry over any edges from the originals to the new thought using \`manage_edges\` with \`action: "link"\`
42
+
43
+ ## Task 4: Contradiction Detection
44
+
45
+ Look for thoughts that disagree with each other — these are high-value signals that something has changed and the user should be aware.
46
+
47
+ 1. Take recent thoughts (use \`list_thoughts\` with \`since\` set to 7 days ago) and for each, search for older thoughts on the same topics
48
+ 2. If you find a genuine contradiction (e.g., "we're using PostgreSQL" vs. "we decided on SQLite"), capture a new thought:
49
+ - Type: \`question\`
50
+ - Source: \`forage\`
51
+ - Topics: \`["needs-attention"]\`
52
+ - Content: describe the contradiction and the two conflicting thoughts
53
+ - Summary: brief description of what contradicts what
54
+ 3. Link the contradicting thoughts to the new question using \`manage_edges\` with \`action: "link"\` and \`edge_type: "refuted_by"\`
55
+
56
+ Minor wording differences or natural evolution of thinking don't count as contradictions. Focus on factual disagreements.
57
+
58
+ ## Task 5: Connection Discovery
59
+
60
+ Find thoughts that should be related but aren't linked yet.
61
+
62
+ 1. Review recent thoughts and search for older thoughts on related topics
63
+ 2. If you find meaningful connections (e.g., a decision that impacts a task, a reference that supports an insight), create edges using \`manage_edges\` with \`action: "link"\`
64
+ 3. Use appropriate edge types:
65
+ - \`refines\` — thought B improves or elaborates on thought A
66
+ - \`cites\` — thought B references thought A as evidence
67
+ - \`related\` — thoughts share a topic but neither builds on the other
68
+ - \`follows\` — thought B is a consequence or next step of thought A
69
+ 4. Check existing edges first via \`explore_graph\` to avoid duplicating relationships
70
+
71
+ ## Task 6: Stale Sweep (Mondays only)
72
+
73
+ Skip this task unless today is Monday.
74
+
75
+ Find *actionable* tasks that may have been forgotten. The goal is to surface things that look like they needed doing but might have slipped — not to flag standing practices or long-term reference items.
76
+
77
+ 1. Use \`list_thoughts\` with \`type: "task"\` and \`until\` set to 14 days ago to find older tasks
78
+ 2. For each, read the content via \`get_thought\` and assess whether it's actually stale:
79
+ - **Flag it** if it reads like a one-off action item that was never completed (e.g., "fix the login bug", "email Tim about the deploy", "update the staging config")
80
+ - **Skip it** if it's a standing practice, ongoing guideline, or reference (e.g., "always use ESM imports", "run tests before merging", "prefer composition over inheritance"). These aren't stale — they're meant to persist.
81
+ - **Skip it** if it has a \`consolidated_into\` value (already handled)
82
+ - **Skip it** if it has recent edges linking it to other thoughts (it's being actively referenced)
83
+ 3. For each genuinely stale task, capture a thought:
84
+ - Type: \`question\`
85
+ - Source: \`forage\`
86
+ - Topics: \`["needs-attention"]\`
87
+ - Summary: a short description of the stale task (e.g., "Stale task: fix the login bug — created 3 weeks ago, never referenced")
88
+ - Content: the original task content, when it was created, and why it looks forgotten
89
+ - Link it to the original task using \`manage_edges\` with \`action: "link"\` and \`edge_type: "related"\`
90
+
91
+ ## Task 7: Digest (Mondays only)
92
+
93
+ Skip this task unless today is Monday.
94
+
95
+ Generate a summary of the week's thinking.
96
+
97
+ 1. Use \`list_thoughts\` with \`since\` set to 7 days ago to get the week's thoughts
98
+ 2. Group them by project and topic
99
+ 3. Capture a new thought:
100
+ - Type: \`reference\`
101
+ - Source: \`forage\`
102
+ - Summary: "Weekly digest — [date range]"
103
+ - Content: structured digest covering key decisions, open questions, active tasks, and emerging themes
104
+
105
+ ## Task 8: Forage Log
106
+
107
+ At the end of every run, capture a brief log of what you did. This serves as an audit trail and helps future runs avoid re-processing.
108
+
109
+ 1. Capture a thought with:
110
+ - Type: \`reference\`
111
+ - Source: \`forage\`
112
+ - Summary: "Forage run — [today's date]"
113
+ - Topics: \`["forage-log"]\`
114
+ - Content: what you did in each task (counts of summaries backfilled, thoughts reclassified, duplicates merged, contradictions found, edges created, etc.). If a task was skipped because there was nothing to do, say so.
115
+
116
+ ## Guidelines
117
+
118
+ - **Be conservative.** Don't merge thoughts unless they're genuinely duplicates. Don't flag contradictions over minor wording.
119
+ - **Preserve information.** Consolidated thoughts must contain everything from the originals — never lose content.
120
+ - **Don't create noise.** Every thought you capture should earn its place. An empty forage log that says "nothing to do" is better than manufactured busywork.
121
+ - **Respect existing edges.** Check before creating — don't duplicate relationships that already exist.
122
+ - **Tag your work.** Always set \`source: "forage"\` on thoughts you create, so they're distinguishable from user-captured memories.
123
+ - **Paginate wisely.** Process up to 50 thoughts per task per run. If there's more, you'll catch them tomorrow — don't try to boil the ocean.`;
124
+ export function printForage() {
125
+ console.error("Paste this into a scheduled task in your AI tool.\n" +
126
+ "Recommended: Claude Desktop > Schedule > Daily\n" +
127
+ "Docs: https://github.com/Studio-Moser/shelbymcp/docs/AGENT-SETUP.md#3-forage-skill-optional\n");
128
+ console.log(FORAGE_PROMPT);
129
+ }
130
+ //# sourceMappingURL=forage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forage.js","sourceRoot":"","sources":["../../src/cli/forage.ts"],"names":[],"mappings":"AAAA,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8IA0HwH,CAAC;AAE/I,MAAM,UAAU,WAAW;IACzB,OAAO,CAAC,KAAK,CACX,qDAAqD;QACrD,kDAAkD;QAClD,+FAA+F,CAChG,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function printHelp(): void;
2
+ //# sourceMappingURL=help.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/cli/help.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,IAAI,IAAI,CAgChC"}
@@ -0,0 +1,34 @@
1
+ export function printHelp() {
2
+ console.log(`ShelbyMCP — Knowledge-graph memory for AI tools
3
+
4
+ Usage:
5
+ shelbymcp Start the MCP server (stdio)
6
+ shelbymcp setup <agent> Set up ShelbyMCP for an agent
7
+ shelbymcp setup <agent> --forage ...and install the Forage skill
8
+ shelbymcp uninstall <agent> Remove ShelbyMCP from an agent
9
+ shelbymcp protocol Print the Memory Protocol
10
+ shelbymcp forage Print the Forage skill prompt
11
+ shelbymcp help Show this help
12
+
13
+ Setup agents:
14
+ claude-code Claude Code CLI
15
+ claude-desktop Claude Desktop app
16
+ cursor Cursor IDE
17
+ codex OpenAI Codex
18
+ windsurf Windsurf (Codeium)
19
+ gemini Gemini CLI
20
+
21
+ Flags:
22
+ --db <path> Database path (default: ~/.shelbymcp/memory.db)
23
+ --verbose Enable verbose logging
24
+ --version Print version
25
+
26
+ Examples:
27
+ shelbymcp setup claude-code --forage Configure + install Forage skill
28
+ shelbymcp setup claude-code Auto-configure Claude Code CLI
29
+ shelbymcp protocol >> CLAUDE.md Append Memory Protocol to your rules
30
+ shelbymcp forage > forage-task.md Save Forage prompt for scheduling
31
+
32
+ Docs: https://github.com/Studio-Moser/shelbymcp/docs/AGENT-SETUP.md`);
33
+ }
34
+ //# sourceMappingURL=help.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/cli/help.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,SAAS;IACvB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oEA8BsD,CAAC,CAAC;AACtE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function printProtocol(): void;
2
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/cli/protocol.ts"],"names":[],"mappings":"AA2CA,wBAAgB,aAAa,IAAI,IAAI,CAMpC"}
@@ -0,0 +1,48 @@
1
+ const MEMORY_PROTOCOL = `## Memory (ShelbyMCP)
2
+
3
+ You have persistent memory via ShelbyMCP MCP tools. Memory survives across sessions and is shared across all AI tools the user works with. You MUST use it — do not rely on conversation context alone.
4
+
5
+ ### When to SAVE (mandatory)
6
+
7
+ You MUST call \`capture_thought\` after any of these events:
8
+
9
+ - **Decisions**: Architecture choices, library selections, tradeoffs considered ("We chose CloudKit over Firebase because...")
10
+ - **Preferences**: User likes/dislikes, workflow habits, coding style ("User prefers functional components over class components")
11
+ - **People & roles**: Who does what ("Sarah owns the auth service, Mike handles DevOps")
12
+ - **Project context**: Goals, deadlines, constraints, scope changes ("Launch target is March 15, blocked on API approval")
13
+ - **Bugs & fixes**: Root cause discoveries, workarounds, things that broke ("Memory leak was caused by unclosed DB connections in the edge traversal loop")
14
+ - **Architecture & patterns**: System design, data flow, conventions ("All API responses use the envelope pattern: { data, error, meta }")
15
+ - **Insights**: Non-obvious learnings, things that surprised you ("FTS5 porter tokenizer handles plurals but not acronyms")
16
+
17
+ Always include: a \`summary\` (one-line, <100 chars), a \`type\`, relevant \`topics\`, and link to \`related_to\` thoughts when applicable.
18
+
19
+ ### When to SEARCH (mandatory)
20
+
21
+ You MUST call \`search_thoughts\` or \`list_thoughts\` before:
22
+
23
+ - **Starting work on any task** — check what's already known about this area
24
+ - **Making a decision** — check for prior decisions on the same topic
25
+ - **When something feels familiar** — it probably is; search for it
26
+ - **After context compaction** — immediately search to recover session context
27
+ - **When the user says** "remember", "recall", "what do we know about", "what did we decide"
28
+
29
+ ### What NOT to save
30
+
31
+ - Ephemeral debugging output (stack traces, log lines you're actively reading)
32
+ - Code content that's already in git (save the *decision* about code, not the code itself)
33
+ - Transient conversation ("let me think about this..." — save the conclusion, not the process)
34
+ - Duplicate information — search first, update existing thoughts instead of creating new ones
35
+
36
+ ### How to save well
37
+
38
+ 1. **Summary first.** Search results only show summaries. A thought without a summary is invisible to search.
39
+ 2. **Type accurately.** Use \`decision\`, \`task\`, \`question\`, \`reference\`, \`insight\`, or \`note\`. Don't default everything to \`note\`.
40
+ 3. **Tag topics and people.** These are the primary filters for \`list_thoughts\`.
41
+ 4. **Link related thoughts.** Use \`manage_edges\` to connect decisions to the tasks they affect, references to the insights they support.
42
+ 5. **Update, don't duplicate.** If a thought exists but is outdated, use \`update_thought\`. Don't create a new one.`;
43
+ export function printProtocol() {
44
+ console.error("Paste this into your agent's rules file (CLAUDE.md, .cursorrules, AGENTS.md, etc.)\n" +
45
+ "Pipe directly: shelbymcp protocol >> CLAUDE.md\n");
46
+ console.log(MEMORY_PROTOCOL);
47
+ }
48
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/cli/protocol.ts"],"names":[],"mappings":"AAAA,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qHAyC6F,CAAC;AAEtH,MAAM,UAAU,aAAa;IAC3B,OAAO,CAAC,KAAK,CACX,sFAAsF;QACtF,kDAAkD,CACnD,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function runSetup(agent: string | undefined, forage: boolean): void;
2
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/cli/setup.ts"],"names":[],"mappings":"AA6UA,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAyCzE"}
@@ -0,0 +1,328 @@
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, cpSync } from "node:fs";
2
+ import { resolve, dirname } from "node:path";
3
+ import { homedir } from "node:os";
4
+ import { execSync } from "node:child_process";
5
+ import { fileURLToPath } from "node:url";
6
+ const AGENTS = [
7
+ "claude-code",
8
+ "claude-desktop",
9
+ "cursor",
10
+ "codex",
11
+ "windsurf",
12
+ "gemini",
13
+ ];
14
+ function isAgent(name) {
15
+ return AGENTS.includes(name);
16
+ }
17
+ /** Resolve the package root (where skills/ lives) from the compiled dist/ output */
18
+ function getPackageRoot() {
19
+ const thisFile = fileURLToPath(import.meta.url);
20
+ // thisFile is dist/cli/setup.js → go up to dist/, then up to package root
21
+ return resolve(dirname(thisFile), "..", "..");
22
+ }
23
+ function getSkillSourcePath() {
24
+ return resolve(getPackageRoot(), "skills", "shelby-forage");
25
+ }
26
+ function mergeJsonConfig(filePath, serverEntry) {
27
+ let config = {};
28
+ if (existsSync(filePath)) {
29
+ try {
30
+ config = JSON.parse(readFileSync(filePath, "utf-8"));
31
+ }
32
+ catch {
33
+ console.error(`Warning: Could not parse ${filePath}. Creating new file.`);
34
+ }
35
+ }
36
+ if (!config.mcpServers || typeof config.mcpServers !== "object") {
37
+ config.mcpServers = {};
38
+ }
39
+ const servers = config.mcpServers;
40
+ if (servers.memory) {
41
+ console.log(`"memory" server already exists in ${filePath}`);
42
+ console.log("To reconfigure, remove the existing entry first.");
43
+ return false;
44
+ }
45
+ servers.memory = serverEntry;
46
+ const dir = dirname(filePath);
47
+ if (!existsSync(dir)) {
48
+ mkdirSync(dir, { recursive: true });
49
+ }
50
+ writeFileSync(filePath, JSON.stringify(config, null, 2) + "\n");
51
+ console.log(`Added ShelbyMCP to ${filePath}`);
52
+ return true;
53
+ }
54
+ function printForageInstructions(agent) {
55
+ console.log("\n--- Forage Skill ---\n");
56
+ switch (agent) {
57
+ case "claude-desktop":
58
+ console.log("To set up Forage on Claude Desktop:");
59
+ console.log(" 1. Open the Schedule page");
60
+ console.log(" 2. Create a new local task, set frequency to Daily");
61
+ console.log(" 3. Paste the Forage prompt: run `shelbymcp forage` to get it");
62
+ console.log("");
63
+ console.log("Also add this to your Profile Preferences (alongside the Memory Protocol):");
64
+ console.log("");
65
+ console.log(" When starting a conversation, check ShelbyMCP for items that need attention:");
66
+ console.log(' use `list_thoughts` with `topic: "needs-attention"` and `limit: 5`.');
67
+ console.log(" If there are any, briefly mention them to the user.");
68
+ console.log(" If the user resolves one, delete the needs-attention thought.");
69
+ break;
70
+ case "cursor":
71
+ console.log("To set up Forage on Cursor:");
72
+ console.log(" 1. Open Cursor Automations settings");
73
+ console.log(" 2. Create a new automation with a Daily cron schedule");
74
+ console.log(" 3. Paste the Forage prompt: run `shelbymcp forage` to get it");
75
+ console.log("");
76
+ console.log("Note: Cursor Automations are cloud-based. MCP access to local");
77
+ console.log("servers may not work. Test to confirm.");
78
+ break;
79
+ case "codex":
80
+ console.log("Codex automation support is still evolving.");
81
+ console.log("To run Forage manually, paste the output of `shelbymcp forage`");
82
+ console.log("into a Codex conversation.");
83
+ break;
84
+ case "windsurf":
85
+ console.log("Windsurf has no scheduler. To run Forage manually, paste the");
86
+ console.log("output of `shelbymcp forage` into a Windsurf conversation");
87
+ console.log("whenever you want to maintain your memories.");
88
+ break;
89
+ case "gemini":
90
+ console.log("To set up Forage on Gemini:");
91
+ console.log(" 1. Create a scheduled action set to Daily");
92
+ console.log(" 2. Paste the Forage prompt: run `shelbymcp forage` to get it");
93
+ console.log("");
94
+ console.log("Note: Gemini has a max of 10 active scheduled actions.");
95
+ console.log("MCP tool access in scheduled actions is uncertain — test to confirm.");
96
+ break;
97
+ }
98
+ }
99
+ function setupClaudeCode(forage) {
100
+ try {
101
+ execSync("which claude", { stdio: "ignore" });
102
+ }
103
+ catch {
104
+ console.log("Claude Code CLI not found. Install it from https://code.claude.com\n");
105
+ console.log("Once installed, run:");
106
+ console.log(" claude mcp add -s user -t stdio memory -- npx shelbymcp");
107
+ return;
108
+ }
109
+ console.log("Adding ShelbyMCP to Claude Code CLI (user scope)...\n");
110
+ try {
111
+ execSync("claude mcp add -s user -t stdio memory -- npx shelbymcp", {
112
+ stdio: "inherit",
113
+ });
114
+ console.log("\nShelbyMCP added to Claude Code CLI.");
115
+ }
116
+ catch {
117
+ console.log("\nCould not add automatically. Run manually:");
118
+ console.log(" claude mcp add -s user -t stdio memory -- npx shelbymcp");
119
+ }
120
+ console.log("\nNext: Add the Memory Protocol to your rules file:");
121
+ console.log(" shelbymcp protocol >> ~/.claude/CLAUDE.md");
122
+ if (forage) {
123
+ const skillSource = getSkillSourcePath();
124
+ const skillDest = resolve(homedir(), ".claude/scheduled-tasks/shelby-forage");
125
+ if (existsSync(resolve(skillDest, "SKILL.md"))) {
126
+ console.log("\n--- Forage Skill ---\n");
127
+ console.log(`Forage skill already installed at ${skillDest}`);
128
+ }
129
+ else if (existsSync(resolve(skillSource, "SKILL.md"))) {
130
+ mkdirSync(skillDest, { recursive: true });
131
+ cpSync(skillSource, skillDest, { recursive: true });
132
+ console.log("\n--- Forage Skill ---\n");
133
+ console.log(`Forage skill installed to ${skillDest}`);
134
+ console.log("It will run daily via Claude Code's scheduler.");
135
+ console.log("\nNote: Claude Code CLI scheduled tasks auto-expire after 7 days.");
136
+ console.log("Use Claude Desktop for persistent scheduling.");
137
+ }
138
+ else {
139
+ console.log("\n--- Forage Skill ---\n");
140
+ console.log("Could not find skills/shelby-forage/SKILL.md in the package.");
141
+ console.log("Install manually: shelbymcp forage > ~/.claude/scheduled-tasks/shelby-forage/SKILL.md");
142
+ }
143
+ }
144
+ }
145
+ function setupClaudeDesktop(forage) {
146
+ const platform = process.platform;
147
+ let configPath;
148
+ if (platform === "darwin") {
149
+ configPath = resolve(homedir(), "Library/Application Support/Claude/claude_desktop_config.json");
150
+ }
151
+ else if (platform === "win32") {
152
+ configPath = resolve(process.env.APPDATA ?? "", "Claude/claude_desktop_config.json");
153
+ }
154
+ else {
155
+ configPath = resolve(homedir(), ".config/Claude/claude_desktop_config.json");
156
+ }
157
+ console.log("Claude Desktop setup\n");
158
+ console.log(`Config file: ${configPath}\n`);
159
+ console.log("Open Claude Desktop > Settings > Developer > Edit Config");
160
+ console.log("Add this to the mcpServers object:\n");
161
+ console.log(JSON.stringify({
162
+ memory: {
163
+ command: "npx",
164
+ args: ["shelbymcp"],
165
+ },
166
+ }, null, 2));
167
+ console.log("\nIMPORTANT: Quit and restart Claude Desktop after editing.");
168
+ console.log("\nNote: Claude Desktop and Claude Code CLI have separate configs.");
169
+ console.log("Setting up one does NOT configure the other.");
170
+ console.log("\nNext: Add the Memory Protocol to your Desktop profile:");
171
+ console.log(" Settings > Profile > \"What preferences should Claude consider?\"");
172
+ console.log(" Run: shelbymcp protocol");
173
+ if (forage) {
174
+ printForageInstructions("claude-desktop");
175
+ }
176
+ }
177
+ function setupCursor(forage) {
178
+ const configPath = resolve(homedir(), ".cursor/mcp.json");
179
+ const entry = {
180
+ command: "npx",
181
+ args: ["shelbymcp"],
182
+ };
183
+ mergeJsonConfig(configPath, entry);
184
+ console.log("\nOr add via UI: Settings > Tools & MCP > New MCP Server");
185
+ console.log("\nNext: Add the Memory Protocol for Cursor:");
186
+ console.log(" mkdir -p .cursor/rules");
187
+ console.log(" echo '---\\nalwaysApply: true\\n---' > .cursor/rules/shelbymcp.mdc");
188
+ console.log(" shelbymcp protocol >> .cursor/rules/shelbymcp.mdc");
189
+ if (forage) {
190
+ printForageInstructions("cursor");
191
+ }
192
+ }
193
+ function setupCodex(forage) {
194
+ try {
195
+ execSync("which codex", { stdio: "ignore" });
196
+ }
197
+ catch {
198
+ console.log("Codex CLI not found.\n");
199
+ console.log("Add this to ~/.codex/config.toml:\n");
200
+ console.log("[mcp_servers.memory]");
201
+ console.log('command = "npx"');
202
+ console.log('args = ["shelbymcp"]');
203
+ console.log("\nNext: Add the Memory Protocol:");
204
+ console.log(" shelbymcp protocol >> AGENTS.md");
205
+ if (forage) {
206
+ printForageInstructions("codex");
207
+ }
208
+ return;
209
+ }
210
+ console.log("Adding ShelbyMCP to Codex...\n");
211
+ try {
212
+ execSync("codex mcp add memory -- npx shelbymcp", { stdio: "inherit" });
213
+ console.log("\nShelbyMCP added to Codex.");
214
+ }
215
+ catch {
216
+ console.log("\nCould not add automatically. Add to ~/.codex/config.toml:\n");
217
+ console.log("[mcp_servers.memory]");
218
+ console.log('command = "npx"');
219
+ console.log('args = ["shelbymcp"]');
220
+ }
221
+ console.log("\nNext: Add the Memory Protocol:");
222
+ console.log(" shelbymcp protocol >> AGENTS.md");
223
+ if (forage) {
224
+ printForageInstructions("codex");
225
+ }
226
+ }
227
+ function setupWindsurf(forage) {
228
+ const platform = process.platform;
229
+ let configPath;
230
+ if (platform === "win32") {
231
+ configPath = resolve(process.env.USERPROFILE ?? homedir(), ".codeium/windsurf/mcp_config.json");
232
+ }
233
+ else {
234
+ configPath = resolve(homedir(), ".codeium/windsurf/mcp_config.json");
235
+ }
236
+ const entry = {
237
+ command: "npx",
238
+ args: ["shelbymcp"],
239
+ };
240
+ mergeJsonConfig(configPath, entry);
241
+ console.log("\nOr add via UI: Settings > Cascade > MCP Servers");
242
+ console.log("\nNext: Add the Memory Protocol:");
243
+ console.log(" shelbymcp protocol >> .windsurfrules");
244
+ if (forage) {
245
+ printForageInstructions("windsurf");
246
+ }
247
+ }
248
+ function setupGemini(forage) {
249
+ const configPath = resolve(homedir(), ".gemini/settings.json");
250
+ const entry = {
251
+ command: "npx",
252
+ args: ["shelbymcp"],
253
+ };
254
+ // Gemini stores mcpServers inside settings.json alongside other settings
255
+ let config = {};
256
+ if (existsSync(configPath)) {
257
+ try {
258
+ config = JSON.parse(readFileSync(configPath, "utf-8"));
259
+ }
260
+ catch {
261
+ console.error(`Warning: Could not parse ${configPath}. Creating new file.`);
262
+ }
263
+ }
264
+ if (!config.mcpServers || typeof config.mcpServers !== "object") {
265
+ config.mcpServers = {};
266
+ }
267
+ const servers = config.mcpServers;
268
+ if (servers["shelby-memory"]) {
269
+ console.log(`"shelby-memory" server already exists in ${configPath}`);
270
+ console.log("To reconfigure, remove the existing entry first.");
271
+ }
272
+ else {
273
+ servers["shelby-memory"] = entry;
274
+ const dir = dirname(configPath);
275
+ if (!existsSync(dir)) {
276
+ mkdirSync(dir, { recursive: true });
277
+ }
278
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
279
+ console.log(`Added ShelbyMCP as "shelby-memory" to ${configPath}`);
280
+ console.log('(Using hyphens, not underscores — Gemini\'s parser breaks on underscores)');
281
+ }
282
+ console.log("\nNext: Add the Memory Protocol:");
283
+ console.log(" shelbymcp protocol >> GEMINI.md");
284
+ if (forage) {
285
+ printForageInstructions("gemini");
286
+ }
287
+ }
288
+ export function runSetup(agent, forage) {
289
+ if (!agent) {
290
+ console.log("Usage: shelbymcp setup <agent> [--forage]\n");
291
+ console.log("Agents:");
292
+ console.log(" claude-code Claude Code CLI");
293
+ console.log(" claude-desktop Claude Desktop app");
294
+ console.log(" cursor Cursor IDE");
295
+ console.log(" codex OpenAI Codex");
296
+ console.log(" windsurf Windsurf (Codeium)");
297
+ console.log(" gemini Gemini CLI");
298
+ console.log("\nFlags:");
299
+ console.log(" --forage Also set up the Forage enrichment skill");
300
+ return;
301
+ }
302
+ if (!isAgent(agent)) {
303
+ console.error(`Unknown agent: "${agent}"\n`);
304
+ console.error("Available agents: " + AGENTS.join(", "));
305
+ process.exit(1);
306
+ }
307
+ switch (agent) {
308
+ case "claude-code":
309
+ setupClaudeCode(forage);
310
+ break;
311
+ case "claude-desktop":
312
+ setupClaudeDesktop(forage);
313
+ break;
314
+ case "cursor":
315
+ setupCursor(forage);
316
+ break;
317
+ case "codex":
318
+ setupCodex(forage);
319
+ break;
320
+ case "windsurf":
321
+ setupWindsurf(forage);
322
+ break;
323
+ case "gemini":
324
+ setupGemini(forage);
325
+ break;
326
+ }
327
+ }
328
+ //# sourceMappingURL=setup.js.map