@simplexlat/memhub 0.1.2 → 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 CHANGED
@@ -753,7 +753,8 @@ var CloudApiClient = class {
753
753
  headers: this.getHeaders(),
754
754
  body: JSON.stringify({ slug: "__health_check__" })
755
755
  });
756
- return { ok: res.ok || res.status === 401 || res.status === 400, status: res.status };
756
+ const reachable = res.ok || res.status === 400 || res.status === 401 || res.status === 429;
757
+ return { ok: reachable, status: res.status, message: reachable ? void 0 : `HTTP ${res.status}` };
757
758
  } catch (err) {
758
759
  return { ok: false, status: 0, message: err.message };
759
760
  }
@@ -1347,9 +1348,9 @@ function getConfig() {
1347
1348
  }
1348
1349
 
1349
1350
  // src/connectors/ide-injector.ts
1350
- import fs5 from "fs";
1351
- import path5 from "path";
1352
- import os3 from "os";
1351
+ import fs6 from "fs";
1352
+ import path6 from "path";
1353
+ import os4 from "os";
1353
1354
 
1354
1355
  // src/connectors/rules-injector.ts
1355
1356
  import fs4 from "fs";
@@ -1361,17 +1362,17 @@ var MEMHUB_PROTOCOL_INSTRUCTIONS = `${MEMHUB_RULES_BEGIN_MARKER}
1361
1362
 
1362
1363
  ## MemHub Persistent Shared Memory \u2014 Protocol
1363
1364
 
1364
- You have access to MemHub, a persistent memory and team knowledge system that survives across sessions, compactions, and teammates.
1365
+ You have access to MemHub, a persistent memory and team knowledge system that survives across sessions, compactions, teammates, and repositories.
1365
1366
 
1366
1367
  ### WHEN TO SAVE TO MEMORY (mandatory \u2014 not optional)
1367
1368
 
1368
- Call \`mem_save\` (or \`memory_save\`) IMMEDIATELY after any of these:
1369
+ You must autonomously call \`mem_save\` (or \`memory_save\`) IMMEDIATELY after any of these events without asking the user:
1369
1370
  - Bug fix completed
1370
1371
  - Architecture or design decision made
1371
- - Non-obvious discovery about the codebase
1372
- - Configuration change or environment setup
1372
+ - Non-obvious discovery about the codebase or dependencies
1373
+ - Configuration change, environment setup, or deployment step
1373
1374
  - Pattern established (naming, structure, convention)
1374
- - User preference or team constraint learned
1375
+ - User preference, constraint, or requirement learned
1375
1376
 
1376
1377
  Format for \`mem_save\`:
1377
1378
  - **title**: Verb + what \u2014 short, searchable (e.g. "Fixed N+1 query in UserList", "Chose Zustand over Redux")
@@ -1384,31 +1385,62 @@ Format for \`mem_save\`:
1384
1385
  **Where**: Files or paths affected
1385
1386
  **Learned**: Gotchas, edge cases, things that surprised you (omit if none)
1386
1387
 
1388
+ ### MULTI-PROJECT & NEW REPOSITORY AUTONOMY
1389
+
1390
+ MemHub automatically detects the Git repository and folder context. When you save a memory in a new repository or workspace, MemHub autonomously connects it to the user's organization in the cloud dashboard and links all memories.
1391
+
1392
+ ### Topic update rules (mandatory)
1393
+
1394
+ - Different topics must not overwrite each other (e.g. architecture vs bugfix)
1395
+ - Reuse the same \`topic_key\` to update an evolving topic instead of creating duplicate fragmented observations
1396
+ - If unsure about the key, call \`mem_suggest_topic_key\` first and reuse it
1397
+ - Use \`mem_update\` when you have an exact observation ID to update
1398
+
1387
1399
  ### WHEN TO SEARCH MEMORY (mandatory)
1388
1400
 
1389
- When the user asks to recall something or references past work ("remember", "recall", "what did we do", "c\xF3mo lo resolvimos", "qu\xE9 hicimos"):
1401
+ When the user asks to recall something or references past work ("remember", "recall", "what did we do", "c\xF3mo lo resolvimos", "qu\xE9 hicimos", or past session context):
1390
1402
  1. First call \`mem_context\` (fast recent session history)
1391
1403
  2. Call \`mem_search\` (or \`memory_recall\`) with relevant keywords (hybrid lexical + vector search)
1392
1404
  3. If needed, use \`mem_get_observation\` for full untruncated content
1393
1405
 
1394
1406
  Also search memory PROACTIVELY when:
1395
1407
  - Starting work on an unfamiliar area of the codebase
1396
- - The user mentions a technical topic you have no context on
1408
+ - The user mentions a technical topic you have no context on \u2014 check if past sessions covered it
1397
1409
 
1398
1410
  ### SESSION CLOSE PROTOCOL (mandatory)
1399
1411
 
1400
- Before ending a session or declaring a milestone done, call \`mem_session_summary\`:
1401
- - **Goal**: What was worked on this session
1402
- - **Discoveries**: Technical findings and gotchas
1403
- - **Accomplished**: Key completed items
1404
- - **Next Steps**: What remains for subsequent sessions
1405
- - **Relevant Files**: Changed files and their purpose
1412
+ Before ending a session or declaring a milestone done, you MUST call \`mem_session_summary\` with this structure:
1413
+
1414
+ ## Goal
1415
+ [What was worked on this session]
1416
+
1417
+ ## Instructions
1418
+ [User preferences or constraints discovered \u2014 skip if none]
1419
+
1420
+ ## Discoveries
1421
+ - [Technical findings, gotchas, non-obvious learnings]
1422
+
1423
+ ## Accomplished
1424
+ - [Completed items with key details]
1425
+
1426
+ ## Next Steps
1427
+ - [What remains to be done \u2014 for the next session]
1428
+
1429
+ ## Relevant Files
1430
+ - path/to/file \u2014 [what it does or what changed]
1406
1431
 
1407
1432
  ### PASSIVE CAPTURE
1408
1433
 
1409
- When completing a task, include a \`## Key Learnings:\` section at the end of your response with numbered items. MemHub will automatically capture and persist these learnings for the team.
1434
+ When completing a task or subtask, include a \`## Key Learnings:\` section at the end of your response with numbered items. MemHub will automatically capture and persist these learnings for the team.
1435
+
1436
+ ### AFTER COMPACTION
1437
+
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.
1410
1439
 
1411
1440
  ${MEMHUB_RULES_END_MARKER}`;
