@simplexlat/memhub 0.1.3 → 0.1.4
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 +299 -51
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1348,9 +1348,9 @@ function getConfig() {
|
|
|
1348
1348
|
}
|
|
1349
1349
|
|
|
1350
1350
|
// src/connectors/ide-injector.ts
|
|
1351
|
-
import
|
|
1352
|
-
import
|
|
1353
|
-
import
|
|
1351
|
+
import fs6 from "fs";
|
|
1352
|
+
import path6 from "path";
|
|
1353
|
+
import os4 from "os";
|
|
1354
1354
|
|
|
1355
1355
|
// src/connectors/rules-injector.ts
|
|
1356
1356
|
import fs4 from "fs";
|
|
@@ -1438,6 +1438,9 @@ When completing a task or subtask, include a \`## Key Learnings:\` section at th
|
|
|
1438
1438
|
If context reset or compaction occurs, immediately call \`mem_session_summary\` to persist the compacted summary, then call \`mem_context\` to recover previous session context.
|
|
1439
1439
|
|
|
1440
1440
|
${MEMHUB_RULES_END_MARKER}`;
|
|
1441
|
+
function getHomeDir() {
|
|
1442
|
+
return process.env.HOME || os2.homedir();
|
|
1443
|
+
}
|
|
1441
1444
|
var RulesInjector = class {
|
|
1442
1445
|
/**
|
|
1443
1446
|
* Injects or updates the managed MemHub rules block inside a markdown file.
|
|
@@ -1481,7 +1484,7 @@ ${MEMHUB_PROTOCOL_INSTRUCTIONS}
|
|
|
1481
1484
|
*/
|
|
1482
1485
|
static injectClaudeCode(cwd = process.cwd()) {
|
|
1483
1486
|
const local = this.injectIntoFile(path4.join(cwd, "CLAUDE.md"), "Claude Code (Workspace)");
|
|
1484
|
-
const globalPath = path4.join(
|
|
1487
|
+
const globalPath = path4.join(getHomeDir(), ".claude", "CLAUDE.md");
|
|
1485
1488
|
const global = this.injectIntoFile(globalPath, "Claude Code (Global)");
|
|
1486
1489
|
return [local, global];
|
|
1487
1490
|
}
|
|
@@ -1492,7 +1495,7 @@ ${MEMHUB_PROTOCOL_INSTRUCTIONS}
|
|
|
1492
1495
|
const cursorRules = this.injectIntoFile(path4.join(cwd, ".cursorrules"), "Cursor (.cursorrules)");
|
|
1493
1496
|
const mdcPath = path4.join(cwd, ".cursor", "rules", "memhub.mdc");
|
|
1494
1497
|
const mdc = this.injectIntoFile(mdcPath, "Cursor MDC (.cursor/rules/memhub.mdc)");
|
|
1495
|
-
const globalCursor = this.injectIntoFile(path4.join(
|
|
1498
|
+
const globalCursor = this.injectIntoFile(path4.join(getHomeDir(), ".cursorrules"), "Cursor (Global .cursorrules)");
|
|
1496
1499
|
return [cursorRules, mdc, globalCursor];
|
|
1497
1500
|
}
|
|
1498
1501
|
/**
|
|
@@ -1500,8 +1503,8 @@ ${MEMHUB_PROTOCOL_INSTRUCTIONS}
|
|
|
1500
1503
|
*/
|
|
1501
1504
|
static injectAntigravity(cwd = process.cwd()) {
|
|
1502
1505
|
const localRule = path4.join(cwd, ".gemini", "antigravity-cli", "rules", "memhub.md");
|
|
1503
|
-
const globalRule = path4.join(
|
|
1504
|
-
const legacyGlobalRule = path4.join(
|
|
1506
|
+
const globalRule = path4.join(getHomeDir(), ".gemini", "antigravity-cli", "rules", "memhub.md");
|
|
1507
|
+
const legacyGlobalRule = path4.join(getHomeDir(), ".gemini", "config", "rules", "memhub.md");
|
|
1505
1508
|
return [
|
|
1506
1509
|
this.injectIntoFile(localRule, "Antigravity (Workspace)"),
|
|
1507
1510
|
this.injectIntoFile(globalRule, "Antigravity (Global)"),
|
|
@@ -1513,7 +1516,7 @@ ${MEMHUB_PROTOCOL_INSTRUCTIONS}
|
|
|
1513
1516
|
*/
|
|
1514
1517
|
static injectWindsurf(cwd = process.cwd()) {
|
|
1515
1518
|
const local = this.injectIntoFile(path4.join(cwd, ".windsurfrules"), "Windsurf (.windsurfrules)");
|
|
1516
|
-
const global = this.injectIntoFile(path4.join(
|
|
1519
|
+
const global = this.injectIntoFile(path4.join(getHomeDir(), ".windsurfrules"), "Windsurf (Global .windsurfrules)");
|
|
1517
1520
|
return [local, global];
|
|
1518
1521
|
}
|
|
1519
1522
|
/**
|
|
@@ -1521,7 +1524,7 @@ ${MEMHUB_PROTOCOL_INSTRUCTIONS}
|
|
|
1521
1524
|
*/
|
|
1522
1525
|
static injectCline(cwd = process.cwd()) {
|
|
1523
1526
|
const local = this.injectIntoFile(path4.join(cwd, ".clinerules"), "Cline (.clinerules)");
|
|
1524
|
-
const global = this.injectIntoFile(path4.join(
|
|
1527
|
+
const global = this.injectIntoFile(path4.join(getHomeDir(), ".clinerules"), "Cline (Global .clinerules)");
|
|
1525
1528
|
return [local, global];
|
|
1526
1529
|
}
|
|
1527
1530
|
/**
|
|
@@ -1529,9 +1532,38 @@ ${MEMHUB_PROTOCOL_INSTRUCTIONS}
|
|
|
1529
1532
|
*/
|
|
1530
1533
|
static injectCodex(cwd = process.cwd()) {
|
|
1531
1534
|
const localAgents = this.injectIntoFile(path4.join(cwd, "AGENTS.md"), "Agents Specification (AGENTS.md)");
|
|
1532
|
-
const globalCodex = this.injectIntoFile(path4.join(
|
|
1535
|
+
const globalCodex = this.injectIntoFile(path4.join(getHomeDir(), ".codex", "instructions.md"), "Codex CLI (Global instructions)");
|
|
1533
1536
|
return [localAgents, globalCodex];
|
|
1534
1537
|
}
|
|
1538
|
+
/**
|
|
1539
|
+
* Injects rules for OpenCode CLI (`OPENCODE.md` and `~/.config/opencode/rules/memhub.md`)
|
|
1540
|
+
*/
|
|
1541
|
+
static injectOpenCode(cwd = process.cwd()) {
|
|
1542
|
+
const local = this.injectIntoFile(path4.join(cwd, "OPENCODE.md"), "OpenCode (Workspace OPENCODE.md)");
|
|
1543
|
+
const global1 = this.injectIntoFile(path4.join(getHomeDir(), ".config", "opencode", "rules", "memhub.md"), "OpenCode (Global ~/.config/opencode)");
|
|
1544
|
+
const global2 = this.injectIntoFile(path4.join(getHomeDir(), ".opencode", "rules.md"), "OpenCode (Global ~/.opencode)");
|
|
1545
|
+
return [local, global1, global2];
|
|
1546
|
+
}
|
|
1547
|
+
/**
|
|
1548
|
+
* Injects rules for Alibaba Qwen Code / Qwen Agent (`.qwenrules`, `QWEN.md`, and `~/.qwen/rules.md`)
|
|
1549
|
+
*/
|
|
1550
|
+
static injectQwen(cwd = process.cwd()) {
|
|
1551
|
+
const localRules = this.injectIntoFile(path4.join(cwd, ".qwenrules"), "Qwen (.qwenrules)");
|
|
1552
|
+
const localMd = this.injectIntoFile(path4.join(cwd, "QWEN.md"), "Qwen (Workspace QWEN.md)");
|
|
1553
|
+
const globalQwen = this.injectIntoFile(path4.join(getHomeDir(), ".qwen", "rules.md"), "Qwen (Global ~/.qwen/rules.md)");
|
|
1554
|
+
const globalDotRules = this.injectIntoFile(path4.join(getHomeDir(), ".qwenrules"), "Qwen (Global ~/.qwenrules)");
|
|
1555
|
+
return [localRules, localMd, globalQwen, globalDotRules];
|
|
1556
|
+
}
|
|
1557
|
+
/**
|
|
1558
|
+
* Injects rules for DeepSeek Harness / CLI (`.deepseekrules`, `DEEPSEEK.md`, and `~/.deepseek/rules.md`)
|
|
1559
|
+
*/
|
|
1560
|
+
static injectDeepSeek(cwd = process.cwd()) {
|
|
1561
|
+
const localRules = this.injectIntoFile(path4.join(cwd, ".deepseekrules"), "DeepSeek (.deepseekrules)");
|
|
1562
|
+
const localMd = this.injectIntoFile(path4.join(cwd, "DEEPSEEK.md"), "DeepSeek (Workspace DEEPSEEK.md)");
|
|
1563
|
+
const globalDeepSeek = this.injectIntoFile(path4.join(getHomeDir(), ".deepseek", "rules.md"), "DeepSeek (Global ~/.deepseek/rules.md)");
|
|
1564
|
+
const globalDotRules = this.injectIntoFile(path4.join(getHomeDir(), ".deepseekrules"), "DeepSeek (Global ~/.deepseekrules)");
|
|
1565
|
+
return [localRules, localMd, globalDeepSeek, globalDotRules];
|
|
1566
|
+
}
|
|
1535
1567
|
/**
|
|
1536
1568
|
* Injects rules across all supported AI coding agents globally and locally.
|
|
1537
1569
|
*/
|
|
@@ -1542,26 +1574,197 @@ ${MEMHUB_PROTOCOL_INSTRUCTIONS}
|
|
|
1542
1574
|
...this.injectAntigravity(cwd),
|
|
1543
1575
|
...this.injectWindsurf(cwd),
|
|
1544
1576
|
...this.injectCline(cwd),
|
|
1545
|
-
...this.injectCodex(cwd)
|
|
1577
|
+
...this.injectCodex(cwd),
|
|
1578
|
+
...this.injectOpenCode(cwd),
|
|
1579
|
+
...this.injectQwen(cwd),
|
|
1580
|
+
...this.injectDeepSeek(cwd)
|
|
1581
|
+
];
|
|
1582
|
+
}
|
|
1583
|
+
};
|
|
1584
|
+
|
|
1585
|
+
// src/connectors/skills-injector.ts
|
|
1586
|
+
import fs5 from "fs";
|
|
1587
|
+
import path5 from "path";
|
|
1588
|
+
import os3 from "os";
|
|
1589
|
+
function getHomeDir2() {
|
|
1590
|
+
return process.env.HOME || os3.homedir();
|
|
1591
|
+
}
|
|
1592
|
+
var MEMHUB_SKILL_MD = `---
|
|
1593
|
+
name: memhub
|
|
1594
|
+
description: Persistent, synchronized team memory and architecture decision logger for AI coding assistants. Use when saving decisions, searching previous solutions, querying shared project context, or closing sessions.
|
|
1595
|
+
---
|
|
1596
|
+
|
|
1597
|
+
# MemHub Persistent Memory Skill
|
|
1598
|
+
|
|
1599
|
+
MemHub synchronizes architectural decisions, bug fixes, technical patterns, and project knowledge across teammates and AI coding agents.
|
|
1600
|
+
|
|
1601
|
+
## Core Capabilities
|
|
1602
|
+
|
|
1603
|
+
1. **Autonomous Knowledge Ingestion**: Call \`mem_save\` immediately upon completing bugfixes, making architecture decisions, or establishing conventions.
|
|
1604
|
+
2. **Proactive Hybrid Retrieval**: Call \`mem_search\` and \`mem_context\` before beginning unfamiliar tasks to benefit from previous solutions.
|
|
1605
|
+
3. **Architecture Invariant Protection**: Call \`mem_pin\` to mark critical constraints into the team's \`/rules\` registry.
|
|
1606
|
+
4. **Session Handoff & Compaction Recovery**: Call \`mem_session_summary\` before declaring a milestone completed.
|
|
1607
|
+
|
|
1608
|
+
## Slash Commands Quick Reference
|
|
1609
|
+
|
|
1610
|
+
- \`/mem-save\`: Saves the latest code changes, bugfixes, or decisions as a structured observation.
|
|
1611
|
+
- \`/mem-search <query>\`: Searches team memories and previous solutions with hybrid lexical + vector ranking.
|
|
1612
|
+
- \`/mem-summary\`: Generates a structured session summary (Goal, Discoveries, Accomplished, Next Steps).
|
|
1613
|
+
- \`/mem-status\`: Displays connection status, device ID, and pending outbox events.
|
|
1614
|
+
|
|
1615
|
+
## When to Save (Mandatory)
|
|
1616
|
+
|
|
1617
|
+
Call \`mem_save\` immediately after:
|
|
1618
|
+
- Resolving a non-trivial bug
|
|
1619
|
+
- Deciding on a library, data structure, or design pattern
|
|
1620
|
+
- Configuring CI/CD, environment variables, or cloud infrastructure
|
|
1621
|
+
- Learning a user constraint or project convention
|
|
1622
|
+
`;
|
|
1623
|
+
var CLAUDE_COMMAND_SAVE = `Save a persistent memory observation of the latest work done using the \`mem_save\` tool.
|
|
1624
|
+
Include:
|
|
1625
|
+
- title: Verb + what (e.g. "Configured JWT Auth", "Fixed N+1 query in UserList")
|
|
1626
|
+
- type: bugfix | decision | architecture | discovery | pattern | config | preference
|
|
1627
|
+
- content:
|
|
1628
|
+
**What**: One sentence summary of what was done.
|
|
1629
|
+
**Why**: The motivation or problem solved.
|
|
1630
|
+
**Where**: Affected files and directories.
|
|
1631
|
+
**Learned**: Surprises, edge cases, or gotchas (if any).
|
|
1632
|
+
`;
|
|
1633
|
+
var CLAUDE_COMMAND_SEARCH = `Search the MemHub shared knowledge base for relevant past solutions, decisions, and patterns using the \`mem_search\` tool with the user's query: \`$ARGUMENTS\`.
|
|
1634
|
+
Provide a clear summary of findings with references.
|
|
1635
|
+
`;
|
|
1636
|
+
var CLAUDE_COMMAND_SUMMARY = `Generate and persist a structured session summary using the \`mem_session_summary\` tool.
|
|
1637
|
+
Structure:
|
|
1638
|
+
## Goal
|
|
1639
|
+
What we worked on in this session.
|
|
1640
|
+
|
|
1641
|
+
## Discoveries
|
|
1642
|
+
Technical findings, gotchas, or surprising behaviors discovered.
|
|
1643
|
+
|
|
1644
|
+
## Accomplished
|
|
1645
|
+
Key items completed.
|
|
1646
|
+
|
|
1647
|
+
## Next Steps
|
|
1648
|
+
Remaining tasks for subsequent sessions.
|
|
1649
|
+
|
|
1650
|
+
## Relevant Files
|
|
1651
|
+
Files touched and their purpose.
|
|
1652
|
+
`;
|
|
1653
|
+
var CLAUDE_COMMAND_STATUS = `Check and display the MemHub synchronization status using the \`memhub_sync_status\` tool.
|
|
1654
|
+
Show device ID, active project, outbox pending count, and cloud connection state.
|
|
1655
|
+
`;
|
|
1656
|
+
var SkillsInjector = class {
|
|
1657
|
+
/**
|
|
1658
|
+
* Injects slash commands for Claude Code in workspace and global ~/.claude/commands
|
|
1659
|
+
*/
|
|
1660
|
+
static injectClaudeCommands(cwd = process.cwd()) {
|
|
1661
|
+
const targets = [
|
|
1662
|
+
path5.join(cwd, ".claude", "commands"),
|
|
1663
|
+
path5.join(getHomeDir2(), ".claude", "commands")
|
|
1664
|
+
];
|
|
1665
|
+
for (const dir of targets) {
|
|
1666
|
+
try {
|
|
1667
|
+
if (!fs5.existsSync(dir)) fs5.mkdirSync(dir, { recursive: true });
|
|
1668
|
+
fs5.writeFileSync(path5.join(dir, "mem-save.md"), CLAUDE_COMMAND_SAVE, "utf8");
|
|
1669
|
+
fs5.writeFileSync(path5.join(dir, "mem-search.md"), CLAUDE_COMMAND_SEARCH, "utf8");
|
|
1670
|
+
fs5.writeFileSync(path5.join(dir, "mem-summary.md"), CLAUDE_COMMAND_SUMMARY, "utf8");
|
|
1671
|
+
fs5.writeFileSync(path5.join(dir, "mem-status.md"), CLAUDE_COMMAND_STATUS, "utf8");
|
|
1672
|
+
} catch {
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
/**
|
|
1677
|
+
* Injects Antigravity / Gemini CLI skill in workspace and global ~/.gemini/antigravity-cli/skills/memhub
|
|
1678
|
+
*/
|
|
1679
|
+
static injectAntigravitySkill(cwd = process.cwd()) {
|
|
1680
|
+
const targets = [
|
|
1681
|
+
path5.join(cwd, ".gemini", "antigravity-cli", "skills", "memhub"),
|
|
1682
|
+
path5.join(getHomeDir2(), ".gemini", "antigravity-cli", "skills", "memhub"),
|
|
1683
|
+
path5.join(getHomeDir2(), ".gemini", "config", "skills", "memhub")
|
|
1546
1684
|
];
|
|
1685
|
+
for (const dir of targets) {
|
|
1686
|
+
try {
|
|
1687
|
+
if (!fs5.existsSync(dir)) fs5.mkdirSync(dir, { recursive: true });
|
|
1688
|
+
fs5.writeFileSync(path5.join(dir, "SKILL.md"), MEMHUB_SKILL_MD, "utf8");
|
|
1689
|
+
} catch {
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
/**
|
|
1694
|
+
* Injects Codex CLI skill in global ~/.codex/skills/memhub
|
|
1695
|
+
*/
|
|
1696
|
+
static injectCodexSkill() {
|
|
1697
|
+
const dir = path5.join(getHomeDir2(), ".codex", "skills", "memhub");
|
|
1698
|
+
try {
|
|
1699
|
+
if (!fs5.existsSync(dir)) fs5.mkdirSync(dir, { recursive: true });
|
|
1700
|
+
fs5.writeFileSync(path5.join(dir, "SKILL.md"), MEMHUB_SKILL_MD, "utf8");
|
|
1701
|
+
} catch {
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
/**
|
|
1705
|
+
* Injects OpenCode skill in global ~/.config/opencode/skills/memhub
|
|
1706
|
+
*/
|
|
1707
|
+
static injectOpenCodeSkill() {
|
|
1708
|
+
const dir = path5.join(getHomeDir2(), ".config", "opencode", "skills", "memhub");
|
|
1709
|
+
try {
|
|
1710
|
+
if (!fs5.existsSync(dir)) fs5.mkdirSync(dir, { recursive: true });
|
|
1711
|
+
fs5.writeFileSync(path5.join(dir, "SKILL.md"), MEMHUB_SKILL_MD, "utf8");
|
|
1712
|
+
} catch {
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
/**
|
|
1716
|
+
* Injects Alibaba Qwen skill in global ~/.qwen/skills/memhub
|
|
1717
|
+
*/
|
|
1718
|
+
static injectQwenSkill() {
|
|
1719
|
+
const dir = path5.join(getHomeDir2(), ".qwen", "skills", "memhub");
|
|
1720
|
+
try {
|
|
1721
|
+
if (!fs5.existsSync(dir)) fs5.mkdirSync(dir, { recursive: true });
|
|
1722
|
+
fs5.writeFileSync(path5.join(dir, "SKILL.md"), MEMHUB_SKILL_MD, "utf8");
|
|
1723
|
+
} catch {
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
/**
|
|
1727
|
+
* Injects DeepSeek skill in global ~/.deepseek/skills/memhub
|
|
1728
|
+
*/
|
|
1729
|
+
static injectDeepSeekSkill() {
|
|
1730
|
+
const dir = path5.join(getHomeDir2(), ".deepseek", "skills", "memhub");
|
|
1731
|
+
try {
|
|
1732
|
+
if (!fs5.existsSync(dir)) fs5.mkdirSync(dir, { recursive: true });
|
|
1733
|
+
fs5.writeFileSync(path5.join(dir, "SKILL.md"), MEMHUB_SKILL_MD, "utf8");
|
|
1734
|
+
} catch {
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
/**
|
|
1738
|
+
* Injects all skills and slash commands across all supported AI environments.
|
|
1739
|
+
*/
|
|
1740
|
+
static injectAll(cwd = process.cwd()) {
|
|
1741
|
+
this.injectClaudeCommands(cwd);
|
|
1742
|
+
this.injectAntigravitySkill(cwd);
|
|
1743
|
+
this.injectCodexSkill();
|
|
1744
|
+
this.injectOpenCodeSkill();
|
|
1745
|
+
this.injectQwenSkill();
|
|
1746
|
+
this.injectDeepSeekSkill();
|
|
1547
1747
|
}
|
|
1548
1748
|
};
|
|
1549
1749
|
|
|
1550
1750
|
// src/connectors/ide-injector.ts
|
|
1751
|
+
function getHomeDir3() {
|
|
1752
|
+
return process.env.HOME || os4.homedir();
|
|
1753
|
+
}
|
|
1551
1754
|
var IdeConfigInjector = class {
|
|
1552
1755
|
static serverConfig() {
|
|
1553
1756
|
return { command: "memhub", args: ["serve"] };
|
|
1554
1757
|
}
|
|
1555
1758
|
static injectJsonMcpConfig(target, configPath, options) {
|
|
1556
1759
|
try {
|
|
1557
|
-
const parent =
|
|
1558
|
-
if (!
|
|
1760
|
+
const parent = path6.dirname(configPath);
|
|
1761
|
+
if (!fs6.existsSync(parent) && !options.dryRun) fs6.mkdirSync(parent, { recursive: true });
|
|
1559
1762
|
let config = { mcpServers: {} };
|
|
1560
|
-
if (
|
|
1763
|
+
if (fs6.existsSync(configPath)) config = JSON.parse(fs6.readFileSync(configPath, "utf8"));
|
|
1561
1764
|
config.mcpServers = config.mcpServers || {};
|
|
1562
1765
|
config.mcpServers.memhub = this.serverConfig();
|
|
1563
|
-
const existed =
|
|
1564
|
-
if (!options.dryRun)
|
|
1766
|
+
const existed = fs6.existsSync(configPath);
|
|
1767
|
+
if (!options.dryRun) fs6.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf8");
|
|
1565
1768
|
return { target, filePath: configPath, success: true, action: existed ? "updated" : "created" };
|
|
1566
1769
|
} catch (err) {
|
|
1567
1770
|
return { target, filePath: configPath, success: false, action: "error", error: err.message };
|
|
@@ -1572,23 +1775,24 @@ var IdeConfigInjector = class {
|
|
|
1572
1775
|
*/
|
|
1573
1776
|
static injectClaudeCode(options) {
|
|
1574
1777
|
const cwd = options.cwd || process.cwd();
|
|
1575
|
-
const configPath =
|
|
1778
|
+
const configPath = path6.join(cwd, "mcp.json");
|
|
1576
1779
|
try {
|
|
1577
1780
|
let config = { mcpServers: {} };
|
|
1578
|
-
if (
|
|
1579
|
-
config = JSON.parse(
|
|
1781
|
+
if (fs6.existsSync(configPath)) {
|
|
1782
|
+
config = JSON.parse(fs6.readFileSync(configPath, "utf8"));
|
|
1580
1783
|
}
|
|
1581
1784
|
config.mcpServers = config.mcpServers || {};
|
|
1582
1785
|
config.mcpServers.memhub = this.serverConfig();
|
|
1583
1786
|
if (!options.dryRun) {
|
|
1584
|
-
|
|
1787
|
+
fs6.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf8");
|
|
1585
1788
|
RulesInjector.injectClaudeCode(cwd);
|
|
1789
|
+
SkillsInjector.injectClaudeCommands(cwd);
|
|
1586
1790
|
}
|
|
1587
1791
|
return {
|
|
1588
1792
|
target: "Claude Code",
|
|
1589
1793
|
filePath: configPath,
|
|
1590
1794
|
success: true,
|
|
1591
|
-
action:
|
|
1795
|
+
action: fs6.existsSync(configPath) ? "updated" : "created"
|
|
1592
1796
|
};
|
|
1593
1797
|
} catch (err) {
|
|
1594
1798
|
return {
|
|
@@ -1605,27 +1809,27 @@ var IdeConfigInjector = class {
|
|
|
1605
1809
|
*/
|
|
1606
1810
|
static injectCursor(options) {
|
|
1607
1811
|
const cwd = options.cwd || process.cwd();
|
|
1608
|
-
const cursorDir =
|
|
1609
|
-
const configPath =
|
|
1812
|
+
const cursorDir = path6.join(cwd, ".cursor");
|
|
1813
|
+
const configPath = path6.join(cursorDir, "mcp.json");
|
|
1610
1814
|
try {
|
|
1611
|
-
if (!
|
|
1612
|
-
|
|
1815
|
+
if (!fs6.existsSync(cursorDir) && !options.dryRun) {
|
|
1816
|
+
fs6.mkdirSync(cursorDir, { recursive: true });
|
|
1613
1817
|
}
|
|
1614
1818
|
let config = { mcpServers: {} };
|
|
1615
|
-
if (
|
|
1616
|
-
config = JSON.parse(
|
|
1819
|
+
if (fs6.existsSync(configPath)) {
|
|
1820
|
+
config = JSON.parse(fs6.readFileSync(configPath, "utf8"));
|
|
1617
1821
|
}
|
|
1618
1822
|
config.mcpServers = config.mcpServers || {};
|
|
1619
1823
|
config.mcpServers.memhub = this.serverConfig();
|
|
1620
1824
|
if (!options.dryRun) {
|
|
1621
|
-
|
|
1825
|
+
fs6.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf8");
|
|
1622
1826
|
RulesInjector.injectCursor(cwd);
|
|
1623
1827
|
}
|
|
1624
1828
|
return {
|
|
1625
1829
|
target: "Cursor",
|
|
1626
1830
|
filePath: configPath,
|
|
1627
1831
|
success: true,
|
|
1628
|
-
action:
|
|
1832
|
+
action: fs6.existsSync(configPath) ? "updated" : "created"
|
|
1629
1833
|
};
|
|
1630
1834
|
} catch (err) {
|
|
1631
1835
|
return {
|
|
@@ -1641,11 +1845,12 @@ var IdeConfigInjector = class {
|
|
|
1641
1845
|
static injectAntigravity(options) {
|
|
1642
1846
|
const res = this.injectJsonMcpConfig(
|
|
1643
1847
|
"Google Antigravity",
|
|
1644
|
-
|
|
1848
|
+
path6.join(getHomeDir3(), ".gemini", "config", "mcp_config.json"),
|
|
1645
1849
|
options
|
|
1646
1850
|
);
|
|
1647
1851
|
if (res.success && !options.dryRun) {
|
|
1648
1852
|
RulesInjector.injectAntigravity(options.cwd || process.cwd());
|
|
1853
|
+
SkillsInjector.injectAntigravitySkill(options.cwd || process.cwd());
|
|
1649
1854
|
}
|
|
1650
1855
|
return res;
|
|
1651
1856
|
}
|
|
@@ -1653,7 +1858,7 @@ var IdeConfigInjector = class {
|
|
|
1653
1858
|
static injectWindsurf(options) {
|
|
1654
1859
|
const res = this.injectJsonMcpConfig(
|
|
1655
1860
|
"Windsurf",
|
|
1656
|
-
|
|
1861
|
+
path6.join(getHomeDir3(), ".codeium", "windsurf", "mcp_config.json"),
|
|
1657
1862
|
options
|
|
1658
1863
|
);
|
|
1659
1864
|
if (res.success && !options.dryRun) {
|
|
@@ -1665,7 +1870,7 @@ var IdeConfigInjector = class {
|
|
|
1665
1870
|
static injectCline(options) {
|
|
1666
1871
|
const res = this.injectJsonMcpConfig(
|
|
1667
1872
|
"Cline",
|
|
1668
|
-
|
|
1873
|
+
path6.join(getHomeDir3(), ".cline", "data", "settings", "cline_mcp_settings.json"),
|
|
1669
1874
|
options
|
|
1670
1875
|
);
|
|
1671
1876
|
if (res.success && !options.dryRun) {
|
|
@@ -1675,17 +1880,17 @@ var IdeConfigInjector = class {
|
|
|
1675
1880
|
}
|
|
1676
1881
|
/** Generic JSON client using the common { mcpServers: {} } format. */
|
|
1677
1882
|
static injectOther(configPath, options) {
|
|
1678
|
-
return this.injectJsonMcpConfig("Other MCP client",
|
|
1883
|
+
return this.injectJsonMcpConfig("Other MCP client", path6.resolve(configPath), options);
|
|
1679
1884
|
}
|
|
1680
1885
|
/**
|
|
1681
1886
|
* Injects config and memory rules for Codex CLI (`config.toml` and `AGENTS.md`)
|
|
1682
1887
|
*/
|
|
1683
1888
|
static injectCodex(options) {
|
|
1684
|
-
const codexDir =
|
|
1685
|
-
const configPath =
|
|
1889
|
+
const codexDir = path6.join(getHomeDir3(), ".codex");
|
|
1890
|
+
const configPath = path6.join(codexDir, "config.toml");
|
|
1686
1891
|
try {
|
|
1687
|
-
if (!
|
|
1688
|
-
|
|
1892
|
+
if (!fs6.existsSync(codexDir) && !options.dryRun) {
|
|
1893
|
+
fs6.mkdirSync(codexDir, { recursive: true });
|
|
1689
1894
|
}
|
|
1690
1895
|
const entry = `
|
|
1691
1896
|
# MemHub MCP Connector
|
|
@@ -1694,17 +1899,18 @@ command = "memhub"
|
|
|
1694
1899
|
args = ["serve"]
|
|
1695
1900
|
`;
|
|
1696
1901
|
let content = "";
|
|
1697
|
-
if (
|
|
1698
|
-
content =
|
|
1902
|
+
if (fs6.existsSync(configPath)) {
|
|
1903
|
+
content = fs6.readFileSync(configPath, "utf8");
|
|
1699
1904
|
}
|
|
1700
1905
|
if (!content.includes("[mcp.servers.memhub]")) {
|
|
1701
1906
|
content += entry;
|
|
1702
1907
|
if (!options.dryRun) {
|
|
1703
|
-
|
|
1908
|
+
fs6.writeFileSync(configPath, content, "utf8");
|
|
1704
1909
|
}
|
|
1705
1910
|
}
|
|
1706
1911
|
if (!options.dryRun) {
|
|
1707
1912
|
RulesInjector.injectCodex(options.cwd || process.cwd());
|
|
1913
|
+
SkillsInjector.injectCodexSkill();
|
|
1708
1914
|
}
|
|
1709
1915
|
return {
|
|
1710
1916
|
target: "Codex CLI",
|
|
@@ -1722,6 +1928,42 @@ args = ["serve"]
|
|
|
1722
1928
|
};
|
|
1723
1929
|
}
|
|
1724
1930
|
}
|
|
1931
|
+
/** OpenCode CLI global MCP configuration and rules. */
|
|
1932
|
+
static injectOpenCode(options) {
|
|
1933
|
+
const res = this.injectJsonMcpConfig(
|
|
1934
|
+
"OpenCode CLI",
|
|
1935
|
+
path6.join(getHomeDir3(), ".config", "opencode", "mcp.json"),
|
|
1936
|
+
options
|
|
1937
|
+
);
|
|
1938
|
+
if (!options.dryRun) {
|
|
1939
|
+
RulesInjector.injectOpenCode(options.cwd || process.cwd());
|
|
1940
|
+
}
|
|
1941
|
+
return res;
|
|
1942
|
+
}
|
|
1943
|
+
/** Alibaba Qwen Code / Qwen Agent global MCP configuration and rules. */
|
|
1944
|
+
static injectQwen(options) {
|
|
1945
|
+
const res = this.injectJsonMcpConfig(
|
|
1946
|
+
"Qwen Code",
|
|
1947
|
+
path6.join(getHomeDir3(), ".qwen", "mcp.json"),
|
|
1948
|
+
options
|
|
1949
|
+
);
|
|
1950
|
+
if (!options.dryRun) {
|
|
1951
|
+
RulesInjector.injectQwen(options.cwd || process.cwd());
|
|
1952
|
+
}
|
|
1953
|
+
return res;
|
|
1954
|
+
}
|
|
1955
|
+
/** DeepSeek Harness / CLI global MCP configuration and rules. */
|
|
1956
|
+
static injectDeepSeek(options) {
|
|
1957
|
+
const res = this.injectJsonMcpConfig(
|
|
1958
|
+
"DeepSeek CLI",
|
|
1959
|
+
path6.join(getHomeDir3(), ".deepseek", "mcp.json"),
|
|
1960
|
+
options
|
|
1961
|
+
);
|
|
1962
|
+
if (!options.dryRun) {
|
|
1963
|
+
RulesInjector.injectDeepSeek(options.cwd || process.cwd());
|
|
1964
|
+
}
|
|
1965
|
+
return res;
|
|
1966
|
+
}
|
|
1725
1967
|
/**
|
|
1726
1968
|
* Injects for all supported IDEs and tools
|
|
1727
1969
|
*/
|
|
@@ -1732,7 +1974,10 @@ args = ["serve"]
|
|
|
1732
1974
|
this.injectCodex(options),
|
|
1733
1975
|
this.injectAntigravity(options),
|
|
1734
1976
|
this.injectWindsurf(options),
|
|
1735
|
-
this.injectCline(options)
|
|
1977
|
+
this.injectCline(options),
|
|
1978
|
+
this.injectOpenCode(options),
|
|
1979
|
+
this.injectQwen(options),
|
|
1980
|
+
this.injectDeepSeek(options)
|
|
1736
1981
|
];
|
|
1737
1982
|
}
|
|
1738
1983
|
};
|
|
@@ -1742,11 +1987,11 @@ import { createInterface } from "node:readline/promises";
|
|
|
1742
1987
|
import { stdin as input, stdout as output } from "node:process";
|
|
1743
1988
|
import { hostname } from "node:os";
|
|
1744
1989
|
import { execSync as execSync2 } from "node:child_process";
|
|
1745
|
-
import
|
|
1990
|
+
import path8 from "node:path";
|
|
1746
1991
|
|
|
1747
1992
|
// src/update-notifier.ts
|
|
1748
|
-
import
|
|
1749
|
-
import
|
|
1993
|
+
import fs7 from "fs";
|
|
1994
|
+
import path7 from "path";
|
|
1750
1995
|
import https from "https";
|
|
1751
1996
|
var CHECK_INTERVAL_MS = 2 * 60 * 60 * 1e3;
|
|
1752
1997
|
var PACKAGE_NAME = "@simplexlat/memhub";
|
|
@@ -1797,7 +2042,7 @@ async function fetchLatestFromNpm() {
|
|
|
1797
2042
|
}
|
|
1798
2043
|
var UpdateNotifier = class {
|
|
1799
2044
|
static cacheFile() {
|
|
1800
|
-
return
|
|
2045
|
+
return path7.join(resolveStorageDir(), "update-cache.json");
|
|
1801
2046
|
}
|
|
1802
2047
|
static async checkForUpdates(currentVersion) {
|
|
1803
2048
|
if (process.argv.includes("serve") || process.argv.includes("update")) {
|
|
@@ -1808,9 +2053,9 @@ var UpdateNotifier = class {
|
|
|
1808
2053
|
ensureDirectory(storageDir);
|
|
1809
2054
|
const cachePath = this.cacheFile();
|
|
1810
2055
|
let cache = { lastChecked: 0, latestVersion: currentVersion };
|
|
1811
|
-
if (
|
|
2056
|
+
if (fs7.existsSync(cachePath)) {
|
|
1812
2057
|
try {
|
|
1813
|
-
cache = JSON.parse(
|
|
2058
|
+
cache = JSON.parse(fs7.readFileSync(cachePath, "utf8"));
|
|
1814
2059
|
} catch {
|
|
1815
2060
|
}
|
|
1816
2061
|
}
|
|
@@ -1821,7 +2066,7 @@ var UpdateNotifier = class {
|
|
|
1821
2066
|
if (fetched) {
|
|
1822
2067
|
cache = { lastChecked: Date.now(), latestVersion: fetched };
|
|
1823
2068
|
try {
|
|
1824
|
-
|
|
2069
|
+
fs7.writeFileSync(cachePath, JSON.stringify(cache), "utf8");
|
|
1825
2070
|
} catch {
|
|
1826
2071
|
}
|
|
1827
2072
|
}
|
|
@@ -1940,7 +2185,7 @@ function openInBrowser(url) {
|
|
|
1940
2185
|
}
|
|
1941
2186
|
|
|
1942
2187
|
// src/cli.ts
|
|
1943
|
-
var CLI_VERSION = "0.1.
|
|
2188
|
+
var CLI_VERSION = "0.1.4";
|
|
1944
2189
|
void UpdateNotifier.checkForUpdates(CLI_VERSION);
|
|
1945
2190
|
var program = new Command();
|
|
1946
2191
|
var supportedTargets = ["claude", "cursor", "windsurf", "cline", "codex", "antigravity"];
|
|
@@ -2000,7 +2245,7 @@ async function installToSelectedClients(options) {
|
|
|
2000
2245
|
}
|
|
2001
2246
|
}
|
|
2002
2247
|
}
|
|
2003
|
-
program.name("memhub").description("Local-first MCP proxy for MemHub & agentmemory").version("0.1.
|
|
2248
|
+
program.name("memhub").description("Local-first MCP proxy for MemHub & agentmemory").version("0.1.4");
|
|
2004
2249
|
program.command("serve").description("Start the MemHub MCP stdio proxy server").action(async () => {
|
|
2005
2250
|
const config = getConfig();
|
|
2006
2251
|
const server = new MemHubMcpServer(config);
|
|
@@ -2223,7 +2468,7 @@ program.command("flush").description("Force an immediate push of all pending out
|
|
|
2223
2468
|
});
|
|
2224
2469
|
program.command("rules").description("Inject or update MemHub persistent memory protocol instructions into all AI client rules").option("--cwd <path>", "Workspace directory to target", process.cwd()).action(async (options) => {
|
|
2225
2470
|
console.log("\u{1F4DD} Injecting MemHub memory protocol rules into AI client configuration files...");
|
|
2226
|
-
const results = RulesInjector.injectAll(
|
|
2471
|
+
const results = RulesInjector.injectAll(path8.resolve(options.cwd));
|
|
2227
2472
|
for (const res of results) {
|
|
2228
2473
|
if (res.success) {
|
|
2229
2474
|
console.log(` \u2713 ${res.target}: ${res.action} at ${res.filePath}`);
|
|
@@ -2231,6 +2476,9 @@ program.command("rules").description("Inject or update MemHub persistent memory
|
|
|
2231
2476
|
console.log(` \u2717 ${res.target}: ${res.error}`);
|
|
2232
2477
|
}
|
|
2233
2478
|
}
|
|
2479
|
+
SkillsInjector.injectAll(path8.resolve(options.cwd));
|
|
2480
|
+
console.log(" \u2713 Slash Commands (/mem-save, /mem-search, /mem-summary, /mem-status): configured");
|
|
2481
|
+
console.log(" \u2713 Agent Skills: memhub/SKILL.md configured");
|
|
2234
2482
|
console.log("\n\u2728 AI agents in this workspace and globally will now proactively save and recall team memories.");
|
|
2235
2483
|
});
|
|
2236
2484
|
program.command("update").description("Check for updates and upgrade @simplexlat/memhub to the latest version").option("--canary", "Install prerelease canary build").action(async (options) => {
|