memorix 0.3.9 → 0.4.1

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/index.js CHANGED
@@ -1876,6 +1876,172 @@ 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
+
1959
+ // src/rules/adapters/copilot.ts
1960
+ init_esm_shims();
1961
+ import matter6 from "gray-matter";
1962
+ var CopilotAdapter = class {
1963
+ source = "copilot";
1964
+ filePatterns = [
1965
+ ".github/copilot-instructions.md",
1966
+ ".github/instructions/*.instructions.md"
1967
+ ];
1968
+ parse(filePath, content) {
1969
+ if (filePath.includes(".instructions.md") && filePath.includes(".github/instructions")) {
1970
+ return this.parsePathSpecific(filePath, content);
1971
+ }
1972
+ if (filePath.includes("copilot-instructions.md")) {
1973
+ return this.parseRepoWide(filePath, content);
1974
+ }
1975
+ return [];
1976
+ }
1977
+ generate(rules) {
1978
+ if (rules.length === 1 && (!rules[0].paths || rules[0].paths.length === 0)) {
1979
+ return [{
1980
+ filePath: ".github/copilot-instructions.md",
1981
+ content: rules[0].content
1982
+ }];
1983
+ }
1984
+ return rules.map((rule, i) => {
1985
+ const fm = {};
1986
+ if (rule.paths && rule.paths.length > 0) {
1987
+ fm.applyTo = rule.paths.join(",");
1988
+ }
1989
+ if (rule.description) {
1990
+ fm.description = rule.description;
1991
+ }
1992
+ const fileName = rule.id.replace(/^copilot:/, "").replace(/[^a-zA-Z0-9-_]/g, "-") || `instruction-${i}`;
1993
+ const body = Object.keys(fm).length > 0 ? matter6.stringify(rule.content, fm) : rule.content;
1994
+ return {
1995
+ filePath: `.github/instructions/${fileName}.instructions.md`,
1996
+ content: body
1997
+ };
1998
+ });
1999
+ }
2000
+ /**
2001
+ * Parse repository-wide .github/copilot-instructions.md
2002
+ * This is plain Markdown with no frontmatter.
2003
+ */
2004
+ parseRepoWide(filePath, content) {
2005
+ const trimmed = content.trim();
2006
+ if (!trimmed) return [];
2007
+ return [{
2008
+ id: generateRuleId("copilot", filePath),
2009
+ content: trimmed,
2010
+ description: "Repository-wide Copilot instructions",
2011
+ source: "copilot",
2012
+ scope: "project",
2013
+ priority: 3,
2014
+ hash: hashContent(trimmed)
2015
+ }];
2016
+ }
2017
+ /**
2018
+ * Parse path-specific .github/instructions/*.instructions.md
2019
+ * These have YAML frontmatter with `applyTo` glob pattern(s).
2020
+ */
2021
+ parsePathSpecific(filePath, content) {
2022
+ const { data, content: body } = matter6(content);
2023
+ const trimmed = body.trim();
2024
+ if (!trimmed) return [];
2025
+ const applyTo = data.applyTo;
2026
+ const hasApplyTo = !!applyTo;
2027
+ const rule = {
2028
+ id: generateRuleId("copilot", filePath),
2029
+ content: trimmed,
2030
+ source: "copilot",
2031
+ scope: hasApplyTo ? "path-specific" : "project",
2032
+ priority: 5,
2033
+ hash: hashContent(trimmed)
2034
+ };
2035
+ if (hasApplyTo) {
2036
+ rule.paths = applyTo.split(",").map((p) => p.trim());
2037
+ }
2038
+ if (data.description) {
2039
+ rule.description = data.description;
2040
+ }
2041
+ return [rule];
2042
+ }
2043
+ };
2044
+
1879
2045
  // src/rules/syncer.ts