1441
+ function getHomeDir() {
1442
+ return process.env.HOME || os2.homedir();
1443
+ }
1412
1444
  var RulesInjector = class {
1413
1445
  /**
1414
1446
  * Injects or updates the managed MemHub rules block inside a markdown file.
@@ -1452,7 +1484,7 @@ ${MEMHUB_PROTOCOL_INSTRUCTIONS}
1452
1484
  */
1453
1485
  static injectClaudeCode(cwd = process.cwd()) {
1454
1486
  const local = this.injectIntoFile(path4.join(cwd, "CLAUDE.md"), "Claude Code (Workspace)");
1455
- const globalPath = path4.join(os2.homedir(), ".claude", "CLAUDE.md");
1487
+ const globalPath = path4.join(getHomeDir(), ".claude", "CLAUDE.md");
1456
1488
  const global = this.injectIntoFile(globalPath, "Claude Code (Global)");
1457
1489
  return [local, global];
1458
1490
  }
@@ -1463,15 +1495,16 @@ ${MEMHUB_PROTOCOL_INSTRUCTIONS}
1463
1495
  const cursorRules = this.injectIntoFile(path4.join(cwd, ".cursorrules"), "Cursor (.cursorrules)");
1464
1496
  const mdcPath = path4.join(cwd, ".cursor", "rules", "memhub.mdc");
1465
1497
  const mdc = this.injectIntoFile(mdcPath, "Cursor MDC (.cursor/rules/memhub.mdc)");
1466
- return [cursorRules, mdc];
1498
+ const globalCursor = this.injectIntoFile(path4.join(getHomeDir(), ".cursorrules"), "Cursor (Global .cursorrules)");
1499
+ return [cursorRules, mdc, globalCursor];
1467
1500
  }
1468
1501
  /**
1469
1502
  * Injects rules for Google Antigravity / Gemini CLI
1470
1503
  */
