-
Notifications
You must be signed in to change notification settings - Fork 1.5k
feat(connect): add Kilo CLI adapter #630
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| import { existsSync } from "node:fs"; | ||
| import { homedir } from "node:os"; | ||
| import { join } from "node:path"; | ||
| import type { ConnectAdapter, ConnectOptions, ConnectResult } from "./types.js"; | ||
| import { | ||
| backupFile, | ||
| logAlreadyWired, | ||
| logBackup, | ||
| logInstalled, | ||
| readJsonSafe, | ||
| writeJsonAtomic, | ||
| } from "./util.js"; | ||
|
|
||
| type McpEntry = { | ||
| type: string; | ||
| command: string[]; | ||
| environment?: Record<string, string>; | ||
| enabled?: boolean; | ||
| }; | ||
|
|
||
| type KiloConfig = { | ||
| mcp?: Record<string, McpEntry>; | ||
| [key: string]: unknown; | ||
| }; | ||
|
|
||
| // Env values use ${VAR} expansion so the wired MCP entry inherits | ||
| // AGENTMEMORY_URL / AGENTMEMORY_SECRET from the user's shell. | ||
| const AGENTMEMORY_MCP_BLOCK: McpEntry = { | ||
| type: "local", | ||
| command: ["npx", "-y", "@agentmemory/mcp"], | ||
| environment: { | ||
| AGENTMEMORY_URL: "${AGENTMEMORY_URL}", | ||
| AGENTMEMORY_SECRET: "${AGENTMEMORY_SECRET}", | ||
| }, | ||
| enabled: true, | ||
| }; | ||
|
|
||
| function entryMatches(entry: unknown): boolean { | ||
| if (!entry || typeof entry !== "object") return false; | ||
| const e = entry as Record<string, unknown>; | ||
| const cmd = Array.isArray(e["command"]) ? (e["command"] as string[]) : []; | ||
| return cmd.some((c) => c.includes("@agentmemory/mcp")); | ||
| } | ||
|
|
||
| const configDir = join(homedir(), ".config", "kilo"); | ||
| const configFiles = ["kilo.jsonc", "kilo.json", "opencode.jsonc", "opencode.json"]; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check if a JSONC parser is available in package.json dependencies
cat package.json | jq '.dependencies, .devDependencies' | grep -i 'jsonc\|strip-json'Repository: rohitg00/agentmemory Length of output: 46 🏁 Script executed: #!/bin/bash
set -euo pipefail
# 1) Inspect the referenced file and relevant helpers
sed -n '1,140p' src/cli/connect/kilo.ts | cat -n
# 2) Locate the implementations of readJsonSafe / writeJsonAtomic in the repo
echo "---- rg readJsonSafe ----"
rg -n "readJsonSafe" -S src
echo "---- rg writeJsonAtomic ----"
rg -n "writeJsonAtomic" -S src
# 3) Re-check package.json for JSONC-related deps
echo "---- package.json deps matching jsonc/strip-json-comments ----"
cat package.json | jq -r '
([.dependencies, .devDependencies] | add | to_entries | map(.key) | .[])
' 2>/dev/null | rg -i 'jsonc|strip-json'Repository: rohitg00/agentmemory Length of output: 6083 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect JSON helpers
sed -n '1,120p' src/cli/connect/util.ts | cat -n
# Search package.json for jsonc/strip-json-comments mentions
echo "---- rg package.json for jsonc/strip-json-comments ----"
rg -n "jsonc|strip-json-comments" package.json || trueRepository: rohitg00/agentmemory Length of output: 3032 Critical:
Fix options
🤖 Prompt for AI Agents |
||
|
|
||
| function findConfigFile(): string | null { | ||
| for (const file of configFiles) { | ||
| const fullPath = join(configDir, file); | ||
| if (existsSync(fullPath)) return fullPath; | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| export const adapter: ConnectAdapter = { | ||
| name: "kilo", | ||
| displayName: "Kilo", | ||
| docs: "https://github.com/rohitg00/agentmemory/tree/main/integrations/kilo", | ||
| protocolNote: "→ Using MCP. Kilo implements memory hooks natively in its codebase.", | ||
|
|
||
| detect(): boolean { | ||
| return existsSync(configDir) || findConfigFile() !== null; | ||
| }, | ||
|
|
||
| async install(opts: ConnectOptions): Promise<ConnectResult> { | ||
| const configPath = findConfigFile() ?? join(configDir, "kilo.json"); | ||
| const existing = readJsonSafe<KiloConfig>(configPath); | ||
| const next: KiloConfig = existing ? { ...existing } : {}; | ||
| const mcp: Record<string, McpEntry> = { | ||
| ...((next.mcp as Record<string, McpEntry>) ?? {}), | ||
| }; | ||
|
|
||
| const alreadyHas = entryMatches(mcp["agentmemory"]); | ||
| if (alreadyHas && !opts.force) { | ||
| logAlreadyWired("Kilo", configPath); | ||
| return { kind: "already-wired", mutatedPath: configPath }; | ||
| } | ||
|
|
||
| if (opts.dryRun) { | ||
| console.log( | ||
| `[dry-run] Would ${alreadyHas ? "overwrite" : "add"} mcp.agentmemory in ${configPath}`, | ||
| ); | ||
| return { kind: "installed", mutatedPath: configPath }; | ||
| } | ||
|
|
||
| let backupPath: string | undefined; | ||
| if (existsSync(configPath)) { | ||
| backupPath = backupFile(configPath, "kilo"); | ||
| logBackup(backupPath); | ||
| } | ||
|
|
||
| mcp["agentmemory"] = AGENTMEMORY_MCP_BLOCK; | ||
| next.mcp = mcp; | ||
| writeJsonAtomic(configPath, next); | ||
|
|
||
| const verify = readJsonSafe<KiloConfig>(configPath); | ||
| if (!entryMatches(verify?.mcp?.["agentmemory"])) { | ||
| console.error( | ||
| `Verification failed: ${configPath} did not contain mcp.agentmemory after write.`, | ||
| ); | ||
| return { kind: "skipped", reason: "verification-failed" }; | ||
| } | ||
|
|
||
| logInstalled("Kilo", configPath); | ||
| return { | ||
| kind: "installed", | ||
| mutatedPath: configPath, | ||
| ...(backupPath !== undefined && { backupPath }), | ||
| }; | ||
| }, | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: rohitg00/agentmemory
Length of output: 391
🏁 Script executed:
Repository: rohitg00/agentmemory
Length of output: 179
🏁 Script executed:
Repository: rohitg00/agentmemory
Length of output: 180
🏁 Script executed:
Repository: rohitg00/agentmemory
Length of output: 180
🏁 Script executed:
Repository: rohitg00/agentmemory
Length of output: 14748
Update
test/cli-connect.test.tsto include the newkiloadapter (expect 9 adapters)src/cli/connect/index.tsnow registerskiloinADAPTERS, but the test still expects exactly 8 adapters and aknownAgents()list that excludes"kilo".🧪 Proposed test fix
🤖 Prompt for AI Agents