gnosys 5.11.3 → 5.11.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 +8 -1
- package/dist/lib/ideMcpInstall.d.ts +30 -0
- package/dist/lib/ideMcpInstall.js +102 -0
- package/dist/lib/setup/sections/ides.d.ts +7 -0
- package/dist/lib/setup/sections/ides.js +24 -2
- package/dist/lib/setup.js +51 -146
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -974,7 +974,14 @@ setupCmd
|
|
|
974
974
|
setupCmd
|
|
975
975
|
.command("ides")
|
|
976
976
|
.description("Configure IDE MCP integrations (Claude Code/Desktop, Cursor, Codex, Grok Build, Gemini CLI, Antigravity)")
|
|
977
|
-
.
|
|
977
|
+
.option("--all", "Configure MCP for all supported IDEs (non-interactive)")
|
|
978
|
+
.action(async (opts) => {
|
|
979
|
+
if (opts.all) {
|
|
980
|
+
const { runIdesSetupAll } = await import("./lib/setup/sections/ides.js");
|
|
981
|
+
const { configured, errors } = await runIdesSetupAll(process.cwd());
|
|
982
|
+
console.log(`\n${configured} ides configured · ${errors} errors`);
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
978
985
|
const readline = await import("readline/promises");
|
|
979
986
|
const { runIdesSetup } = await import("./lib/setup/sections/ides.js");
|
|
980
987
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared stdio MCP install helpers for IDE setup (`gnosys setup ides`).
|
|
3
|
+
*/
|
|
4
|
+
/** IDE keys handled by `setupIDE()`. */
|
|
5
|
+
export declare const SUPPORTED_IDE_KEYS: readonly ["claude", "claude-desktop", "cursor", "codex", "gemini-cli", "antigravity", "grok-build"];
|
|
6
|
+
export type SupportedIde = (typeof SUPPORTED_IDE_KEYS)[number];
|
|
7
|
+
/** User-facing aliases → canonical IDE key. */
|
|
8
|
+
export declare const IDE_ALIASES: Record<string, SupportedIde>;
|
|
9
|
+
export declare function normalizeIdeKey(ide: string): SupportedIde | null;
|
|
10
|
+
/** Absolute path to `gnosys-mcp` when on PATH, else bare name. */
|
|
11
|
+
export declare function resolveGnosysMcpCommand(): string;
|
|
12
|
+
export declare function gnosysStdioMcpEntry(): {
|
|
13
|
+
command: string;
|
|
14
|
+
args: string[];
|
|
15
|
+
};
|
|
16
|
+
/** True when an existing JSON MCP entry still points at broken `gnosys serve`. */
|
|
17
|
+
export declare function isStaleGnosysMcpEntry(entry: unknown): boolean;
|
|
18
|
+
/** Merge (or replace) the gnosys stdio entry in a JSON MCP config file. */
|
|
19
|
+
export declare function installStdioMcpJson(file: string): Promise<void>;
|
|
20
|
+
/** Project + user-global Cursor MCP paths. */
|
|
21
|
+
export declare function cursorMcpPaths(projectDir: string): {
|
|
22
|
+
project: string;
|
|
23
|
+
user: string;
|
|
24
|
+
};
|
|
25
|
+
/** Run a CLI with argv (safe for paths containing spaces). */
|
|
26
|
+
export declare function runCli(command: string, args: string[], opts?: {
|
|
27
|
+
allowFailure?: boolean;
|
|
28
|
+
}): string;
|
|
29
|
+
/** Remove a `[section]` block from hand-rolled TOML text. */
|
|
30
|
+
export declare function removeTomlSection(existing: string, sectionHeader: string): string;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared stdio MCP install helpers for IDE setup (`gnosys setup ides`).
|
|
3
|
+
*/
|
|
4
|
+
import { execFileSync, execSync } from "child_process";
|
|
5
|
+
import path from "path";
|
|
6
|
+
import os from "os";
|
|
7
|
+
import { mergeJsonMcpServer } from "./mcpClientConfig.js";
|
|
8
|
+
/** IDE keys handled by `setupIDE()`. */
|
|
9
|
+
export const SUPPORTED_IDE_KEYS = [
|
|
10
|
+
"claude",
|
|
11
|
+
"claude-desktop",
|
|
12
|
+
"cursor",
|
|
13
|
+
"codex",
|
|
14
|
+
"gemini-cli",
|
|
15
|
+
"antigravity",
|
|
16
|
+
"grok-build",
|
|
17
|
+
];
|
|
18
|
+
/** User-facing aliases → canonical IDE key. */
|
|
19
|
+
export const IDE_ALIASES = {
|
|
20
|
+
grok: "grok-build",
|
|
21
|
+
"grok-build": "grok-build",
|
|
22
|
+
};
|
|
23
|
+
export function normalizeIdeKey(ide) {
|
|
24
|
+
const key = ide.toLowerCase();
|
|
25
|
+
if (SUPPORTED_IDE_KEYS.includes(key)) {
|
|
26
|
+
return key;
|
|
27
|
+
}
|
|
28
|
+
return IDE_ALIASES[key] ?? null;
|
|
29
|
+
}
|
|
30
|
+
/** Absolute path to `gnosys-mcp` when on PATH, else bare name. */
|
|
31
|
+
export function resolveGnosysMcpCommand() {
|
|
32
|
+
try {
|
|
33
|
+
const p = execSync("command -v gnosys-mcp", { encoding: "utf-8" }).trim();
|
|
34
|
+
if (p)
|
|
35
|
+
return p;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Fall back to bare name on PATH.
|
|
39
|
+
}
|
|
40
|
+
return "gnosys-mcp";
|
|
41
|
+
}
|
|
42
|
+
export function gnosysStdioMcpEntry() {
|
|
43
|
+
return { command: resolveGnosysMcpCommand(), args: [] };
|
|
44
|
+
}
|
|
45
|
+
/** True when an existing JSON MCP entry still points at broken `gnosys serve`. */
|
|
46
|
+
export function isStaleGnosysMcpEntry(entry) {
|
|
47
|
+
if (!entry || typeof entry !== "object")
|
|
48
|
+
return false;
|
|
49
|
+
const e = entry;
|
|
50
|
+
const cmd = String(e.command ?? "");
|
|
51
|
+
const args = Array.isArray(e.args) ? e.args.map(String) : [];
|
|
52
|
+
if (cmd.includes("gnosys-mcp"))
|
|
53
|
+
return false;
|
|
54
|
+
if (cmd.endsWith("/gnosys") || cmd === "gnosys") {
|
|
55
|
+
return args.includes("serve") || args.length === 0;
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
/** Merge (or replace) the gnosys stdio entry in a JSON MCP config file. */
|
|
60
|
+
export async function installStdioMcpJson(file) {
|
|
61
|
+
await mergeJsonMcpServer(file, gnosysStdioMcpEntry());
|
|
62
|
+
}
|
|
63
|
+
/** Project + user-global Cursor MCP paths. */
|
|
64
|
+
export function cursorMcpPaths(projectDir) {
|
|
65
|
+
return {
|
|
66
|
+
project: path.join(projectDir, ".cursor", "mcp.json"),
|
|
67
|
+
user: path.join(os.homedir(), ".cursor", "mcp.json"),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** Run a CLI with argv (safe for paths containing spaces). */
|
|
71
|
+
export function runCli(command, args, opts) {
|
|
72
|
+
try {
|
|
73
|
+
return execFileSync(command, args, {
|
|
74
|
+
encoding: "utf-8",
|
|
75
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
if (opts?.allowFailure) {
|
|
80
|
+
return err instanceof Error && "stdout" in err ? String(err.stdout ?? "") : "";
|
|
81
|
+
}
|
|
82
|
+
throw err;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** Remove a `[section]` block from hand-rolled TOML text. */
|
|
86
|
+
export function removeTomlSection(existing, sectionHeader) {
|
|
87
|
+
const lines = existing.split("\n");
|
|
88
|
+
const headerIdx = lines.findIndex((line) => line.trim() === sectionHeader);
|
|
89
|
+
if (headerIdx === -1)
|
|
90
|
+
return existing;
|
|
91
|
+
let endIdx = lines.length;
|
|
92
|
+
for (let i = headerIdx + 1; i < lines.length; i++) {
|
|
93
|
+
if (/^\s*\[/.test(lines[i])) {
|
|
94
|
+
endIdx = i;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const before = lines.slice(0, headerIdx).join("\n");
|
|
99
|
+
const after = lines.slice(endIdx).join("\n");
|
|
100
|
+
const merged = [before, after].filter((s) => s.length > 0).join("\n");
|
|
101
|
+
return merged.length > 0 ? `${merged.replace(/\n{3,}/g, "\n\n")}\n` : "";
|
|
102
|
+
}
|
|
@@ -25,3 +25,10 @@ export interface IdesSetupOptions {
|
|
|
25
25
|
* Returns true if at least one IDE config was written.
|
|
26
26
|
*/
|
|
27
27
|
export declare function runIdesSetup(opts: IdesSetupOptions): Promise<boolean>;
|
|
28
|
+
/**
|
|
29
|
+
* Non-interactive: wire MCP for every supported IDE (user-level + project cursor).
|
|
30
|
+
*/
|
|
31
|
+
export declare function runIdesSetupAll(directory: string): Promise<{
|
|
32
|
+
configured: number;
|
|
33
|
+
errors: number;
|
|
34
|
+
}>;
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import fs from "fs/promises";
|
|
10
10
|
import path from "path";
|
|
11
11
|
import { detectIDEs, setupIDE } from "../../setup.js";
|
|
12
|
+
import { SUPPORTED_IDE_KEYS } from "../../ideMcpInstall.js";
|
|
12
13
|
import { safeQuestion } from "../ui/safePrompt.js";
|
|
13
14
|
import { renderTable } from "../ui/table.js";
|
|
14
15
|
const DIM = "\x1b[2m";
|
|
@@ -18,7 +19,7 @@ const RESET = "\x1b[0m";
|
|
|
18
19
|
const CHECK = `${GREEN}✓${RESET}`;
|
|
19
20
|
const CROSS = `${RED}✗${RESET}`;
|
|
20
21
|
const IDE_LABELS = {
|
|
21
|
-
claude: "Claude Code",
|
|
22
|
+
claude: "Claude Code + Desktop",
|
|
22
23
|
"claude-desktop": "Claude Desktop",
|
|
23
24
|
cursor: "Cursor",
|
|
24
25
|
codex: "Codex",
|
|
@@ -35,7 +36,7 @@ const IDE_TARGET_DISPLAY = {
|
|
|
35
36
|
claude: "claude mcp add (CLI)",
|
|
36
37
|
"claude-desktop": "~/Library/.../claude_desktop_config.json",
|
|
37
38
|
cursor: ".cursor/mcp.json",
|
|
38
|
-
codex: "
|
|
39
|
+
codex: "codex mcp add (CLI registry)",
|
|
39
40
|
"gemini-cli": "~/.gemini/settings.json",
|
|
40
41
|
antigravity: "~/.gemini/antigravity/mcp_config.json",
|
|
41
42
|
"grok-build": "~/.grok/config.toml ([mcp_servers.gnosys])",
|
|
@@ -178,3 +179,24 @@ export async function runIdesSetup(opts) {
|
|
|
178
179
|
console.log(` ${color(c.textDim, `${configured} ides configured · ${errors} errors`)}`);
|
|
179
180
|
return configured > 0;
|
|
180
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Non-interactive: wire MCP for every supported IDE (user-level + project cursor).
|
|
184
|
+
*/
|
|
185
|
+
export async function runIdesSetupAll(directory) {
|
|
186
|
+
let configured = 0;
|
|
187
|
+
let errors = 0;
|
|
188
|
+
// Claude setup also wires Claude Desktop — skip duplicate pass.
|
|
189
|
+
const idesToRun = SUPPORTED_IDE_KEYS.filter((k) => k !== "claude-desktop");
|
|
190
|
+
for (const ide of idesToRun) {
|
|
191
|
+
const result = await setupIDE(ide, directory);
|
|
192
|
+
if (result.success) {
|
|
193
|
+
console.log(` ${CHECK} ${IDE_LABELS[ide] ?? ide}: ${result.message}`);
|
|
194
|
+
configured++;
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
console.log(` ${CROSS} ${IDE_LABELS[ide] ?? ide}: ${result.message}`);
|
|
198
|
+
errors++;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return { configured, errors };
|
|
202
|
+
}
|
package/dist/lib/setup.js
CHANGED
|
@@ -19,6 +19,7 @@ import { validateModel } from "./modelValidation.js";
|
|
|
19
19
|
import { resolveActiveStorePath, ensureActiveStorePath } from "./setup/storePath.js";
|
|
20
20
|
import { safeQuestion } from "./setup/ui/safePrompt.js";
|
|
21
21
|
import { getClaudeDesktopConfigPath, getApiKeySkipHints } from "./platform.js";
|
|
22
|
+
import { gnosysStdioMcpEntry, installStdioMcpJson, normalizeIdeKey, resolveGnosysMcpCommand, cursorMcpPaths, runCli, removeTomlSection, } from "./ideMcpInstall.js";
|
|
22
23
|
// ─── ANSI Colors ────────────────────────────────────────────────────────────
|
|
23
24
|
const BOLD = "\x1b[1m";
|
|
24
25
|
const DIM = "\x1b[2m";
|
|
@@ -567,24 +568,6 @@ export async function detectIDEs(projectDir) {
|
|
|
567
568
|
}
|
|
568
569
|
return detected;
|
|
569
570
|
}
|
|
570
|
-
/** Remove a single `[section]` block from Grok TOML (hand-rolled; see upsertGrokMcpBlock). */
|
|
571
|
-
function removeGrokTomlSection(existing, sectionHeader) {
|
|
572
|
-
const lines = existing.split("\n");
|
|
573
|
-
const headerIdx = lines.findIndex((line) => line.trim() === sectionHeader);
|
|
574
|
-
if (headerIdx === -1)
|
|
575
|
-
return existing;
|
|
576
|
-
let endIdx = lines.length;
|
|
577
|
-
for (let i = headerIdx + 1; i < lines.length; i++) {
|
|
578
|
-
if (/^\s*\[/.test(lines[i])) {
|
|
579
|
-
endIdx = i;
|
|
580
|
-
break;
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
const before = lines.slice(0, headerIdx).join("\n");
|
|
584
|
-
const after = lines.slice(endIdx).join("\n");
|
|
585
|
-
const merged = [before, after].filter((s) => s.length > 0).join("\n");
|
|
586
|
-
return merged.length > 0 ? `${merged}\n` : "";
|
|
587
|
-
}
|
|
588
571
|
/**
|
|
589
572
|
* Replace (or append) a `[mcp_servers.<name>]` block inside Grok Build's
|
|
590
573
|
* `~/.grok/config.toml`. Preserves every line outside that block (deci-046).
|
|
@@ -596,7 +579,7 @@ function removeGrokTomlSection(existing, sectionHeader) {
|
|
|
596
579
|
*/
|
|
597
580
|
export function upsertGrokMcpBlock(existing, name, entry) {
|
|
598
581
|
// Drop mistaken v5.9.4 `[mcp.<name>]` sections so we don't leave dead config.
|
|
599
|
-
let content =
|
|
582
|
+
let content = removeTomlSection(existing, `[mcp.${name}]`);
|
|
600
583
|
const sectionHeader = `[mcp_servers.${name}]`;
|
|
601
584
|
const lines = content.split("\n");
|
|
602
585
|
const headerIdx = lines.findIndex((line) => line.trim() === sectionHeader);
|
|
@@ -632,25 +615,6 @@ export function upsertGrokMcpBlock(existing, name, entry) {
|
|
|
632
615
|
const afterBlock = afterLines.join("\n");
|
|
633
616
|
return `${head}${sectionHeader}\n${blockBody}${gap}${afterBlock}`;
|
|
634
617
|
}
|
|
635
|
-
/**
|
|
636
|
-
* Absolute path to the `gnosys-mcp` stdio entry (dist/index.js).
|
|
637
|
-
* Prefer this over `gnosys serve` — v5.11.0 `gnosys serve` imported index.js but
|
|
638
|
-
* did not call startMcpServer(), so MCP hosts saw "connection closed" on init.
|
|
639
|
-
*/
|
|
640
|
-
function resolveGnosysMcpCommand() {
|
|
641
|
-
try {
|
|
642
|
-
const p = execSync("command -v gnosys-mcp", { encoding: "utf-8" }).trim();
|
|
643
|
-
if (p)
|
|
644
|
-
return p;
|
|
645
|
-
}
|
|
646
|
-
catch {
|
|
647
|
-
// Fall back to bare name on PATH.
|
|
648
|
-
}
|
|
649
|
-
return "gnosys-mcp";
|
|
650
|
-
}
|
|
651
|
-
function gnosysMcpServerEntry() {
|
|
652
|
-
return { command: resolveGnosysMcpCommand(), args: [] };
|
|
653
|
-
}
|
|
654
618
|
function renderGrokMcpBlock(entry) {
|
|
655
619
|
const argsStr = `[${entry.args.map((a) => JSON.stringify(a)).join(", ")}]`;
|
|
656
620
|
const lines = [
|
|
@@ -666,48 +630,45 @@ function renderGrokMcpBlock(entry) {
|
|
|
666
630
|
* Set up Gnosys MCP integration for a specific IDE.
|
|
667
631
|
*/
|
|
668
632
|
export async function setupIDE(ide, projectDir) {
|
|
633
|
+
const canonical = normalizeIdeKey(ide);
|
|
634
|
+
if (!canonical) {
|
|
635
|
+
return { success: false, message: `Unknown IDE: ${ide}` };
|
|
636
|
+
}
|
|
669
637
|
try {
|
|
670
|
-
switch (
|
|
638
|
+
switch (canonical) {
|
|
671
639
|
case "claude": {
|
|
672
640
|
const mcpCmd = resolveGnosysMcpCommand();
|
|
641
|
+
let codeMsg = `Claude Code MCP registered (${mcpCmd})`;
|
|
673
642
|
try {
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
}
|
|
677
|
-
catch {
|
|
678
|
-
// Not registered yet — fine.
|
|
679
|
-
}
|
|
680
|
-
execSync(`claude mcp add -s user gnosys -- ${mcpCmd}`, {
|
|
681
|
-
stdio: "pipe",
|
|
682
|
-
});
|
|
643
|
+
runCli("claude", ["mcp", "remove", "gnosys"], { allowFailure: true });
|
|
644
|
+
runCli("claude", ["mcp", "add", "-s", "user", "gnosys", "--", mcpCmd]);
|
|
683
645
|
}
|
|
684
646
|
catch (e) {
|
|
685
647
|
const msg = e instanceof Error ? e.message : String(e);
|
|
686
648
|
if (msg.includes("already exists")) {
|
|
687
|
-
|
|
649
|
+
codeMsg = "Claude Code MCP server already configured";
|
|
650
|
+
}
|
|
651
|
+
else {
|
|
652
|
+
codeMsg = `Claude Code MCP skipped (is \`claude\` on PATH?): ${msg}`;
|
|
688
653
|
}
|
|
689
|
-
throw e;
|
|
690
654
|
}
|
|
691
|
-
|
|
655
|
+
const desktop = await setupIDE("claude-desktop", projectDir);
|
|
656
|
+
return {
|
|
657
|
+
success: desktop.success,
|
|
658
|
+
message: desktop.success
|
|
659
|
+
? `${codeMsg}; ${desktop.message}`
|
|
660
|
+
: `${codeMsg}; Claude Desktop: ${desktop.message}`,
|
|
661
|
+
};
|
|
692
662
|
}
|
|
693
663
|
case "cursor": {
|
|
694
|
-
const
|
|
695
|
-
|
|
696
|
-
await
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
}
|
|
702
|
-
catch {
|
|
703
|
-
// File doesn't exist or is invalid — start fresh
|
|
704
|
-
}
|
|
705
|
-
// Merge gnosys entry
|
|
706
|
-
const servers = (config.mcpServers ?? {});
|
|
707
|
-
servers.gnosys = gnosysMcpServerEntry();
|
|
708
|
-
config.mcpServers = servers;
|
|
709
|
-
await fs.writeFile(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
710
|
-
return { success: true, message: "Cursor MCP config updated (.cursor/mcp.json)" };
|
|
664
|
+
const paths = cursorMcpPaths(projectDir);
|
|
665
|
+
await fs.mkdir(path.dirname(paths.project), { recursive: true });
|
|
666
|
+
await installStdioMcpJson(paths.project);
|
|
667
|
+
await installStdioMcpJson(paths.user);
|
|
668
|
+
return {
|
|
669
|
+
success: true,
|
|
670
|
+
message: "Cursor MCP updated (project .cursor/mcp.json and ~/.cursor/mcp.json)",
|
|
671
|
+
};
|
|
711
672
|
}
|
|
712
673
|
case "codex": {
|
|
713
674
|
// v5.8.5: register via `codex mcp add` (the real Codex CLI registration
|
|
@@ -719,19 +680,13 @@ export async function setupIDE(ide, projectDir) {
|
|
|
719
680
|
//
|
|
720
681
|
// We also migrate away from those legacy blocks in
|
|
721
682
|
// `~/.codex/config.toml` so users on stale configs get cleaned up.
|
|
722
|
-
|
|
723
|
-
// 1. Migrate (strip) legacy hand-written blocks in ~/.codex/config.toml.
|
|
683
|
+
// 1. Strip legacy hand-written sections in ~/.codex/config.toml.
|
|
724
684
|
const userCodexConfig = path.join(os.homedir(), ".codex", "config.toml");
|
|
725
685
|
try {
|
|
726
686
|
let existing = await fs.readFile(userCodexConfig, "utf-8");
|
|
727
|
-
const
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
// v5.8.4 shape: [mcp.gnosys] type/command
|
|
731
|
-
existing = existing.replace(/\n?\[mcp\.gnosys\][^[]*?type\s*=\s*"local"[^[]*?command\s*=\s*\[[^\]]*\]\s*\n?/, "\n");
|
|
732
|
-
if (existing !== before) {
|
|
733
|
-
existing = existing.replace(/\n{3,}/g, "\n\n");
|
|
734
|
-
await fs.writeFile(userCodexConfig, existing, "utf-8");
|
|
687
|
+
const cleaned = removeTomlSection(removeTomlSection(existing, "[mcp.gnosys]"), "[gnosys]");
|
|
688
|
+
if (cleaned !== existing) {
|
|
689
|
+
await fs.writeFile(userCodexConfig, cleaned, "utf-8");
|
|
735
690
|
}
|
|
736
691
|
}
|
|
737
692
|
catch {
|
|
@@ -744,25 +699,16 @@ export async function setupIDE(ide, projectDir) {
|
|
|
744
699
|
// remove and re-add.
|
|
745
700
|
let alreadyCorrect = false;
|
|
746
701
|
try {
|
|
747
|
-
const existing =
|
|
748
|
-
encoding: "utf-8",
|
|
749
|
-
});
|
|
702
|
+
const existing = runCli("codex", ["mcp", "get", "gnosys"], { allowFailure: true });
|
|
750
703
|
if (existing && existing.includes(gnosysCmd) && !existing.includes(" serve")) {
|
|
751
704
|
alreadyCorrect = true;
|
|
752
705
|
}
|
|
753
706
|
else if (existing) {
|
|
754
|
-
|
|
755
|
-
try {
|
|
756
|
-
execSync("codex mcp remove gnosys", { stdio: "pipe" });
|
|
757
|
-
}
|
|
758
|
-
catch {
|
|
759
|
-
// Non-fatal — `mcp add` below will overwrite or fail loudly.
|
|
760
|
-
}
|
|
707
|
+
runCli("codex", ["mcp", "remove", "gnosys"], { allowFailure: true });
|
|
761
708
|
}
|
|
762
709
|
}
|
|
763
710
|
catch {
|
|
764
|
-
// `codex mcp get`
|
|
765
|
-
// that's the common case on first install; proceed to add.
|
|
711
|
+
// `codex mcp get` failed — proceed to add.
|
|
766
712
|
}
|
|
767
713
|
if (alreadyCorrect) {
|
|
768
714
|
return {
|
|
@@ -772,7 +718,7 @@ export async function setupIDE(ide, projectDir) {
|
|
|
772
718
|
}
|
|
773
719
|
// 4. Register via the canonical Codex CLI command.
|
|
774
720
|
try {
|
|
775
|
-
|
|
721
|
+
runCli("codex", ["mcp", "add", "gnosys", "--", gnosysCmd]);
|
|
776
722
|
}
|
|
777
723
|
catch (err) {
|
|
778
724
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -789,43 +735,19 @@ export async function setupIDE(ide, projectDir) {
|
|
|
789
735
|
};
|
|
790
736
|
}
|
|
791
737
|
case "gemini-cli": {
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
await fs.mkdir(geminiDir, { recursive: true });
|
|
796
|
-
let config = {};
|
|
797
|
-
try {
|
|
798
|
-
const existing = await fs.readFile(settingsPath, "utf-8");
|
|
799
|
-
config = JSON.parse(existing);
|
|
800
|
-
}
|
|
801
|
-
catch {
|
|
802
|
-
// File doesn't exist or is invalid — start fresh
|
|
803
|
-
}
|
|
804
|
-
const servers = (config.mcpServers ?? {});
|
|
805
|
-
servers.gnosys = gnosysMcpServerEntry();
|
|
806
|
-
config.mcpServers = servers;
|
|
807
|
-
await fs.writeFile(settingsPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
738
|
+
const settingsPath = path.join(os.homedir(), ".gemini", "settings.json");
|
|
739
|
+
await fs.mkdir(path.dirname(settingsPath), { recursive: true });
|
|
740
|
+
await installStdioMcpJson(settingsPath);
|
|
808
741
|
return { success: true, message: "Gemini CLI MCP config updated (~/.gemini/settings.json)" };
|
|
809
742
|
}
|
|
810
743
|
case "antigravity": {
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
const existing = await fs.readFile(configPath, "utf-8");
|
|
819
|
-
config = JSON.parse(existing);
|
|
820
|
-
}
|
|
821
|
-
catch {
|
|
822
|
-
// File doesn't exist or is invalid — start fresh
|
|
823
|
-
}
|
|
824
|
-
const servers = (config.mcpServers ?? {});
|
|
825
|
-
servers.gnosys = gnosysMcpServerEntry();
|
|
826
|
-
config.mcpServers = servers;
|
|
827
|
-
await fs.writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
828
|
-
return { success: true, message: "Antigravity MCP config updated (~/.gemini/antigravity/mcp_config.json)" };
|
|
744
|
+
const configPath = path.join(os.homedir(), ".gemini", "antigravity", "mcp_config.json");
|
|
745
|
+
await fs.mkdir(path.dirname(configPath), { recursive: true });
|
|
746
|
+
await installStdioMcpJson(configPath);
|
|
747
|
+
return {
|
|
748
|
+
success: true,
|
|
749
|
+
message: "Antigravity MCP config updated (~/.gemini/antigravity/mcp_config.json)",
|
|
750
|
+
};
|
|
829
751
|
}
|
|
830
752
|
case "grok-build": {
|
|
831
753
|
// v5.9.4 Bug 12 — Grok Build reads MCP from `[mcp_servers.<name>]`
|
|
@@ -842,32 +764,16 @@ export async function setupIDE(ide, projectDir) {
|
|
|
842
764
|
// File doesn't exist yet — start fresh
|
|
843
765
|
}
|
|
844
766
|
const updated = upsertGrokMcpBlock(existing, "gnosys", {
|
|
845
|
-
...
|
|
767
|
+
...gnosysStdioMcpEntry(),
|
|
846
768
|
startup_timeout_sec: 90,
|
|
847
769
|
});
|
|
848
770
|
await fs.writeFile(configPath, updated, "utf-8");
|
|
849
771
|
return { success: true, message: "Grok Build MCP config updated (~/.grok/config.toml)" };
|
|
850
772
|
}
|
|
851
773
|
case "claude-desktop": {
|
|
852
|
-
// Claude Desktop reads MCP servers from claude_desktop_config.json
|
|
853
|
-
// in a platform-specific app data directory. Distinct from Claude
|
|
854
|
-
// Code CLI which uses `claude mcp add`.
|
|
855
774
|
const configPath = getClaudeDesktopConfigPath();
|
|
856
|
-
|
|
857
|
-
await
|
|
858
|
-
let config = {};
|
|
859
|
-
try {
|
|
860
|
-
const existing = await fs.readFile(configPath, "utf-8");
|
|
861
|
-
config = JSON.parse(existing);
|
|
862
|
-
}
|
|
863
|
-
catch {
|
|
864
|
-
// File doesn't exist or is invalid — start fresh
|
|
865
|
-
}
|
|
866
|
-
const servers = (config.mcpServers ?? {});
|
|
867
|
-
servers.gnosys = gnosysMcpServerEntry();
|
|
868
|
-
config.mcpServers = servers;
|
|
869
|
-
await fs.writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
870
|
-
// Display path with ~ prefix when inside HOME for clarity
|
|
775
|
+
await fs.mkdir(path.dirname(configPath), { recursive: true });
|
|
776
|
+
await installStdioMcpJson(configPath);
|
|
871
777
|
const home = os.homedir();
|
|
872
778
|
const displayPath = configPath.startsWith(home)
|
|
873
779
|
? configPath.replace(home, "~")
|
|
@@ -877,9 +783,8 @@ export async function setupIDE(ide, projectDir) {
|
|
|
877
783
|
message: `Claude Desktop MCP config updated (${displayPath}). Restart Claude Desktop for the change to take effect.`,
|
|
878
784
|
};
|
|
879
785
|
}
|
|
880
|
-
default:
|
|
881
|
-
return { success: false, message: `Unknown IDE: ${ide}` };
|
|
882
786
|
}
|
|
787
|
+
return { success: false, message: `Unhandled IDE: ${canonical}` };
|
|
883
788
|
}
|
|
884
789
|
catch (err) {
|
|
885
790
|
const msg = err instanceof Error ? err.message : String(err);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gnosys",
|
|
3
|
-
"version": "5.11.
|
|
3
|
+
"version": "5.11.4",
|
|
4
4
|
"description": "Gnosys — Persistent Memory for AI Agents. Sandbox-first runtime, central SQLite brain, federated search, Dream Mode, Web Knowledge Base, Obsidian export.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|