memorix 0.3.8 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -21
- package/dist/cli/index.js +193 -28
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +172 -23
- package/dist/index.js.map +1 -1
- package/package.json +8 -2
package/dist/index.js
CHANGED
|
@@ -1876,6 +1876,86 @@ var WindsurfAdapter = class {
|
|
|
1876
1876
|
}
|
|
1877
1877
|
};
|
|
1878
1878
|
|
|
1879
|
+
// src/rules/adapters/antigravity.ts
|
|
1880
|
+
init_esm_shims();
|
|
1881
|
+
import matter5 from "gray-matter";
|
|
1882
|
+
var AntigravityAdapter = class {
|
|
1883
|
+
source = "antigravity";
|
|
1884
|
+
filePatterns = [
|
|
1885
|
+
"GEMINI.md",
|
|
1886
|
+
".agent/rules/*.md",
|
|
1887
|
+
".agent/skills/*/SKILL.md"
|
|
1888
|
+
];
|
|
1889
|
+
parse(filePath, content) {
|
|
1890
|
+
if (filePath.includes("SKILL.md")) {
|
|
1891
|
+
return this.parseSkillMd(filePath, content);
|
|
1892
|
+
}
|
|
1893
|
+
if (filePath.includes(".agent/rules/")) {
|
|
1894
|
+
return this.parseAgentRule(filePath, content);
|
|
1895
|
+
}
|
|
1896
|
+
if (filePath === "GEMINI.md" || filePath.endsWith("/GEMINI.md")) {
|
|
1897
|
+
return this.parseGeminiMd(filePath, content);
|
|
1898
|
+
}
|
|
1899
|
+
return [];
|
|
1900
|
+
}
|
|
1901
|
+
generate(rules) {
|
|
1902
|
+
const projectRules = rules.filter((r) => r.scope !== "path-specific");
|
|
1903
|
+
const pathRules = rules.filter((r) => r.scope === "path-specific");
|
|
1904
|
+
const files = [];
|
|
1905
|
+
for (const rule of [...projectRules, ...pathRules]) {
|
|
1906
|
+
const fm = {};
|
|
1907
|
+
if (rule.description) fm.description = rule.description;
|
|
1908
|
+
const fileName = rule.id.replace(/^antigravity:/, "").replace(/[^a-zA-Z0-9-_]/g, "-") || "rule";
|
|
1909
|
+
const body = Object.keys(fm).length > 0 ? matter5.stringify(rule.content, fm) : rule.content;
|
|
1910
|
+
files.push({
|
|
1911
|
+
filePath: `.agent/rules/${fileName}.md`,
|
|
1912
|
+
content: body
|
|
1913
|
+
});
|
|
1914
|
+
}
|
|
1915
|
+
return files;
|
|
1916
|
+
}
|
|
1917
|
+
parseGeminiMd(filePath, content) {
|
|
1918
|
+
const trimmed = content.trim();
|
|
1919
|
+
if (!trimmed) return [];
|
|
1920
|
+
return [{
|
|
1921
|
+
id: generateRuleId("antigravity", filePath),
|
|
1922
|
+
content: trimmed,
|
|
1923
|
+
source: "antigravity",
|
|
1924
|
+
scope: "global",
|
|
1925
|
+
priority: 10,
|
|
1926
|
+
hash: hashContent(trimmed)
|
|
1927
|
+
}];
|
|
1928
|
+
}
|
|
1929
|
+
parseAgentRule(filePath, content) {
|
|
1930
|
+
const { data, content: body } = matter5(content);
|
|
1931
|
+
const trimmed = body.trim();
|
|
1932
|
+
if (!trimmed) return [];
|
|
1933
|
+
return [{
|
|
1934
|
+
id: generateRuleId("antigravity", filePath),
|
|
1935
|
+
content: trimmed,
|
|
1936
|
+
description: data.description,
|
|
1937
|
+
source: "antigravity",
|
|
1938
|
+
scope: "project",
|
|
1939
|
+
priority: 5,
|
|
1940
|
+
hash: hashContent(trimmed)
|
|
1941
|
+
}];
|
|
1942
|
+
}
|
|
1943
|
+
parseSkillMd(filePath, content) {
|
|
1944
|
+
const { data, content: body } = matter5(content);
|
|
1945
|
+
const trimmed = body.trim();
|
|
1946
|
+
if (!trimmed) return [];
|
|
1947
|
+
return [{
|
|
1948
|
+
id: generateRuleId("antigravity", filePath),
|
|
1949
|
+
content: trimmed,
|
|
1950
|
+
description: data.description || void 0,
|
|
1951
|
+
source: "antigravity",
|
|
1952
|
+
scope: "project",
|
|
1953
|
+
priority: 5,
|
|
1954
|
+
hash: hashContent(trimmed)
|
|
1955
|
+
}];
|
|
1956
|
+
}
|
|
1957
|
+
};
|
|
1958
|
+
|
|
1879
1959
|
// src/rules/syncer.ts
|
|
1880
1960
|
var RulesSyncer = class {
|
|
1881
1961
|
projectRoot;
|
|
@@ -1887,7 +1967,8 @@ var RulesSyncer = class {
|
|
|
1887
1967
|
new CursorAdapter(),
|
|
1888
1968
|
new ClaudeCodeAdapter(),
|
|
1889
1969
|
new CodexAdapter(),
|
|
1890
|
-
new WindsurfAdapter()
|
|
1970
|
+
new WindsurfAdapter(),
|
|
1971
|
+
new AntigravityAdapter()
|
|
1891
1972
|
];
|
|
1892
1973
|
for (const a of all) {
|
|
1893
1974
|
this.adapters.set(a.source, a);
|
|
@@ -2029,8 +2110,8 @@ var RulesSyncer = class {
|
|
|
2029
2110
|
// src/workspace/engine.ts
|
|
2030
2111
|
init_esm_shims();
|
|
2031
2112
|
import { readFileSync as readFileSync2, readdirSync, existsSync as existsSync4, cpSync, mkdirSync as mkdirSync2 } from "fs";
|
|
2032
|
-
import { join as
|
|
2033
|
-
import { homedir as
|
|
2113
|
+
import { join as join8 } from "path";
|
|
2114
|
+
import { homedir as homedir7 } from "os";
|
|
2034
2115
|
|
|
2035
2116
|
// src/workspace/mcp-adapters/windsurf.ts
|
|
2036
2117
|
init_esm_shims();
|
|
@@ -2400,9 +2481,73 @@ var CopilotMCPAdapter = class {
|
|
|
2400
2481
|
}
|
|
2401
2482
|
};
|
|
2402
2483
|
|
|
2484
|
+
// src/workspace/mcp-adapters/antigravity.ts
|
|
2485
|
+
init_esm_shims();
|
|
2486
|
+
import { homedir as homedir6 } from "os";
|
|
2487
|
+
import { join as join6 } from "path";
|
|
2488
|
+
var AntigravityMCPAdapter = class {
|
|
2489
|
+
source = "antigravity";
|
|
2490
|
+
parse(content) {
|
|
2491
|
+
try {
|
|
2492
|
+
const config = JSON.parse(content);
|
|
2493
|
+
const servers = config.mcpServers ?? config.mcp_servers ?? {};
|
|
2494
|
+
return Object.entries(servers).map(([name, entry]) => {
|
|
2495
|
+
const result = {
|
|
2496
|
+
name,
|
|
2497
|
+
command: entry.command ?? "",
|
|
2498
|
+
args: entry.args ?? []
|
|
2499
|
+
};
|
|
2500
|
+
if (entry.serverUrl) {
|
|
2501
|
+
result.url = entry.serverUrl;
|
|
2502
|
+
} else if (entry.url) {
|
|
2503
|
+
result.url = entry.url;
|
|
2504
|
+
}
|
|
2505
|
+
if (entry.headers && typeof entry.headers === "object" && Object.keys(entry.headers).length > 0) {
|
|
2506
|
+
result.headers = entry.headers;
|
|
2507
|
+
}
|
|
2508
|
+
if (entry.env && typeof entry.env === "object" && Object.keys(entry.env).length > 0) {
|
|
2509
|
+
result.env = entry.env;
|
|
2510
|
+
}
|
|
2511
|
+
if (entry.disabled === true) {
|
|
2512
|
+
result.disabled = true;
|
|
2513
|
+
}
|
|
2514
|
+
return result;
|
|
2515
|
+
});
|
|
2516
|
+
} catch {
|
|
2517
|
+
return [];
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
generate(servers) {
|
|
2521
|
+
const mcpServers = {};
|
|
2522
|
+
for (const s of servers) {
|
|
2523
|
+
const entry = {};
|
|
2524
|
+
if (s.url) {
|
|
2525
|
+
entry.url = s.url;
|
|
2526
|
+
if (s.headers && Object.keys(s.headers).length > 0) {
|
|
2527
|
+
entry.headers = s.headers;
|
|
2528
|
+
}
|
|
2529
|
+
} else {
|
|
2530
|
+
entry.command = s.command;
|
|
2531
|
+
entry.args = s.args;
|
|
2532
|
+
}
|
|
2533
|
+
if (s.env && Object.keys(s.env).length > 0) {
|
|
2534
|
+
entry.env = s.env;
|
|
2535
|
+
}
|
|
2536
|
+
if (s.disabled === true) {
|
|
2537
|
+
entry.disabled = true;
|
|
2538
|
+
}
|
|
2539
|
+
mcpServers[s.name] = entry;
|
|
2540
|
+
}
|
|
2541
|
+
return JSON.stringify({ mcpServers }, null, 2);
|
|
2542
|
+
}
|
|
2543
|
+
getConfigPath(_projectRoot) {
|
|
2544
|
+
return join6(homedir6(), ".gemini", "antigravity", "mcp_config.json");
|
|
2545
|
+
}
|
|
2546
|
+
};
|
|
2547
|
+
|
|
2403
2548
|
// src/workspace/workflow-sync.ts
|
|
2404
2549
|
init_esm_shims();
|
|
2405
|
-
import
|
|
2550
|
+
import matter6 from "gray-matter";
|
|
2406
2551
|
var WorkflowSyncer = class {
|
|
2407
2552
|
/**
|
|
2408
2553
|
* Parse a Windsurf workflow markdown file into a WorkflowEntry.
|
|
@@ -2412,7 +2557,7 @@ var WorkflowSyncer = class {
|
|
|
2412
2557
|
let description = "";
|
|
2413
2558
|
let content = raw;
|
|
2414
2559
|
try {
|
|
2415
|
-
const parsed =
|
|
2560
|
+
const parsed = matter6(raw);
|
|
2416
2561
|
description = parsed.data?.description ?? "";
|
|
2417
2562
|
content = parsed.content.trim();
|
|
2418
2563
|
} catch {
|
|
@@ -2434,7 +2579,7 @@ var WorkflowSyncer = class {
|
|
|
2434
2579
|
if (wf.description) {
|
|
2435
2580
|
fm.description = wf.description;
|
|
2436
2581
|
}
|
|
2437
|
-
const content =
|
|
2582
|
+
const content = matter6.stringify(wf.content, fm);
|
|
2438
2583
|
return {
|
|
2439
2584
|
filePath: `.agents/skills/${safeName}/SKILL.md`,
|
|
2440
2585
|
content
|
|
@@ -2451,7 +2596,7 @@ var WorkflowSyncer = class {
|
|
|
2451
2596
|
}
|
|
2452
2597
|
fm.globs = "";
|
|
2453
2598
|
fm.alwaysApply = "false";
|
|
2454
|
-
const content =
|
|
2599
|
+
const content = matter6.stringify(wf.content, fm);
|
|
2455
2600
|
return {
|
|
2456
2601
|
filePath: `.cursor/rules/${safeName}.mdc`,
|
|
2457
2602
|
content
|
|
@@ -2632,7 +2777,8 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
|
|
|
2632
2777
|
["cursor", new CursorMCPAdapter()],
|
|
2633
2778
|
["codex", new CodexMCPAdapter()],
|
|
2634
2779
|
["claude-code", new ClaudeCodeMCPAdapter()],
|
|
2635
|
-
["copilot", new CopilotMCPAdapter()]
|
|
2780
|
+
["copilot", new CopilotMCPAdapter()],
|
|
2781
|
+
["antigravity", new AntigravityMCPAdapter()]
|
|
2636
2782
|
]);
|
|
2637
2783
|
this.workflowSyncer = new WorkflowSyncer();
|
|
2638
2784
|
this.rulesSyncer = new RulesSyncer(projectRoot);
|
|
@@ -2649,7 +2795,8 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
|
|
|
2649
2795
|
cursor: [],
|
|
2650
2796
|
codex: [],
|
|
2651
2797
|
"claude-code": [],
|
|
2652
|
-
copilot: []
|
|
2798
|
+
copilot: [],
|
|
2799
|
+
antigravity: []
|
|
2653
2800
|
};
|
|
2654
2801
|
for (const [target, adapter] of this.adapters) {
|
|
2655
2802
|
const configPath = adapter.getConfigPath(this.projectRoot);
|
|
@@ -2740,13 +2887,14 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
|
|
|
2740
2887
|
cursor: [".cursor/skills", ".cursor/skills-cursor"],
|
|
2741
2888
|
windsurf: [".windsurf/skills"],
|
|
2742
2889
|
"claude-code": [".claude/skills"],
|
|
2743
|
-
copilot: []
|
|
2890
|
+
copilot: [],
|
|
2891
|
+
antigravity: [".agent/skills", ".gemini/skills", ".gemini/antigravity/skills"]
|
|
2744
2892
|
};
|
|
2745
2893
|
/** Get the target skills directory for an agent (null if agent has no skills support) */
|
|
2746
2894
|
getTargetSkillsDir(target) {
|
|
2747
2895
|
const dirs = _WorkspaceSyncEngine.SKILLS_DIRS[target];
|
|
2748
2896
|
if (!dirs || dirs.length === 0) return null;
|
|
2749
|
-
return
|
|
2897
|
+
return join8(this.projectRoot, dirs[0]);
|
|
2750
2898
|
}
|
|
2751
2899
|
/**
|
|
2752
2900
|
* Scan all agent skills directories and collect unique skills.
|
|
@@ -2755,12 +2903,12 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
|
|
|
2755
2903
|
const skills = [];
|
|
2756
2904
|
const conflicts = [];
|
|
2757
2905
|
const seen = /* @__PURE__ */ new Map();
|
|
2758
|
-
const home =
|
|
2906
|
+
const home = homedir7();
|
|
2759
2907
|
for (const [agent, dirs] of Object.entries(_WorkspaceSyncEngine.SKILLS_DIRS)) {
|
|
2760
2908
|
for (const dir of dirs) {
|
|
2761
2909
|
const paths = [
|
|
2762
|
-
|
|
2763
|
-
|
|
2910
|
+
join8(this.projectRoot, dir),
|
|
2911
|
+
join8(home, dir)
|
|
2764
2912
|
];
|
|
2765
2913
|
for (const skillsRoot of paths) {
|
|
2766
2914
|
if (!existsSync4(skillsRoot)) continue;
|
|
@@ -2768,7 +2916,7 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
|
|
|
2768
2916
|
const entries = readdirSync(skillsRoot, { withFileTypes: true });
|
|
2769
2917
|
for (const entry of entries) {
|
|
2770
2918
|
if (!entry.isDirectory()) continue;
|
|
2771
|
-
const skillMd =
|
|
2919
|
+
const skillMd = join8(skillsRoot, entry.name, "SKILL.md");
|
|
2772
2920
|
if (!existsSync4(skillMd)) continue;
|
|
2773
2921
|
let description = "";
|
|
2774
2922
|
try {
|
|
@@ -2780,7 +2928,7 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
|
|
|
2780
2928
|
const newEntry = {
|
|
2781
2929
|
name: entry.name,
|
|
2782
2930
|
description,
|
|
2783
|
-
sourcePath:
|
|
2931
|
+
sourcePath: join8(skillsRoot, entry.name),
|
|
2784
2932
|
sourceAgent: agent
|
|
2785
2933
|
};
|
|
2786
2934
|
const existing = seen.get(entry.name);
|
|
@@ -2817,7 +2965,7 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
|
|
|
2817
2965
|
}
|
|
2818
2966
|
for (const skill of skills) {
|
|
2819
2967
|
if (skill.sourceAgent === target) continue;
|
|
2820
|
-
const dest =
|
|
2968
|
+
const dest = join8(targetDir, skill.name);
|
|
2821
2969
|
if (existsSync4(dest)) {
|
|
2822
2970
|
skipped.push(`${skill.name} (already exists in ${target})`);
|
|
2823
2971
|
continue;
|
|
@@ -2833,13 +2981,13 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
|
|
|
2833
2981
|
}
|
|
2834
2982
|
scanWorkflows() {
|
|
2835
2983
|
const workflows = [];
|
|
2836
|
-
const wfDir =
|
|
2984
|
+
const wfDir = join8(this.projectRoot, ".windsurf", "workflows");
|
|
2837
2985
|
if (!existsSync4(wfDir)) return workflows;
|
|
2838
2986
|
try {
|
|
2839
2987
|
const files = readdirSync(wfDir).filter((f) => f.endsWith(".md"));
|
|
2840
2988
|
for (const file of files) {
|
|
2841
2989
|
try {
|
|
2842
|
-
const content = readFileSync2(
|
|
2990
|
+
const content = readFileSync2(join8(wfDir, file), "utf-8");
|
|
2843
2991
|
workflows.push(this.workflowSyncer.parseWindsurfWorkflow(file, content));
|
|
2844
2992
|
} catch {
|
|
2845
2993
|
}
|
|
@@ -2926,7 +3074,8 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
|
|
|
2926
3074
|
"claude-code": "claude-code",
|
|
2927
3075
|
codex: "codex",
|
|
2928
3076
|
windsurf: "windsurf",
|
|
2929
|
-
copilot: "windsurf"
|
|
3077
|
+
copilot: "windsurf",
|
|
3078
|
+
antigravity: "antigravity"
|
|
2930
3079
|
};
|
|
2931
3080
|
return map[target] ?? null;
|
|
2932
3081
|
}
|
|
@@ -3402,12 +3551,12 @@ Entity: ${entityName} | Type: ${type} | Project: ${project.id}${enrichment}`
|
|
|
3402
3551
|
};
|
|
3403
3552
|
}
|
|
3404
3553
|
);
|
|
3405
|
-
const RULE_SOURCES = ["cursor", "claude-code", "codex", "windsurf"];
|
|
3554
|
+
const RULE_SOURCES = ["cursor", "claude-code", "codex", "windsurf", "antigravity"];
|
|
3406
3555
|
server.registerTool(
|
|
3407
3556
|
"memorix_rules_sync",
|
|
3408
3557
|
{
|
|
3409
3558
|
title: "Rules Sync",
|
|
3410
|
-
description: "Scan project for agent rule files (Cursor, Claude Code, Codex, Windsurf), deduplicate, detect conflicts, and optionally generate rules for a target agent format. Without target: returns sync status report. With target: generates converted rule files.",
|
|
3559
|
+
description: "Scan project for agent rule files (Cursor, Claude Code, Codex, Windsurf, Antigravity), deduplicate, detect conflicts, and optionally generate rules for a target agent format. Without target: returns sync status report. With target: generates converted rule files.",
|
|
3411
3560
|
inputSchema: {
|
|
3412
3561
|
action: z.enum(["status", "generate"]).describe('Action: "status" for report, "generate" to produce target files'),
|
|
3413
3562
|
target: z.enum(RULE_SOURCES).optional().describe("Target agent format for generation (required when action=generate)")
|
|
@@ -3457,7 +3606,7 @@ Entity: ${entityName} | Type: ${type} | Project: ${project.id}${enrichment}`
|
|
|
3457
3606
|
};
|
|
3458
3607
|
}
|
|
3459
3608
|
);
|
|
3460
|
-
const AGENT_TARGETS = ["windsurf", "cursor", "claude-code", "codex", "copilot"];
|
|
3609
|
+
const AGENT_TARGETS = ["windsurf", "cursor", "claude-code", "codex", "copilot", "antigravity"];
|
|
3461
3610
|
server.registerTool(
|
|
3462
3611
|
"memorix_workspace_sync",
|
|
3463
3612
|
{
|