@simplexlat/memhub 0.1.3 → 0.1.5

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 CHANGED
@@ -1348,9 +1348,9 @@ function getConfig() {
1348
1348
  }
1349
1349
 
1350
1350
  // src/connectors/ide-injector.ts
1351
- import fs5 from "fs";
1352
- import path5 from "path";
1353
- import os3 from "os";
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(os2.homedir(), ".claude", "CLAUDE.md");
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(os2.homedir(), ".cursorrules"), "Cursor (Global .cursorrules)");
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(os2.homedir(), ".gemini", "antigravity-cli", "rules", "memhub.md");
1504
- const legacyGlobalRule = path4.join(os2.homedir(), ".gemini", "config", "rules", "memhub.md");
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(os2.homedir(), ".windsurfrules"), "Windsurf (Global .windsurfrules)");
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(os2.homedir(), ".clinerules"), "Cline (Global .clinerules)");
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(os2.homedir(), ".codex", "instructions.md"), "Codex CLI (Global instructions)");
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)
1546
1581
  ];
1547
1582
  }
1548
1583
  };
1549
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")
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();
1747
+ }
1748
+ };
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 = path5.dirname(configPath);
1558
- if (!fs5.existsSync(parent) && !options.dryRun) fs5.mkdirSync(parent, { recursive: true });
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 (fs5.existsSync(configPath)) config = JSON.parse(fs5.readFileSync(configPath, "utf8"));
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 = fs5.existsSync(configPath);
1564
- if (!options.dryRun) fs5.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf8");
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 = path5.join(cwd, "mcp.json");
1778
+ const configPath = path6.join(cwd, "mcp.json");
1576
1779
  try {
1577
1780
  let config = { mcpServers: {} };
1578
- if (fs5.existsSync(configPath)) {
1579
- config = JSON.parse(fs5.readFileSync(configPath, "utf8"));
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
- fs5.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf8");
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: fs5.existsSync(configPath) ? "updated" : "created"
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 = path5.join(cwd, ".cursor");
1609
- const configPath = path5.join(cursorDir, "mcp.json");
1812
+ const cursorDir = path6.join(cwd, ".cursor");
1813
+ const configPath = path6.join(cursorDir, "mcp.json");
1610
1814
  try {
1611
- if (!fs5.existsSync(cursorDir) && !options.dryRun) {
1612
- fs5.mkdirSync(cursorDir, { recursive: true });
1815
+ if (!fs6.existsSync(cursorDir) && !options.dryRun) {
1816
+ fs6.mkdirSync(cursorDir, { recursive: true });
1613
1817
  }
1614
1818
  let config = { mcpServers: {} };
1615
- if (fs5.existsSync(configPath)) {
1616
- config = JSON.parse(fs5.readFileSync(configPath, "utf8"));
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
- fs5.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf8");
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: fs5.existsSync(configPath) ? "updated" : "created"
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
- path5.join(os3.homedir(), ".gemini", "config", "mcp_config.json"),
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
- path5.join(os3.homedir(), ".codeium", "windsurf", "mcp_config.json"),
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
- path5.join(os3.homedir(), ".cline", "data", "settings", "cline_mcp_settings.json"),
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", path5.resolve(configPath), options);
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 = path5.join(os3.homedir(), ".codex");
1685
- const configPath = path5.join(codexDir, "config.toml");
1889
+ const codexDir = path6.join(getHomeDir3(), ".codex");
1890
+ const configPath = path6.join(codexDir, "config.toml");
1686
1891
  try {
1687
- if (!fs5.existsSync(codexDir) && !options.dryRun) {
1688
- fs5.mkdirSync(codexDir, { recursive: true });
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 (fs5.existsSync(configPath)) {
1698
- content = fs5.readFileSync(configPath, "utf8");
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
- fs5.writeFileSync(configPath, content, "utf8");
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 path7 from "node:path";
1990
+ import path8 from "node:path";
1746
1991
 
1747
1992
  // src/update-notifier.ts
1748
- import fs6 from "fs";
1749
- import path6 from "path";
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 path6.join(resolveStorageDir(), "update-cache.json");
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 (fs6.existsSync(cachePath)) {
2056
+ if (fs7.existsSync(cachePath)) {
1812
2057
  try {
1813
- cache = JSON.parse(fs6.readFileSync(cachePath, "utf8"));
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
- fs6.writeFileSync(cachePath, JSON.stringify(cache), "utf8");
2069
+ fs7.writeFileSync(cachePath, JSON.stringify(cache), "utf8");
1825
2070
  } catch {
1826
2071
  }
1827
2072
  }
@@ -1940,10 +2185,10 @@ function openInBrowser(url) {
1940
2185
  }
1941
2186
 
1942
2187
  // src/cli.ts
1943
- var CLI_VERSION = "0.1.3";
2188
+ var CLI_VERSION = "0.1.5";
1944
2189
  void UpdateNotifier.checkForUpdates(CLI_VERSION);
1945
2190
  var program = new Command();
1946
- var supportedTargets = ["claude", "cursor", "windsurf", "cline", "codex", "antigravity"];
2191
+ var supportedTargets = ["claude", "cursor", "windsurf", "cline", "codex", "antigravity", "opencode", "qwen", "deepseek"];
1947
2192
  async function selectInstallTargets(value, otherConfig) {
1948
2193
  if (value) {
1949
2194
  const requested = value.toLowerCase().split(",").map((item) => item.trim()).filter(Boolean);
@@ -1956,12 +2201,23 @@ async function selectInstallTargets(value, otherConfig) {
1956
2201
  if (!input.isTTY || !output.isTTY) return [...supportedTargets];
1957
2202
  const rl = createInterface({ input, output });
1958
2203
  output.write("\nWhere should MemHub be installed? Select one or more (comma-separated):\n");
1959
- output.write(" 1) Claude Code\n 2) Cursor\n 3) Windsurf\n 4) Cline\n 5) Codex CLI\n 6) Google Antigravity\n 7) All supported clients\n 8) Other JSON MCP client\n");
1960
- const answer = await rl.question("Selection [7]: ");
2204
+ output.write(" 1) Claude Code\n 2) Cursor\n 3) Windsurf\n 4) Cline\n 5) Codex CLI\n 6) Google Antigravity\n 7) OpenCode CLI\n 8) Alibaba Qwen Code\n 9) DeepSeek CLI / Harness\n 10) All supported clients\n 11) Other JSON MCP client\n");
2205
+ const answer = await rl.question("Selection [10]: ");
1961
2206
  rl.close();
1962
- const choices = (answer.trim() || "7").split(",").map((item) => item.trim());
1963
- if (choices.includes("7")) return [...supportedTargets];
1964
- const map = { "1": "claude", "2": "cursor", "3": "windsurf", "4": "cline", "5": "codex", "6": "antigravity", "8": "other" };
2207
+ const choices = (answer.trim() || "10").split(",").map((item) => item.trim());
2208
+ if (choices.includes("10")) return [...supportedTargets];
2209
+ const map = {
2210
+ "1": "claude",
2211
+ "2": "cursor",
2212
+ "3": "windsurf",
2213
+ "4": "cline",
2214
+ "5": "codex",
2215
+ "6": "antigravity",
2216
+ "7": "opencode",
2217
+ "8": "qwen",
2218
+ "9": "deepseek",
2219
+ "11": "other"
2220
+ };
1965
2221
  const selected = choices.map((choice) => map[choice]).filter(Boolean);
1966
2222
  if (!selected.length) throw new Error("No valid installation target selected");
1967
2223
  if (selected.includes("other") && !otherConfig) throw new Error("Use --config <path> when selecting Other");
@@ -1983,6 +2239,9 @@ async function installToSelectedClients(options) {
1983
2239
  if (target === "cline") results.push(IdeConfigInjector.injectCline(injectOpts));
1984
2240
  if (target === "codex") results.push(IdeConfigInjector.injectCodex(injectOpts));
1985
2241
  if (target === "antigravity") results.push(IdeConfigInjector.injectAntigravity(injectOpts));
2242
+ if (target === "opencode") results.push(IdeConfigInjector.injectOpenCode(injectOpts));
2243
+ if (target === "qwen") results.push(IdeConfigInjector.injectQwen(injectOpts));
2244
+ if (target === "deepseek") results.push(IdeConfigInjector.injectDeepSeek(injectOpts));
1986
2245
  if (target === "other") results.push(IdeConfigInjector.injectOther(options.configPath, injectOpts));
1987
2246
  }
1988
2247
  for (const res of results) {
@@ -2000,7 +2259,7 @@ async function installToSelectedClients(options) {
2000
2259
  }
2001
2260
  }
2002
2261
  }
2003
- program.name("memhub").description("Local-first MCP proxy for MemHub & agentmemory").version("0.1.3");
2262
+ program.name("memhub").description("Local-first MCP proxy for MemHub & agentmemory").version("0.1.5");
2004
2263
  program.command("serve").description("Start the MemHub MCP stdio proxy server").action(async () => {
2005
2264
  const config = getConfig();
2006
2265
  const server = new MemHubMcpServer(config);
@@ -2223,7 +2482,7 @@ program.command("flush").description("Force an immediate push of all pending out
2223
2482
  });
2224
2483
  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
2484
  console.log("\u{1F4DD} Injecting MemHub memory protocol rules into AI client configuration files...");
2226
- const results = RulesInjector.injectAll(path7.resolve(options.cwd));
2485
+ const results = RulesInjector.injectAll(path8.resolve(options.cwd));
2227
2486
  for (const res of results) {
2228
2487
  if (res.success) {
2229
2488
  console.log(` \u2713 ${res.target}: ${res.action} at ${res.filePath}`);
@@ -2231,6 +2490,9 @@ program.command("rules").description("Inject or update MemHub persistent memory
2231
2490
  console.log(` \u2717 ${res.target}: ${res.error}`);
2232
2491
  }
2233
2492
  }
2493
+ SkillsInjector.injectAll(path8.resolve(options.cwd));
2494
+ console.log(" \u2713 Slash Commands (/mem-save, /mem-search, /mem-summary, /mem-status): configured");
2495
+ console.log(" \u2713 Agent Skills: memhub/SKILL.md configured");
2234
2496
  console.log("\n\u2728 AI agents in this workspace and globally will now proactively save and recall team memories.");
2235
2497
  });
2236
2498
  program.command("update").description("Check for updates and upgrade @simplexlat/memhub to the latest version").option("--canary", "Install prerelease canary build").action(async (options) => {