1880
2046
  var RulesSyncer = class {
1881
2047
  projectRoot;
@@ -1887,7 +2053,9 @@ var RulesSyncer = class {
1887
2053
  new CursorAdapter(),
1888
2054
  new ClaudeCodeAdapter(),
1889
2055
  new CodexAdapter(),
1890
- new WindsurfAdapter()
2056
+ new WindsurfAdapter(),
2057
+ new AntigravityAdapter(),
2058
+ new CopilotAdapter()
1891
2059
  ];
1892
2060
  for (const a of all) {
1893
2061
  this.adapters.set(a.source, a);
@@ -2029,8 +2197,8 @@ var RulesSyncer = class {
2029
2197
  // src/workspace/engine.ts
2030
2198
  init_esm_shims();
2031
2199
  import { readFileSync as readFileSync2, readdirSync, existsSync as existsSync4, cpSync, mkdirSync as mkdirSync2 } from "fs";
2032
- import { join as join7 } from "path";
2033
- import { homedir as homedir6 } from "os";
2200
+ import { join as join8 } from "path";
2201
+ import { homedir as homedir7 } from "os";
2034
2202
 
2035
2203
  // src/workspace/mcp-adapters/windsurf.ts
2036
2204
  init_esm_shims();
@@ -2400,9 +2568,73 @@ var CopilotMCPAdapter = class {
2400
2568
  }
2401
2569
  };
2402
2570
 
2571
+ // src/workspace/mcp-adapters/antigravity.ts
2572
+ init_esm_shims();
2573
+ import { homedir as homedir6 } from "os";
2574
+ import { join as join6 } from "path";
2575
+ var AntigravityMCPAdapter = class {
2576
+ source = "antigravity";
2577
+ parse(content) {
2578
+ try {
2579
+ const config = JSON.parse(content);
2580
+ const servers = config.mcpServers ?? config.mcp_servers ?? {};
2581
+ return Object.entries(servers).map(([name, entry]) => {
2582
+ const result = {
2583
+ name,
2584
+ command: entry.command ?? "",
2585
+ args: entry.args ?? []
2586
+ };
2587
+ if (entry.serverUrl) {
2588
+ result.url = entry.serverUrl;
2589
+ } else if (entry.url) {
2590
+ result.url = entry.url;
2591
+ }
2592
+ if (entry.headers && typeof entry.headers === "object" && Object.keys(entry.headers).length > 0) {
2593
+ result.headers = entry.headers;
2594
+ }
2595
+ if (entry.env && typeof entry.env === "object" && Object.keys(entry.env).length > 0) {
2596
+ result.env = entry.env;
2597
+ }
2598
+ if (entry.disabled === true) {
2599
+ result.disabled = true;
2600
+ }
2601
+ return result;
2602
+ });
2603
+ } catch {
2604
+ return [];
2605
+ }
2606
+ }
2607
+ generate(servers) {
2608
+ const mcpServers = {};
2609
+ for (const s of servers) {
2610
+ const entry = {};
2611
+ if (s.url) {
2612
+ entry.url = s.url;
2613
+ if (s.headers && Object.keys(s.headers).length > 0) {
2614
+ entry.headers = s.headers;
2615
+ }
2616
+ } else {
2617
+ entry.command = s.command;
2618
+ entry.args = s.args;
2619
+ }
2620
+ if (s.env && Object.keys(s.env).length > 0) {
2621
+ entry.env = s.env;
2622
+ }
2623
+ if (s.disabled === true) {
2624
+ entry.disabled = true;
2625
+ }
2626
+ mcpServers[s.name] = entry;
2627
+ }
2628
+ return JSON.stringify({ mcpServers }, null, 2);
2629
+ }
2630
+ getConfigPath(_projectRoot) {
2631
+ return join6(homedir6(), ".gemini", "antigravity", "mcp_config.json");
2632
+ }
2633
+ };
2634
+
2403
2635
  // src/workspace/workflow-sync.ts
2404
2636
  init_esm_shims();
2405
- import matter5 from "gray-matter";
2637
+ import matter7 from "gray-matter";
2406
2638
  var WorkflowSyncer = class {
2407
2639
  /**
2408
2640
  * Parse a Windsurf workflow markdown file into a WorkflowEntry.
@@ -2412,7 +2644,7 @@ var WorkflowSyncer = class {
2412
2644
  let description = "";
2413
2645
  let content = raw;
2414
2646
  try {
2415
- const parsed = matter5(raw);
2647
+ const parsed = matter7(raw);
2416
2648
  description = parsed.data?.description ?? "";
2417
2649
  content = parsed.content.trim();
2418
2650
  } catch {
@@ -2434,7 +2666,7 @@ var WorkflowSyncer = class {
2434
2666
  if (wf.description) {
2435
2667
  fm.description = wf.description;
2436
2668
  }
2437
- const content = matter5.stringify(wf.content, fm);
2669
+ const content = matter7.stringify(wf.content, fm);
2438
2670
  return {
2439
2671
  filePath: `.agents/skills/${safeName}/SKILL.md`,
2440
2672
  content
@@ -2451,7 +2683,7 @@ var WorkflowSyncer = class {
2451
2683
  }
2452
2684
  fm.globs = "";
2453
2685
  fm.alwaysApply = "false";
2454
- const content = matter5.stringify(wf.content, fm);
2686
+ const content = matter7.stringify(wf.content, fm);
2455
2687
  return {
2456
2688
  filePath: `.cursor/rules/${safeName}.mdc`,
2457
2689
  content
@@ -2632,7 +2864,8 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
2632
2864
  ["cursor", new CursorMCPAdapter()],
2633
2865
  ["codex", new CodexMCPAdapter()],
2634
2866
  ["claude-code", new ClaudeCodeMCPAdapter()],
2635
- ["copilot", new CopilotMCPAdapter()]
2867
+ ["copilot", new CopilotMCPAdapter()],
2868
+ ["antigravity", new AntigravityMCPAdapter()]
2636
2869
  ]);
2637
2870
  this.workflowSyncer = new WorkflowSyncer();
2638
2871
  this.rulesSyncer = new RulesSyncer(projectRoot);
@@ -2649,7 +2882,8 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
2649
2882
  cursor: [],
2650
2883
  codex: [],
2651
2884
  "claude-code": [],
2652
- copilot: []
2885
+ copilot: [],
2886
+ antigravity: []
2653
2887
  };
2654
2888
  for (const [target, adapter] of this.adapters) {
2655
2889
  const configPath = adapter.getConfigPath(this.projectRoot);
@@ -2740,13 +2974,14 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
2740
2974
  cursor: [".cursor/skills", ".cursor/skills-cursor"],
2741
2975
  windsurf: [".windsurf/skills"],
2742
2976
  "claude-code": [".claude/skills"],
2743
- copilot: []
2977
+ copilot: [".github/skills", ".copilot/skills"],
2978
+ antigravity: [".agent/skills", ".gemini/skills", ".gemini/antigravity/skills"]
2744
2979
  };
2745
2980
  /** Get the target skills directory for an agent (null if agent has no skills support) */
2746
2981
  getTargetSkillsDir(target) {
2747
2982
  const dirs = _WorkspaceSyncEngine.SKILLS_DIRS[target];
2748
2983
  if (!dirs || dirs.length === 0) return null;
2749
- return join7(this.projectRoot, dirs[0]);
2984
+ return join8(this.projectRoot, dirs[0]);
2750
2985
  }
2751
2986
  /**
2752
2987
  * Scan all agent skills directories and collect unique skills.
@@ -2755,12 +2990,12 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
2755
2990
  const skills = [];
2756
2991
  const conflicts = [];
2757
2992
  const seen = /* @__PURE__ */ new Map();
2758
- const home = homedir6();
2993
+ const home = homedir7();
2759
2994
  for (const [agent, dirs] of Object.entries(_WorkspaceSyncEngine.SKILLS_DIRS)) {
2760
2995
  for (const dir of dirs) {
2761
2996
  const paths = [
2762
- join7(this.projectRoot, dir),
2763
- join7(home, dir)
2997
+ join8(this.projectRoot, dir),
2998
+ join8(home, dir)
2764
2999
  ];
2765
3000
  for (const skillsRoot of paths) {
2766
3001
  if (!existsSync4(skillsRoot)) continue;
@@ -2768,7 +3003,7 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
2768
3003
  const entries = readdirSync(skillsRoot, { withFileTypes: true });
2769
3004
  for (const entry of entries) {
2770
3005
  if (!entry.isDirectory()) continue;
2771
- const skillMd = join7(skillsRoot, entry.name, "SKILL.md");
3006
+ const skillMd = join8(skillsRoot, entry.name, "SKILL.md");
2772
3007
  if (!existsSync4(skillMd)) continue;
2773
3008
  let description = "";
2774
3009
  try {
@@ -2780,7 +3015,7 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
2780
3015
  const newEntry = {
2781
3016
  name: entry.name,
2782
3017
  description,
2783
- sourcePath: join7(skillsRoot, entry.name),
3018
+ sourcePath: join8(skillsRoot, entry.name),
2784
3019
  sourceAgent: agent
2785
3020
  };
2786
3021
  const existing = seen.get(entry.name);
@@ -2817,7 +3052,7 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
2817
3052
  }
2818
3053
  for (const skill of skills) {
2819
3054
  if (skill.sourceAgent === target) continue;
2820
- const dest = join7(targetDir, skill.name);
3055
+ const dest = join8(targetDir, skill.name);
2821
3056
  if (existsSync4(dest)) {
2822
3057
  skipped.push(`${skill.name} (already exists in ${target})`);
2823
3058
  continue;
@@ -2833,13 +3068,13 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
2833
3068
  }
2834
3069
  scanWorkflows() {
2835
3070
  const workflows = [];
2836
- const wfDir = join7(this.projectRoot, ".windsurf", "workflows");
3071
+ const wfDir = join8(this.projectRoot, ".windsurf", "workflows");
2837
3072
  if (!existsSync4(wfDir)) return workflows;
2838
3073
  try {
2839
3074
  const files = readdirSync(wfDir).filter((f) => f.endsWith(".md"));
2840
3075
  for (const file of files) {
2841
3076
  try {
2842
- const content = readFileSync2(join7(wfDir, file), "utf-8");
3077
+ const content = readFileSync2(join8(wfDir, file), "utf-8");
2843
3078
  workflows.push(this.workflowSyncer.parseWindsurfWorkflow(file, content));
2844
3079
  } catch {
2845
3080
  }
@@ -2926,7 +3161,8 @@ var WorkspaceSyncEngine = class _WorkspaceSyncEngine {
2926
3161
  "claude-code": "claude-code",
2927
3162
  codex: "codex",
2928
3163
  windsurf: "windsurf",
2929
- copilot: "windsurf"
3164
+ copilot: "copilot",
3165
+ antigravity: "antigravity"
2930
3166
  };
2931
3167
  return map[target] ?? null;
2932
3168
  }
@@ -3402,12 +3638,12 @@ Entity: ${entityName} | Type: ${type} | Project: ${project.id}${enrichment}`
3402
3638
  };
3403
3639
  }
3404
3640
  );
3405
- const RULE_SOURCES = ["cursor", "claude-code", "codex", "windsurf"];
3641
+ const RULE_SOURCES = ["cursor", "claude-code", "codex", "windsurf", "antigravity", "copilot"];
3406
3642
  server.registerTool(
3407
3643
  "memorix_rules_sync",
3408
3644
  {
3409
3645
  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.",
3646
+ description: "Scan project for agent rule files (Cursor, Claude Code, Codex, Windsurf, Antigravity, Copilot), 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
3647
  inputSchema: {
3412
3648
  action: z.enum(["status", "generate"]).describe('Action: "status" for report, "generate" to produce target files'),
3413
3649
  target: z.enum(RULE_SOURCES).optional().describe("Target agent format for generation (required when action=generate)")
@@ -3457,7 +3693,7 @@ Entity: ${entityName} | Type: ${type} | Project: ${project.id}${enrichment}`
3457
3693
  };
3458
3694
  }
3459
3695
  );
3460
- const AGENT_TARGETS = ["windsurf", "cursor", "claude-code", "codex", "copilot"];
3696
+ const AGENT_TARGETS = ["windsurf", "cursor", "claude-code", "codex", "copilot", "antigravity"];
3461
3697
  server.registerTool(
3462
3698
  "memorix_workspace_sync",
3463
3699
  {