@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 +374 -82
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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
|
|
1351
|
-
import
|
|
1352
|
-
import
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
1474
|
-
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");
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
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 =
|
|
1524
|
-
if (!
|
|
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 (
|
|
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 =
|
|
1530
|
-
if (!options.dryRun)
|
|
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 =
|
|
1778
|
+
const configPath = path6.join(cwd, "mcp.json");
|
|
1542
1779
|
try {
|
|
1543
1780
|
let config = { mcpServers: {} };
|
|
1544
|
-
if (
|
|
1545
|
-
config = JSON.parse(
|
|
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
|
-
|
|
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:
|
|
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 =
|
|
1575
|
-
const configPath =
|
|
1812
|
+
const cursorDir = path6.join(cwd, ".cursor");
|
|
1813
|
+
const configPath = path6.join(cursorDir, "mcp.json");
|
|
1576
1814
|
try {
|
|
1577
|
-
if (!
|
|
1578
|
-
|
|
1815
|
+
if (!fs6.existsSync(cursorDir) && !options.dryRun) {
|
|
1816
|
+
fs6.mkdirSync(cursorDir, { recursive: true });
|
|
1579
1817
|
}
|
|
1580
1818
|
let config = { mcpServers: {} };
|
|
1581
|
-
if (
|
|
1582
|
-
config = JSON.parse(
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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",
|
|
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 =
|
|
1651
|
-
const configPath =
|
|
1889
|
+
const codexDir = path6.join(getHomeDir3(), ".codex");
|
|
1890
|
+
const configPath = path6.join(codexDir, "config.toml");
|
|
1652
1891
|
try {
|
|
1653
|
-
if (!
|
|
1654
|
-
|
|
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 (
|
|
1664
|
-
content =
|
|
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
|
-
|
|
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
|
|
1990
|
+
import path8 from "node:path";
|
|
1712
1991
|
|
|
1713
1992
|
// src/update-notifier.ts
|
|
1714
|
-
import
|
|
1715
|
-
import
|
|
1993
|
+
import fs7 from "fs";
|
|
1994
|
+
import path7 from "path";
|
|
1716
1995
|
import https from "https";
|
|
1717
|
-
var CHECK_INTERVAL_MS =
|
|
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:
|
|
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
|
|
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 (
|
|
2056
|
+
if (fs7.existsSync(cachePath)) {
|
|
1778
2057
|
try {
|
|
1779
|
-
cache = JSON.parse(
|
|
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
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
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
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
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.
|
|
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.
|
|
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(
|
|
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) => {
|