@kahinmcp/kahin 0.1.6 → 0.1.8
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 +18 -30
- package/bin/kahin.mjs +7 -0
- package/bin/setup.mjs +324 -0
- package/package.json +20 -6
package/README.md
CHANGED
|
@@ -33,49 +33,37 @@ CDP'yi bilmeyen AI'a Chrome'u kontrol etmeyi öğreten, yanlış yapınca düzel
|
|
|
33
33
|
|
|
34
34
|
## Kurulum
|
|
35
35
|
|
|
36
|
-
Zorunlu: Python 3.12+ · Chrome/Chromium
|
|
36
|
+
Zorunlu: Python 3.12+ · Chrome/Chromium · Node.js 18+ (npm launcher için)
|
|
37
|
+
|
|
38
|
+
### Otomatik kurulum — tek komut
|
|
37
39
|
|
|
38
40
|
```bash
|
|
39
41
|
pnpm add -g kahin
|
|
40
|
-
kahin --upgrade # ilk çalıştırmada Python ortamını kurar (~30 sn)
|
|
41
42
|
```
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Kaynak kodunla geliştirme:
|
|
44
|
+
Bu kadar. Kurulum sonrası Kahin, sistemindeki AI CLI araçlarını otomatik tespit eder ve kendini kaydeder:
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
git clone https://github.com/void0x14/cdp-kahin-mcp
|
|
49
|
-
cd cdp-kahin-mcp
|
|
50
|
-
uv venv && source .venv/bin/activate
|
|
51
|
-
uv pip install -e .
|
|
52
|
-
```
|
|
46
|
+
**Claude Code · Claude Desktop · Cursor · Windsurf · opencode · Codex CLI · Gemini CLI · Zed · VS Code · Cline · Cline CLI · Roo Code · Kilo Code · Continue · Amazon Q · Trae · BoltAI · Antigravity · Amp · MCPorter · GitHub Copilot CLI · Goose**
|
|
53
47
|
|
|
54
|
-
|
|
48
|
+
Mevcut config'lerine dokunmaz, sadece `kahin` girişini ekler (merge). Zaten kayıtlıysa atlar (idempotent). Elle JSON yazmana gerek yok.
|
|
55
49
|
|
|
56
|
-
|
|
50
|
+
Yeni bir araç kurduysan veya kurulum kaçırdıysa:
|
|
57
51
|
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
"type": "local",
|
|
61
|
-
"command": ["kahin"],
|
|
62
|
-
"enabled": true
|
|
63
|
-
}
|
|
52
|
+
```bash
|
|
53
|
+
kahin setup
|
|
64
54
|
```
|
|
65
55
|
|
|
66
|
-
|
|
56
|
+
Otomatik kurulumu devre dışı bırakmak için: `KAHIN_SKIP_AUTO_SETUP=1`
|
|
57
|
+
|
|
58
|
+
`kahin` çalışınca MCP stdio server'ı başlar. Python ortamı `~/.local/share/kahin/` altında yönetilir.
|
|
67
59
|
|
|
68
|
-
|
|
60
|
+
Kaynak kodunla geliştirme:
|
|
69
61
|
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
"args": []
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
62
|
+
```bash
|
|
63
|
+
git clone https://gitlab.com/void0x14/kahin-mcp
|
|
64
|
+
cd kahin-mcp
|
|
65
|
+
uv venv && source .venv/bin/activate
|
|
66
|
+
uv pip install -e .
|
|
79
67
|
```
|
|
80
68
|
|
|
81
69
|
## Kullanım
|
package/bin/kahin.mjs
CHANGED
|
@@ -30,6 +30,13 @@ async function setup() {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
const args = process.argv.slice(2);
|
|
33
|
+
|
|
34
|
+
if (args[0] === "setup") {
|
|
35
|
+
const { setup } = await import("./setup.mjs");
|
|
36
|
+
setup();
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
|
|
33
40
|
const python = await setup();
|
|
34
41
|
const child = spawn(python, ["-m", "kahin.oracle", ...args], { stdio: "inherit" });
|
|
35
42
|
child.on("exit", (code, signal) => {
|
package/bin/setup.mjs
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// kahin auto-setup — kurulu AI CLI istemcilerini tespit eder ve kahin MCP'yi kaydeder.
|
|
3
|
+
// Idempotent: zaten kayıtlıysa atlar, mevcut config'leri merge eder (ezmez).
|
|
4
|
+
// Opt-out: KAHIN_SKIP_AUTO_SETUP=1
|
|
5
|
+
// El ile: kahin setup
|
|
6
|
+
//
|
|
7
|
+
// Client listesi, otomatik tespit yapan sistemlerden derlendi (add-mcp 15 ajan,
|
|
8
|
+
// everymcp 15, mcpm 20+, getmcp 19, mcp-get 9, mcpkit): 22 client.
|
|
9
|
+
|
|
10
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
11
|
+
import { homedir } from "node:os";
|
|
12
|
+
import { join, dirname } from "node:path";
|
|
13
|
+
|
|
14
|
+
const HOME = homedir();
|
|
15
|
+
const isWin = process.platform === "win32";
|
|
16
|
+
const isMac = process.platform === "darwin";
|
|
17
|
+
const APPDATA = process.env.APPDATA || join(HOME, "AppData", "Roaming");
|
|
18
|
+
|
|
19
|
+
const ENTRY = { command: "kahin", args: [] };
|
|
20
|
+
const ENTRY_OPENCODE = { type: "local", command: ["kahin"], enabled: true };
|
|
21
|
+
const ENTRY_VSCODE = { type: "stdio", command: "kahin", args: [] };
|
|
22
|
+
|
|
23
|
+
// VS Code uzantı globalStorage yolu (Cline/Roo/Kilo burada yaşar)
|
|
24
|
+
function vscodeStorage(...ext) {
|
|
25
|
+
const base = isWin
|
|
26
|
+
? join(APPDATA, "Code", "User", "globalStorage")
|
|
27
|
+
: isMac
|
|
28
|
+
? join(HOME, "Library", "Application Support", "Code", "User", "globalStorage")
|
|
29
|
+
: join(HOME, ".config", "Code", "User", "globalStorage");
|
|
30
|
+
return join(base, ...ext);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// her client: { name, file, root, entry, format }
|
|
34
|
+
const CLIENTS = [
|
|
35
|
+
// ---- JSON: root "mcpServers" ----
|
|
36
|
+
{
|
|
37
|
+
name: "Claude Code",
|
|
38
|
+
file: join(HOME, ".claude.json"),
|
|
39
|
+
root: "mcpServers",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "Claude Desktop",
|
|
43
|
+
file: isWin
|
|
44
|
+
? join(APPDATA, "Claude", "claude_desktop_config.json")
|
|
45
|
+
: join(HOME, ".config", "Claude", "claude_desktop_config.json"),
|
|
46
|
+
root: "mcpServers",
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "Cursor",
|
|
50
|
+
file: join(HOME, ".cursor", "mcp.json"),
|
|
51
|
+
root: "mcpServers",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: "Windsurf",
|
|
55
|
+
file: join(HOME, ".codeium", "windsurf", "mcp_config.json"),
|
|
56
|
+
root: "mcpServers",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: "Gemini CLI",
|
|
60
|
+
file: join(HOME, ".gemini", "settings.json"),
|
|
61
|
+
root: "mcpServers",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: "Cline (VS Code)",
|
|
65
|
+
file: vscodeStorage("saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
|
|
66
|
+
root: "mcpServers",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "Cline CLI",
|
|
70
|
+
file: join(HOME, ".cline", "data", "settings", "cline_mcp_settings.json"),
|
|
71
|
+
root: "mcpServers",
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: "Roo Code",
|
|
75
|
+
file: vscodeStorage("rooveterinaryinc.roo-cline", "settings", "mcp_settings.json"),
|
|
76
|
+
root: "mcpServers",
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: "Kilo Code",
|
|
80
|
+
file: vscodeStorage("kilocode.kilo-code", "settings", "mcp_settings.json"),
|
|
81
|
+
root: "mcpServers",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: "Continue",
|
|
85
|
+
file: join(HOME, ".continue", "config.json"),
|
|
86
|
+
root: "mcpServers",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "Amazon Q",
|
|
90
|
+
file: join(HOME, ".aws", "amazonq", "mcp.json"),
|
|
91
|
+
root: "mcpServers",
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: "Trae",
|
|
95
|
+
file: join(HOME, ".trae", "mcp.json"),
|
|
96
|
+
root: "mcpServers",
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: "BoltAI",
|
|
100
|
+
file: isMac
|
|
101
|
+
? join(HOME, "Library", "Application Support", "boltAI", "config.json")
|
|
102
|
+
: join(HOME, ".boltai", "config.json"),
|
|
103
|
+
root: "mcpServers",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: "Antigravity",
|
|
107
|
+
file: join(HOME, ".gemini", "config", "mcp_config.json"),
|
|
108
|
+
root: "mcpServers",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: "Amp",
|
|
112
|
+
file: join(HOME, ".amp", "config.json"),
|
|
113
|
+
root: "mcpServers",
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: "MCPorter",
|
|
117
|
+
file: join(HOME, ".mcporter", "mcporter.json"),
|
|
118
|
+
root: "mcpServers",
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: "GitHub Copilot CLI",
|
|
122
|
+
file: join(HOME, ".copilot", "mcp-config.json"),
|
|
123
|
+
root: "mcpServers",
|
|
124
|
+
},
|
|
125
|
+
// ---- JSON: özel root ----
|
|
126
|
+
{
|
|
127
|
+
name: "Zed",
|
|
128
|
+
file: isWin
|
|
129
|
+
? join(APPDATA, "Zed", "settings.json")
|
|
130
|
+
: isMac
|
|
131
|
+
? join(HOME, "Library", "Application Support", "Zed", "settings.json")
|
|
132
|
+
: join(HOME, ".config", "zed", "settings.json"),
|
|
133
|
+
root: "context_servers",
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
name: "opencode",
|
|
137
|
+
file: join(HOME, ".config", "opencode", "opencode.json"),
|
|
138
|
+
root: "mcp",
|
|
139
|
+
entry: ENTRY_OPENCODE,
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: "VS Code",
|
|
143
|
+
file: isWin
|
|
144
|
+
? join(APPDATA, "Code", "User", "mcp.json")
|
|
145
|
+
: isMac
|
|
146
|
+
? join(HOME, "Library", "Application Support", "Code", "User", "mcp.json")
|
|
147
|
+
: join(HOME, ".config", "Code", "User", "mcp.json"),
|
|
148
|
+
root: "servers",
|
|
149
|
+
entry: ENTRY_VSCODE,
|
|
150
|
+
},
|
|
151
|
+
// ---- TOML ----
|
|
152
|
+
{
|
|
153
|
+
name: "Codex CLI",
|
|
154
|
+
file: join(HOME, ".codex", "config.toml"),
|
|
155
|
+
root: "mcp_servers",
|
|
156
|
+
format: "toml",
|
|
157
|
+
},
|
|
158
|
+
// ---- YAML ----
|
|
159
|
+
{
|
|
160
|
+
name: "Goose",
|
|
161
|
+
file: join(HOME, ".config", "goose", "config.yaml"),
|
|
162
|
+
root: "extensions",
|
|
163
|
+
format: "yaml",
|
|
164
|
+
},
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
function log(msg) {
|
|
168
|
+
process.stderr.write(`[kahin] ${msg}\n`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// JSONC (yorumlu JSON) için basit strip — // ve /* */ satırları temizler.
|
|
172
|
+
function stripJsonc(src) {
|
|
173
|
+
let out = "";
|
|
174
|
+
let i = 0;
|
|
175
|
+
const n = src.length;
|
|
176
|
+
let inStr = false;
|
|
177
|
+
while (i < n) {
|
|
178
|
+
const c = src[i];
|
|
179
|
+
const nx = src[i + 1];
|
|
180
|
+
if (inStr) {
|
|
181
|
+
out += c;
|
|
182
|
+
if (c === "\\") {
|
|
183
|
+
out += nx ?? "";
|
|
184
|
+
i += 2;
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
if (c === '"') inStr = false;
|
|
188
|
+
i++;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (c === '"') {
|
|
192
|
+
inStr = true;
|
|
193
|
+
out += c;
|
|
194
|
+
i++;
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
if (c === "/" && nx === "/") {
|
|
198
|
+
while (i < n && src[i] !== "\n") i++;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
if (c === "/" && nx === "*") {
|
|
202
|
+
i += 2;
|
|
203
|
+
while (i < n && !(src[i] === "*" && src[i + 1] === "/")) i++;
|
|
204
|
+
i += 2;
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
out += c;
|
|
208
|
+
i++;
|
|
209
|
+
}
|
|
210
|
+
return out;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function readJson(file) {
|
|
214
|
+
try {
|
|
215
|
+
return JSON.parse(stripJsonc(readFileSync(file, "utf8")));
|
|
216
|
+
} catch {
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function upsertJson(client) {
|
|
222
|
+
const { file, root, name } = client;
|
|
223
|
+
const entry = client.entry || ENTRY;
|
|
224
|
+
const cfg = readJson(file);
|
|
225
|
+
if (cfg === undefined) {
|
|
226
|
+
log(`${name}: config okunamadı (bozuk JSON?), atlandı`);
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
if (typeof cfg !== "object" || cfg === null || Array.isArray(cfg)) {
|
|
230
|
+
log(`${name}: beklenmeyen config yapısı, atlandı`);
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
const rootObj = cfg[root];
|
|
234
|
+
if (rootObj !== undefined && typeof rootObj !== "object") {
|
|
235
|
+
log(`${name}: beklenmeyen "${root}" yapısı, atlandı`);
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
cfg[root] = cfg[root] || {};
|
|
239
|
+
if (cfg[root]["kahin"]) {
|
|
240
|
+
log(`${name}: zaten kayıtlı, atlandı`);
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
cfg[root]["kahin"] = entry;
|
|
244
|
+
writeFileSync(file, JSON.stringify(cfg, null, 2) + "\n");
|
|
245
|
+
log(`${name}: kaydedildi (${file})`);
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function upsertToml(client) {
|
|
250
|
+
const { file, name } = client;
|
|
251
|
+
let content = "";
|
|
252
|
+
try {
|
|
253
|
+
content = readFileSync(file, "utf8");
|
|
254
|
+
} catch {
|
|
255
|
+
log(`${name}: config okunamadı, atlandı`);
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
if (content.includes("[mcp_servers.kahin]")) {
|
|
259
|
+
log(`${name}: zaten kayıtlı, atlandı`);
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
content += `\n[mcp_servers.kahin]\ncommand = "kahin"\nargs = []\n`;
|
|
263
|
+
writeFileSync(file, content);
|
|
264
|
+
log(`${name}: kaydedildi (${file})`);
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function upsertYaml(client) {
|
|
269
|
+
const { file, name } = client;
|
|
270
|
+
let content = "";
|
|
271
|
+
try {
|
|
272
|
+
content = readFileSync(file, "utf8");
|
|
273
|
+
} catch {
|
|
274
|
+
log(`${name}: config okunamadı, atlandı`);
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
// extensions altında kahin bloğu var mı?
|
|
278
|
+
if (/^extensions:\s*$[\s\S]*?^ kahin:/m.test(content)) {
|
|
279
|
+
log(`${name}: zaten kayıtlı, atlandı`);
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
if (!/^extensions:/m.test(content)) {
|
|
283
|
+
content += "\nextensions:\n";
|
|
284
|
+
}
|
|
285
|
+
content += " kahin:\n cmd: kahin\n enabled: true\n";
|
|
286
|
+
writeFileSync(file, content);
|
|
287
|
+
log(`${name}: kaydedildi (${file})`);
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export function setup() {
|
|
292
|
+
if (process.env.KAHIN_SKIP_AUTO_SETUP || process.env.CI) {
|
|
293
|
+
log("otomatik kurulum atlandı (KAHIN_SKIP_AUTO_SETUP/CI)");
|
|
294
|
+
return { skipped: true };
|
|
295
|
+
}
|
|
296
|
+
let installed = 0;
|
|
297
|
+
let found = 0;
|
|
298
|
+
for (const client of CLIENTS) {
|
|
299
|
+
if (!existsSync(client.file)) continue;
|
|
300
|
+
found++;
|
|
301
|
+
mkdirSync(dirname(client.file), { recursive: true });
|
|
302
|
+
const ok =
|
|
303
|
+
client.format === "toml"
|
|
304
|
+
? upsertToml(client)
|
|
305
|
+
: client.format === "yaml"
|
|
306
|
+
? upsertYaml(client)
|
|
307
|
+
: upsertJson(client);
|
|
308
|
+
if (ok) installed++;
|
|
309
|
+
}
|
|
310
|
+
if (installed === 0) {
|
|
311
|
+
if (found > 0) {
|
|
312
|
+
log("tüm tespit edilen istemcilerde kahin zaten kayıtlı.");
|
|
313
|
+
} else {
|
|
314
|
+
log("desteklenen AI CLI aracı bulunamadı. `kahin setup` ile sonradan çalıştır.");
|
|
315
|
+
}
|
|
316
|
+
} else {
|
|
317
|
+
log(`tamamlandı: ${installed} istemciye kaydedildi. Yeni kurulum sonrası aracı yeniden başlat.`);
|
|
318
|
+
}
|
|
319
|
+
return { installed };
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (process.argv[1] && process.argv[1].endsWith("setup.mjs")) {
|
|
323
|
+
setup();
|
|
324
|
+
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kahinmcp/kahin",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Kahin — CDP ansiklopedisi + anti-detect browser otomasyon MCP sunucusu. Obscura ve Camoufox motorlarını kullanır, motor seçimini ajana bırakır.",
|
|
3
|
+
"version": "0.1.8",
|
|
4
|
+
"description": "Kahin — CDP ansiklopedisi + anti-detect browser otomasyon MCP sunucusu. Kurulumda 22 AI CLI aracını otomatik tespit edip kendini kaydeder. Obscura ve Camoufox motorlarını kullanır, motor seçimini ajana bırakır.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"kahin": "bin/kahin.mjs"
|
|
7
7
|
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"postinstall": "node bin/setup.mjs",
|
|
10
|
+
"setup": "node bin/setup.mjs"
|
|
11
|
+
},
|
|
8
12
|
"files": [
|
|
9
13
|
"bin",
|
|
10
14
|
"LICENSE"
|
|
@@ -15,21 +19,31 @@
|
|
|
15
19
|
"license": "AGPL-3.0",
|
|
16
20
|
"repository": {
|
|
17
21
|
"type": "git",
|
|
18
|
-
"url": "git+https://
|
|
22
|
+
"url": "git+https://gitlab.com/void0x14/kahin-mcp.git"
|
|
19
23
|
},
|
|
20
|
-
"homepage": "https://
|
|
24
|
+
"homepage": "https://gitlab.com/void0x14/kahin-mcp",
|
|
21
25
|
"bugs": {
|
|
22
|
-
"url": "https://
|
|
26
|
+
"url": "https://gitlab.com/void0x14/kahin-mcp/-/issues"
|
|
23
27
|
},
|
|
24
28
|
"keywords": [
|
|
25
29
|
"cdp",
|
|
26
30
|
"chrome-devtools-protocol",
|
|
27
31
|
"mcp",
|
|
28
32
|
"model-context-protocol",
|
|
33
|
+
"mcp-server",
|
|
29
34
|
"browser-automation",
|
|
30
35
|
"camoufox",
|
|
31
36
|
"anti-detect",
|
|
37
|
+
"ai-agents",
|
|
38
|
+
"ai",
|
|
32
39
|
"llm",
|
|
33
|
-
"
|
|
40
|
+
"automation",
|
|
41
|
+
"web-scraping",
|
|
42
|
+
"claude-code",
|
|
43
|
+
"cursor",
|
|
44
|
+
"windsurf",
|
|
45
|
+
"opencode",
|
|
46
|
+
"codex",
|
|
47
|
+
"python"
|
|
34
48
|
]
|
|
35
49
|
}
|