1471
1504
  static injectAntigravity(cwd = process.cwd()) {
1472
1505
  const localRule = path4.join(cwd, ".gemini", "antigravity-cli", "rules", "memhub.md");
1473
- const globalRule = path4.join(os2.homedir(), ".gemini", "antigravity-cli", "rules", "memhub.md");
1474
- 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");
1475
1508
  return [
1476
1509
  this.injectIntoFile(localRule, "Antigravity (Workspace)"),
1477
1510
  this.injectIntoFile(globalRule, "Antigravity (Global)"),
@@ -1482,24 +1515,57 @@ ${MEMHUB_PROTOCOL_INSTRUCTIONS}
1482
1515
  * Injects rules for Windsurf (`.windsurfrules`)
1483
1516
  */
1484
1517
  static injectWindsurf(cwd = process.cwd()) {
1485
- return [this.injectIntoFile(path4.join(cwd, ".windsurfrules"), "Windsurf (.windsurfrules)")];
1518
+ const local = this.injectIntoFile(path4.join(cwd, ".windsurfrules"), "Windsurf (.windsurfrules)");
1519
+ const global = this.injectIntoFile(path4.join(getHomeDir(), ".windsurfrules"), "Windsurf (Global .windsurfrules)");
1520
+ return [local, global];
1486
1521
  }
1487
1522
  /**
1488
1523
  * Injects rules for Cline / Roo Code (`.clinerules`)
1489
1524
  */
1490
1525
  static injectCline(cwd = process.cwd()) {
1491
- return [this.injectIntoFile(path4.join(cwd, ".clinerules"), "Cline (.clinerules)")];
1526
+ const local = this.injectIntoFile(path4.join(cwd, ".clinerules"), "Cline (.clinerules)");
1527
+ const global = this.injectIntoFile(path4.join(getHomeDir(), ".clinerules"), "Cline (Global .clinerules)");
1528
+ return [local, global];
1492
1529
  }
1493
1530
  /**
1494
1531
  * Injects rules for Codex CLI & General Agent specification (`AGENTS.md`)
1495
1532
  */
1496
1533
  static injectCodex(cwd = process.cwd()) {
1497
1534
  const localAgents = this.injectIntoFile(path4.join(cwd, "AGENTS.md"), "Agents Specification (AGENTS.md)");
1498
- 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)");
1499
1536
  return [localAgents, globalCodex];
1500
1537
  }
1501
1538
  /**
1502
- * Injects rules across all supported AI coding agents.
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
+ }
1567
+ /**
1568
+ * Injects rules across all supported AI coding agents globally and locally.
1503
1569
  */
1504
1570
  static injectAll(cwd = process.cwd()) {
1505
1571
  return [
@@ -1508,26 +1574,197 @@ ${MEMHUB_PROTOCOL_INSTRUCTIONS}
1508
1574
  ...this.injectAntigravity(cwd),
1509
1575
  ...this.injectWindsurf(cwd),
1510
1576
  ...this.injectCline(cwd),
1511
- ...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")
1512
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();
1513
1747
  }
1514
1748
  };
1515
1749
 
1516
1750
  // src/connectors/ide-injector.ts
1751
+ function getHomeDir3() {
1752
+ return process.env.HOME || os4.homedir();
1753
+ }
1517
1754
  var IdeConfigInjector = class {
1518
1755
  static serverConfig() {
1519
1756
  return { command: "memhub", args: ["serve"] };
1520
1757
  }
1521
1758
  static injectJsonMcpConfig(target, configPath, options) {
1522
1759
  try {
1523
- const parent = path5.dirname(configPath);
1524
- 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 });
1525
1762
  let config = { mcpServers: {} };
1526
- if (fs5.existsSync(configPath)) config = JSON.parse(fs5.readFileSync(configPath, "utf8"));
1763
+ if (fs6.existsSync(configPath)) config = JSON.parse(fs6.readFileSync(configPath, "utf8"));
1527
1764
  config.mcpServers = config.mcpServers || {};
1528
1765
  config.mcpServers.memhub = this.serverConfig();
1529
- const existed = fs5.existsSync(configPath);
1530
- 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");
1531
1768
  return { target, filePath: configPath, success: true, action: existed ? "updated" : "created" };
1532
1769
  } catch (err) {
1533
1770
  return { target, filePath: configPath, success: false, action: "error", error: err.message };
@@ -1538,23 +1775,24 @@ var IdeConfigInjector = class {
1538
1775
  */
1539
1776
  static injectClaudeCode(options) {
1540
1777
  const cwd = options.cwd || process.cwd();
1541
- const configPath = path5.join(cwd, "mcp.json");
1778
+ const configPath = path6.join(cwd, "mcp.json");
1542
1779
  try {
1543
1780
  let config = { mcpServers: {} };
1544
- if (fs5.existsSync(configPath)) {
1545
- config = JSON.parse(fs5.readFileSync(configPath, "utf8"));
1781
+ if (fs6.existsSync(configPath)) {
1782
+ config = JSON.parse(fs6.readFileSync(configPath, "utf8"));
1546
1783
  }
1547
1784
  config.mcpServers = config.mcpServers || {};
1548
1785
  config.mcpServers.memhub = this.serverConfig();
1549
1786
  if (!options.dryRun) {
1550
- fs5.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf8");
1787
+ fs6.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf8");
1551
1788
  RulesInjector.injectClaudeCode(cwd);
1789
+ SkillsInjector.injectClaudeCommands(cwd);
1552
1790
  }
1553
1791
  return {
1554
1792
  target: "Claude Code",
1555
1793
  filePath: configPath,
1556
1794
  success: true,
1557
- action: fs5.existsSync(configPath) ? "updated" : "created"
1795
+ action: fs6.existsSync(configPath) ? "updated" : "created"
1558
1796
  };
1559
1797
  } catch (err) {
1560
1798
  return {
@@ -1571,27 +1809,27 @@ var IdeConfigInjector = class {
1571
1809
  */
1572
1810
  static injectCursor(options) {
1573
1811
  const cwd = options.cwd || process.cwd();
1574
- const cursorDir = path5.join(cwd, ".cursor");
1575
- const configPath = path5.join(cursorDir, "mcp.json");
1812
+ const cursorDir = path6.join(cwd, ".cursor");
1813
+ const configPath = path6.join(cursorDir, "mcp.json");
1576
1814
  try {
1577
- if (!fs5.existsSync(cursorDir) && !options.dryRun) {
1578
- fs5.mkdirSync(cursorDir, { recursive: true });
1815
+ if (!fs6.existsSync(cursorDir) && !options.dryRun) {
1816
+ fs6.mkdirSync(cursorDir, { recursive: true });
1579
1817
  }
1580
1818
  let config = { mcpServers: {} };
1581
- if (fs5.existsSync(configPath)) {
1582
- config = JSON.parse(fs5.readFileSync(configPath, "utf8"));
1819
+ if (fs6.existsSync(configPath)) {
1820
+ config = JSON.parse(fs6.readFileSync(configPath, "utf8"));
1583
1821
  }
1584
1822
  config.mcpServers = config.mcpServers || {};
1585
1823
  config.mcpServers.memhub = this.serverConfig();
1586
1824
  if (!options.dryRun) {
1587
- fs5.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf8");
1825
+ fs6.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf8");
1588
1826
  RulesInjector.injectCursor(cwd);
1589
1827
  }
1590
1828
  return {
1591
1829
  target: "Cursor",
1592
1830
  filePath: configPath,
1593
1831
  success: true,
1594
- action: fs5.existsSync(configPath) ? "updated" : "created"
1832
+ action: fs6.existsSync(configPath) ? "updated" : "created"
1595
1833
  };
1596
1834
  } catch (err) {
1597
1835
  return {
@@ -1607,11 +1845,12 @@ var IdeConfigInjector = class {
1607
1845
  static injectAntigravity(options) {
1608
1846
  const res = this.injectJsonMcpConfig(
1609
1847
  "Google Antigravity",
1610
- path5.join(os3.homedir(), ".gemini", "config", "mcp_config.json"),
1848
+ path6.join(getHomeDir3(), ".gemini", "config", "mcp_config.json"),
1611
1849
  options
1612
1850
  );
1613
1851
  if (res.success && !options.dryRun) {
1614
1852
  RulesInjector.injectAntigravity(options.cwd || process.cwd());
1853
+ SkillsInjector.injectAntigravitySkill(options.cwd || process.cwd());
1615
1854
  }
1616
1855
  return res;
1617
1856
  }
@@ -1619,7 +1858,7 @@ var IdeConfigInjector = class {
1619
1858
  static injectWindsurf(options) {
1620
1859
  const res = this.injectJsonMcpConfig(
1621
1860
  "Windsurf",
1622
- path5.join(os3.homedir(), ".codeium", "windsurf", "mcp_config.json"),
1861
+ path6.join(getHomeDir3(), ".codeium", "windsurf", "mcp_config.json"),
1623
1862
  options
1624
1863
  );
1625
1864
  if (res.success && !options.dryRun) {
@@ -1631,7 +1870,7 @@ var IdeConfigInjector = class {
1631
1870
  static injectCline(options) {
1632
1871
  const res = this.injectJsonMcpConfig(
1633
1872
  "Cline",
1634
- path5.join(os3.homedir(), ".cline", "data", "settings", "cline_mcp_settings.json"),
1873
+ path6.join(getHomeDir3(), ".cline", "data", "settings", "cline_mcp_settings.json"),
1635
1874
  options
1636
1875
  );
1637
1876
  if (res.success && !options.dryRun) {
@@ -1641,17 +1880,17 @@ var IdeConfigInjector = class {
1641
1880
  }
1642
1881
  /** Generic JSON client using the common { mcpServers: {} } format. */
1643
1882
  static injectOther(configPath, options) {
1644
- return this.injectJsonMcpConfig("Other MCP client", path5.resolve(configPath), options);
1883
+ return this.injectJsonMcpConfig("Other MCP client", path6.resolve(configPath), options);
1645
1884
  }
1646
1885
  /**
1647
1886
  * Injects config and memory rules for Codex CLI (`config.toml` and `AGENTS.md`)
1648
1887
  */
1649
1888
  static injectCodex(options) {
1650
- const codexDir = path5.join(os3.homedir(), ".codex");
1651
- const configPath = path5.join(codexDir, "config.toml");
1889
+ const codexDir = path6.join(getHomeDir3(), ".codex");
1890
+ const configPath = path6.join(codexDir, "config.toml");
1652
1891
  try {
1653
- if (!fs5.existsSync(codexDir) && !options.dryRun) {
1654
- fs5.mkdirSync(codexDir, { recursive: true });
1892
+ if (!fs6.existsSync(codexDir) && !options.dryRun) {
1893
+ fs6.mkdirSync(codexDir, { recursive: true });
1655
1894
  }
1656
1895
  const entry = `
1657
1896
  # MemHub MCP Connector
@@ -1660,17 +1899,18 @@ command = "memhub"
1660
1899
  args = ["serve"]
1661
1900
  `;
1662
1901
  let content = "";
1663
- if (fs5.existsSync(configPath)) {
1664
- content = fs5.readFileSync(configPath, "utf8");
1902
+ if (fs6.existsSync(configPath)) {
1903
+ content = fs6.readFileSync(configPath, "utf8");
1665
1904
  }
1666
1905
  if (!content.includes("[mcp.servers.memhub]")) {
1667
1906
  content += entry;
1668
1907
  if (!options.dryRun) {
1669
- fs5.writeFileSync(configPath, content, "utf8");
1908
+ fs6.writeFileSync(configPath, content, "utf8");
1670
1909
  }
1671
1910
  }
1672
1911
  if (!options.dryRun) {
1673
1912
  RulesInjector.injectCodex(options.cwd || process.cwd());
1913
+ SkillsInjector.injectCodexSkill();
1674
1914
  }
1675
1915
  return {
1676
1916
  target: "Codex CLI",
@@ -1688,6 +1928,42 @@ args = ["serve"]
1688
1928
  };
1689
1929
  }
1690
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
+ }
1691
1967
  /**
1692
1968
  * Injects for all supported IDEs and tools
1693
1969
  */
@@ -1698,7 +1974,10 @@ args = ["serve"]
1698
1974
  this.injectCodex(options),
1699
1975
  this.injectAntigravity(options),
1700
1976
  this.injectWindsurf(options),
1701
- this.injectCline(options)
1977
+ this.injectCline(options),
1978
+ this.injectOpenCode(options),
1979
+ this.injectQwen(options),
1980
+ this.injectDeepSeek(options)
1702
1981
  ];
1703
1982
  }
1704
1983
  };
@@ -1708,13 +1987,13 @@ import { createInterface } from "node:readline/promises";
1708
1987
  import { stdin as input, stdout as output } from "node:process";
1709
1988
  import { hostname } from "node:os";
1710
1989
  import { execSync as execSync2 } from "node:child_process";
1711
- import path7 from "node:path";
1990
+ import path8 from "node:path";
1712
1991
 
1713
1992
  // src/update-notifier.ts
1714
- import fs6 from "fs";
1715
- import path6 from "path";
1993
+ import fs7 from "fs";
1994
+ import path7 from "path";
1716
1995
  import https from "https";
1717
- var CHECK_INTERVAL_MS = 6 * 60 * 60 * 1e3;
1996
+ var CHECK_INTERVAL_MS = 2 * 60 * 60 * 1e3;
1718
1997
  var PACKAGE_NAME = "@simplexlat/memhub";
1719
1998
  function compareVersions(v1, v2) {
1720
1999
  const parts1 = v1.split(".").map((p) => parseInt(p, 10) || 0);
@@ -1733,7 +2012,7 @@ async function fetchLatestFromNpm() {
1733
2012
  `https://registry.npmjs.org/${PACKAGE_NAME}/latest`,
1734
2013
  {
1735
2014
  headers: { "User-Agent": "memhub-cli" },
1736
- timeout: 1500
2015
+ timeout: 2e3
1737
2016
  },
1738
2017
  (res) => {
1739
2018
  if (res.statusCode !== 200) {
@@ -1763,7 +2042,7 @@ async function fetchLatestFromNpm() {
1763
2042
  }
1764
2043
  var UpdateNotifier = class {
1765
2044
  static cacheFile() {
1766
- return path6.join(resolveStorageDir(), "update-cache.json");
2045
+ return path7.join(resolveStorageDir(), "update-cache.json");
1767
2046
  }
1768
2047
  static async checkForUpdates(currentVersion) {
1769
2048
  if (process.argv.includes("serve") || process.argv.includes("update")) {
@@ -1774,32 +2053,31 @@ var UpdateNotifier = class {
1774
2053
  ensureDirectory(storageDir);
1775
2054
  const cachePath = this.cacheFile();
1776
2055
  let cache = { lastChecked: 0, latestVersion: currentVersion };
1777
- if (fs6.existsSync(cachePath)) {
2056
+ if (fs7.existsSync(cachePath)) {
1778
2057
  try {
1779
- cache = JSON.parse(fs6.readFileSync(cachePath, "utf8"));
2058
+ cache = JSON.parse(fs7.readFileSync(cachePath, "utf8"));
1780
2059
  } catch {
1781
2060
  }
1782
2061
  }
1783
2062
  const now = Date.now();
1784
2063
  let latestVersion = cache.latestVersion;
1785
2064
  if (now - cache.lastChecked > CHECK_INTERVAL_MS) {
1786
- const fetched = await fetchLatestFromNpm();
1787
- if (fetched) {
1788
- latestVersion = fetched;
1789
- cache = { lastChecked: now, latestVersion: fetched };
1790
- try {
1791
- fs6.writeFileSync(cachePath, JSON.stringify(cache), "utf8");
1792
- } catch {
2065
+ fetchLatestFromNpm().then((fetched) => {
2066
+ if (fetched) {
2067
+ cache = { lastChecked: Date.now(), latestVersion: fetched };
2068
+ try {
2069
+ fs7.writeFileSync(cachePath, JSON.stringify(cache), "utf8");
2070
+ } catch {
2071
+ }
1793
2072
  }
1794
- }
2073
+ }).catch(() => {
2074
+ });
1795
2075
  }
1796
2076
  if (compareVersions(latestVersion, currentVersion) > 0) {
1797
- process.on("exit", () => {
1798
- console.error("\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
1799
- console.error(`\u2502 \u{1F680} Actualizaci\xF3n disponible para MemHub: ${currentVersion} \u2192 \x1B[32m${latestVersion}\x1B[0m \u2502`);
1800
- console.error("\u2502 Ejecuta \x1B[1m\x1B[36mmh update\x1B[0m para instalar la \xFAltima versi\xF3n. \u2502");
1801
- console.error("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n");
1802
- });
2077
+ console.error("\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
2078
+ console.error(`\u2502 \u{1F680} Actualizaci\xF3n disponible para MemHub: ${currentVersion} \u2192 \x1B[32m${latestVersion}\x1B[0m \u2502`);
2079
+ console.error("\u2502 Ejecuta \x1B[1m\x1B[36mmh update\x1B[0m para instalar la \xFAltima versi\xF3n. \u2502");
2080
+ console.error("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n");
1803
2081
  }
1804
2082
  } catch {
1805
2083
  }
@@ -1907,7 +2185,7 @@ function openInBrowser(url) {
1907
2185
  }
1908
2186
 
1909
2187
  // src/cli.ts
1910
- var CLI_VERSION = "0.1.2";
2188
+ var CLI_VERSION = "0.1.4";
1911
2189
  void UpdateNotifier.checkForUpdates(CLI_VERSION);
1912
2190
  var program = new Command();
1913
2191
  var supportedTargets = ["claude", "cursor", "windsurf", "cline", "codex", "antigravity"];
@@ -1967,7 +2245,7 @@ async function installToSelectedClients(options) {
1967
2245
  }
1968
2246
  }
1969
2247
  }
1970
- program.name("memhub").description("Local-first MCP proxy for MemHub & agentmemory").version("0.1.2");
2248
+ program.name("memhub").description("Local-first MCP proxy for MemHub & agentmemory").version("0.1.4");
1971
2249
  program.command("serve").description("Start the MemHub MCP stdio proxy server").action(async () => {
1972
2250
  const config = getConfig();
1973
2251
  const server = new MemHubMcpServer(config);
@@ -2138,6 +2416,17 @@ program.command("doctor").description("Run system health checks and diagnostics
2138
2416
  console.log(` \u2717 Cloud API unreachable at ${config.apiUrl} (${health.message})`);
2139
2417
  }
2140
2418
  }
2419
+ console.log("4. Checking for CLI updates:");
2420
+ try {
2421
+ const latest = await fetchLatestFromNpm();
2422
+ if (latest && compareVersions(latest, CLI_VERSION) > 0) {
2423
+ console.log(` \u26A0\uFE0F Update available: ${CLI_VERSION} \u2192 ${latest}. Run \`mh update\` to upgrade.`);
2424
+ } else {
2425
+ console.log(` \u2713 MemHub CLI is up to date (v${CLI_VERSION}).`);
2426
+ }
2427
+ } catch {
2428
+ console.log(` \u2713 Running MemHub CLI v${CLI_VERSION}.`);
2429
+ }
2141
2430
  console.log("\nDoctor inspection completed.");
2142
2431
  });
2143
2432
  program.command("flush").description("Force an immediate push of all pending outbox events to the cloud").action(async () => {
@@ -2179,7 +2468,7 @@ program.command("flush").description("Force an immediate push of all pending out
2179
2468
  });
2180
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) => {
2181
2470
  console.log("\u{1F4DD} Injecting MemHub memory protocol rules into AI client configuration files...");
2182
- const results = RulesInjector.injectAll(path7.resolve(options.cwd));
2471
+ const results = RulesInjector.injectAll(path8.resolve(options.cwd));
2183
2472
  for (const res of results) {
2184
2473
  if (res.success) {
2185
2474
  console.log(` \u2713 ${res.target}: ${res.action} at ${res.filePath}`);
@@ -2187,6 +2476,9 @@ program.command("rules").description("Inject or update MemHub persistent memory
2187
2476
  console.log(` \u2717 ${res.target}: ${res.error}`);
2188
2477
  }
2189
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");
2190
2482
  console.log("\n\u2728 AI agents in this workspace and globally will now proactively save and recall team memories.");
2191
2483
  });
2192
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) => {