Repository navigation
feat(connect): Warp + Cline + Continue + Zed + Droid adapters (5 new) #677
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
343e8b2
feat(connect): Warp adapter + skills surface via Claude Code plugin
rohitg00 03ac975
feat(connect): Cline + Continue.dev + Zed + Droid adapters
rohitg00 7330909
fix(connect): droid type:stdio required field + continue yaml-first
rohitg00 ee80f95
fix(connect): coderabbit feedback — grid, dead ternary, yaml message
rohitg00 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import { homedir } from "node:os"; | ||
| import { join } from "node:path"; | ||
| import { createJsonMcpAdapter } from "./json-mcp-adapter.js"; | ||
|
|
||
| // Cline CLI stores MCP server config at ~/.cline/mcp.json with the | ||
| // canonical `mcpServers` wrapper — same schema as Claude Code with | ||
| // optional `disabled` and `autoApprove` fields per entry. | ||
| // VS Code extension users manage MCP through Cline's Settings UI; | ||
| // this adapter targets the standalone CLI surface. | ||
| // Source: github.com/cline/cline/blob/main/docs/mcp/mcp-overview.mdx | ||
| export const adapter = createJsonMcpAdapter({ | ||
| name: "cline", | ||
| displayName: "Cline", | ||
| detectDir: join(homedir(), ".cline"), | ||
| configPath: join(homedir(), ".cline", "mcp.json"), | ||
| docs: "https://github.com/rohitg00/agentmemory#other-agents", | ||
| protocolNote: | ||
| "→ Using MCP via ~/.cline/mcp.json (CLI). VS Code users: add the same block via Cline Settings → MCP Servers → Edit JSON.", | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,163 @@ | ||
| import { existsSync, mkdirSync, writeFileSync } from "node:fs"; | ||
| import { homedir } from "node:os"; | ||
| import { dirname, join } from "node:path"; | ||
| import * as p from "@clack/prompts"; | ||
| import type { ConnectAdapter, ConnectOptions, ConnectResult } from "./types.js"; | ||
| import { | ||
| AGENTMEMORY_MCP_BLOCK, | ||
| backupFile, | ||
| logAlreadyWired, | ||
| logBackup, | ||
| logInstalled, | ||
| readJsonSafe, | ||
| writeJsonAtomic, | ||
| } from "./util.js"; | ||
|
|
||
| // Continue.dev v1+ prefers ~/.continue/config.yaml; config.json is | ||
| // deprecated and ignored when yaml is present. Three branches: | ||
| // - config.yaml exists → emit stub with manual edit instructions | ||
| // (no YAML dep in tree; preserving comments/anchors safely needs it) | ||
| // - config.json exists → modify it (legacy path still loaded when no yaml) | ||
| // - neither → create config.yaml from scratch (no merge risk) | ||
| // Source: docs.continue.dev/reference/yaml-migration | ||
| const CONTINUE_DIR = join(homedir(), ".continue"); | ||
| const YAML_PATH = join(CONTINUE_DIR, "config.yaml"); | ||
| const JSON_PATH = join(CONTINUE_DIR, "config.json"); | ||
|
|
||
| type ContinueEntry = { | ||
| name: string; | ||
| command: string; | ||
| args: string[]; | ||
| env?: Record<string, string>; | ||
| }; | ||
|
|
||
| type ContinueJsonConfig = { | ||
| mcpServers?: ContinueEntry[]; | ||
| [key: string]: unknown; | ||
| }; | ||
|
|
||
| function buildEntry(): ContinueEntry { | ||
| return { | ||
| name: "agentmemory", | ||
| command: AGENTMEMORY_MCP_BLOCK.command, | ||
| args: [...AGENTMEMORY_MCP_BLOCK.args], | ||
| env: { ...AGENTMEMORY_MCP_BLOCK.env }, | ||
| }; | ||
| } | ||
|
|
||
| function entryIsAgentmemory(entry: ContinueEntry | undefined): boolean { | ||
| if (!entry) return false; | ||
| return entry.name === "agentmemory" && entry.args.includes("@agentmemory/mcp"); | ||
| } | ||
|
|
||
| // Minimal YAML emitter for the agentmemory entry. Quotes string values | ||
| // that contain ${ ... } expansion to keep parsers happy. Only used when | ||
| // creating a fresh config.yaml — never when modifying an existing one. | ||
| function renderFreshYaml(): string { | ||
| const e = buildEntry(); | ||
| const envLines = Object.entries(e.env ?? {}) | ||
| .map(([k, v]) => ` ${k}: "${v}"`) | ||
| .join("\n"); | ||
| return [ | ||
| "mcpServers:", | ||
| ` - name: ${e.name}`, | ||
| ` command: ${e.command}`, | ||
| " args:", | ||
| ...e.args.map((a) => ` - "${a}"`), | ||
| " env:", | ||
| envLines, | ||
| "", | ||
| ].join("\n"); | ||
| } | ||
|
|
||
| export const adapter: ConnectAdapter = { | ||
| name: "continue", | ||
| displayName: "Continue", | ||
| docs: "https://github.com/rohitg00/agentmemory#other-agents", | ||
| protocolNote: | ||
| "→ Using MCP via ~/.continue/config.yaml (preferred) or config.json (legacy, only when no yaml).", | ||
|
|
||
| detect(): boolean { | ||
| return existsSync(CONTINUE_DIR); | ||
| }, | ||
|
|
||
| async install(opts: ConnectOptions): Promise<ConnectResult> { | ||
| const yamlExists = existsSync(YAML_PATH); | ||
| const jsonExists = existsSync(JSON_PATH); | ||
|
|
||
| // Branch 1: yaml present — refuse to silently mutate user's yaml | ||
| // config (preserving comments/anchors needs a proper parser). | ||
| if (yamlExists) { | ||
| const indented = renderFreshYaml() | ||
| .split("\n") | ||
| .map((l) => (l ? ` ${l}` : l)) | ||
| .join("\n"); | ||
| const manual = `\nMerge this block into ~/.continue/config.yaml (the snippet already includes the top-level mcpServers key — if your config already has a mcpServers list, append the agentmemory entry to it instead of duplicating the key):\n\n${indented}`; | ||
| p.log.info( | ||
| `Continue: ${YAML_PATH} already exists. Manual edit needed.${manual}`, | ||
| ); | ||
| return { kind: "stub", reason: "config.yaml-needs-manual-edit" }; | ||
| } | ||
|
|
||
| // Branch 2: legacy json present — modify in place. | ||
| if (jsonExists) { | ||
| const existing = readJsonSafe<ContinueJsonConfig>(JSON_PATH); | ||
| const next: ContinueJsonConfig = existing ? { ...existing } : {}; | ||
| const servers = Array.isArray(next.mcpServers) | ||
| ? [...next.mcpServers] | ||
| : []; | ||
|
|
||
| const idx = servers.findIndex((s) => s?.name === "agentmemory"); | ||
| const alreadyHas = idx >= 0 && entryIsAgentmemory(servers[idx]); | ||
| if (alreadyHas && !opts.force) { | ||
| logAlreadyWired("Continue", JSON_PATH); | ||
| return { kind: "already-wired", mutatedPath: JSON_PATH }; | ||
| } | ||
|
|
||
| if (opts.dryRun) { | ||
| p.log.info( | ||
| `[dry-run] Would ${alreadyHas ? "overwrite" : "add"} mcpServers[agentmemory] in ${JSON_PATH}`, | ||
| ); | ||
| return { kind: "installed", mutatedPath: JSON_PATH }; | ||
| } | ||
|
|
||
| const backupPath = backupFile(JSON_PATH, "continue"); | ||
| logBackup(backupPath); | ||
|
|
||
| const entry = buildEntry(); | ||
| if (idx >= 0) servers[idx] = entry; | ||
| else servers.push(entry); | ||
| next.mcpServers = servers; | ||
| writeJsonAtomic(JSON_PATH, next); | ||
|
|
||
| const verify = readJsonSafe<ContinueJsonConfig>(JSON_PATH); | ||
| const verifyEntry = verify?.mcpServers?.find( | ||
| (s) => s?.name === "agentmemory", | ||
| ); | ||
| if (!entryIsAgentmemory(verifyEntry)) { | ||
| p.log.error( | ||
| `Verification failed: ${JSON_PATH} did not contain mcpServers[agentmemory] after write.`, | ||
| ); | ||
| return { kind: "skipped", reason: "verification-failed" }; | ||
| } | ||
|
|
||
| logInstalled("Continue (legacy config.json)", JSON_PATH); | ||
| return { | ||
| kind: "installed", | ||
| mutatedPath: JSON_PATH, | ||
| backupPath, | ||
| }; | ||
| } | ||
|
|
||
| // Branch 3: neither exists — create config.yaml from scratch (modern path). | ||
| if (opts.dryRun) { | ||
| p.log.info(`[dry-run] Would create ${YAML_PATH} with agentmemory entry`); | ||
| return { kind: "installed", mutatedPath: YAML_PATH }; | ||
| } | ||
|
|
||
| mkdirSync(dirname(YAML_PATH), { recursive: true }); | ||
| writeFileSync(YAML_PATH, renderFreshYaml(), "utf-8"); | ||
| logInstalled("Continue", YAML_PATH); | ||
| return { kind: "installed", mutatedPath: YAML_PATH }; | ||
| }, | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| import { homedir } from "node:os"; | ||
| import { join } from "node:path"; | ||
| import { createJsonMcpAdapter } from "./json-mcp-adapter.js"; | ||
|
|
||
| // Factory.ai's Droid CLI stores MCP server config at ~/.factory/mcp.json | ||
| // with the canonical `mcpServers` wrapper. Project-scoped overrides live | ||
| // at <repo>/.factory/mcp.json. Each entry adds an optional `type` field | ||
| // ("stdio" | "http") and `disabled` boolean — agentmemory's stdio block | ||
| // works against the same shape without needing the explicit type tag. | ||
| // Source: docs.factory.ai/cli/configuration/mcp | ||
| export const adapter = createJsonMcpAdapter({ | ||
| name: "droid", | ||
| displayName: "Droid (Factory.ai)", | ||
| detectDir: join(homedir(), ".factory"), | ||
| configPath: join(homedir(), ".factory", "mcp.json"), | ||
| docs: "https://github.com/rohitg00/agentmemory#other-agents", | ||
| protocolNote: | ||
| "→ Using MCP via ~/.factory/mcp.json. The `/mcp` slash command inside droid lists configured servers.", | ||
| // Droid requires `type` per the documented schema. stdio for npx-spawned shim. | ||
| extraEntryFields: { type: "stdio" }, | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import { homedir } from "node:os"; | ||
| import { join } from "node:path"; | ||
| import { createJsonMcpAdapter } from "./json-mcp-adapter.js"; | ||
|
|
||
| // Warp stores MCP server config at ~/.warp/.mcp.json with the | ||
| // canonical `mcpServers` wrapper — identical schema to Claude Code. | ||
| // Warp also auto-discovers skills from .claude/skills/ so the | ||
| // agentmemory plugin's 8 skills are surfaced natively once the | ||
| // Claude Code plugin is installed. | ||
| // Source: docs.warp.dev/agent-platform/capabilities/mcp/ | ||
| export const adapter = createJsonMcpAdapter({ | ||
| name: "warp", | ||
| displayName: "Warp", | ||
| detectDir: join(homedir(), ".warp"), | ||
| configPath: join(homedir(), ".warp", ".mcp.json"), | ||
| docs: "https://github.com/rohitg00/agentmemory#other-agents", | ||
| protocolNote: | ||
| "→ Using MCP via ~/.warp/.mcp.json. Skills auto-discover from .claude/skills/ if the Claude Code plugin is also installed.", | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import { homedir } from "node:os"; | ||
| import { join } from "node:path"; | ||
| import { createJsonMcpAdapter } from "./json-mcp-adapter.js"; | ||
|
|
||
| // Zed stores its settings (including MCP servers) under "context_servers" | ||
| // in settings.json — NOT "mcpServers". User config lives at | ||
| // ~/.config/zed/settings.json on all platforms (Zed uses the XDG path | ||
| // even on macOS; ~/Library/Application Support/Zed/ holds runtime data | ||
| // like the database + cached language servers, not the config). | ||
| // Source: zed.dev/docs/ai/mcp + zed.dev/docs/configuring-zed | ||
| const zedConfigDir = join(homedir(), ".config", "zed"); | ||
|
|
||
| export const adapter = createJsonMcpAdapter({ | ||
| name: "zed", | ||
| displayName: "Zed", | ||
| detectDir: zedConfigDir, | ||
| configPath: join(zedConfigDir, "settings.json"), | ||
| wrapperKey: "context_servers", | ||
| docs: "https://github.com/rohitg00/agentmemory#other-agents", | ||
| protocolNote: | ||
| "→ Using MCP via ~/.config/zed/settings.json (key: context_servers).", | ||
| }); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.