@musashishao/agent-kit 1.2.2 → 1.3.0

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.
Files changed (39) hide show
  1. package/.agent/mcp-gateway/README.md +121 -0
  2. package/.agent/mcp-gateway/dist/index.d.ts +11 -0
  3. package/.agent/mcp-gateway/dist/index.js +504 -0
  4. package/.agent/mcp-gateway/dist/sync/debouncer.d.ts +56 -0
  5. package/.agent/mcp-gateway/dist/sync/debouncer.js +112 -0
  6. package/.agent/mcp-gateway/dist/sync/incremental_syncer.d.ts +58 -0
  7. package/.agent/mcp-gateway/dist/sync/incremental_syncer.js +172 -0
  8. package/.agent/mcp-gateway/dist/sync/index.d.ts +6 -0
  9. package/.agent/mcp-gateway/dist/sync/index.js +6 -0
  10. package/.agent/mcp-gateway/dist/sync/timestamp_checker.d.ts +69 -0
  11. package/.agent/mcp-gateway/dist/sync/timestamp_checker.js +169 -0
  12. package/.agent/mcp-gateway/package.json +28 -0
  13. package/.agent/mcp-gateway/src/index.ts +608 -0
  14. package/.agent/mcp-gateway/src/sync/debouncer.ts +129 -0
  15. package/.agent/mcp-gateway/src/sync/incremental_syncer.ts +237 -0
  16. package/.agent/mcp-gateway/src/sync/index.ts +7 -0
  17. package/.agent/mcp-gateway/src/sync/timestamp_checker.ts +194 -0
  18. package/.agent/scripts/ak_cli.py +533 -0
  19. package/.agent/scripts/setup_host.py +557 -0
  20. package/.agent/scripts/verify_install.py +174 -0
  21. package/.agent/skills/app-builder/SKILL.md +51 -1
  22. package/.agent/skills/app-builder/scripts/generate_ai_infra.py +510 -0
  23. package/.agent/skills/documentation-templates/SKILL.md +9 -1
  24. package/.agent/skills/documentation-templates/agents-template.md +202 -0
  25. package/.agent/skills/graph-mapper/SKILL.md +211 -0
  26. package/.agent/skills/graph-mapper/scripts/generate_graph.py +503 -0
  27. package/.agent/skills/rag-engineering/SKILL.md +342 -0
  28. package/.agent/skills/rag-engineering/chunking-strategies.md +229 -0
  29. package/.agent/skills/rag-engineering/contextual-retrieval.md +261 -0
  30. package/.agent/skills/rag-engineering/hybrid-search.md +356 -0
  31. package/.agent/skills/rag-engineering/scripts/chunk_code.py +606 -0
  32. package/.agent/templates/mcp_configs/claude_desktop.json +14 -0
  33. package/.agent/templates/mcp_configs/cursor.json +13 -0
  34. package/.agent/templates/mcp_configs/vscode.json +13 -0
  35. package/.agent/workflows/create.md +70 -2
  36. package/bin/cli.js +91 -0
  37. package/docs/AI_DATA_INFRASTRUCTURE.md +288 -0
  38. package/docs/CHANGELOG_AI_INFRA.md +111 -0
  39. package/package.json +7 -2
@@ -0,0 +1,557 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ AI Host Auto-Configuration
4
+
5
+ Automatically detects and configures AI hosts (Claude Desktop, Cursor, VS Code)
6
+ to use the Agent Kit MCP Gateway.
7
+
8
+ Usage:
9
+ python setup_host.py --project-root /path/to/project
10
+ python setup_host.py --list # List detected hosts only
11
+ """
12
+
13
+ import os
14
+ import sys
15
+ import json
16
+ import shutil
17
+ import platform
18
+ import argparse
19
+ import subprocess
20
+ from pathlib import Path
21
+ from typing import Dict, List, Optional, Tuple
22
+
23
+
24
+ # ============================================================================
25
+ # Constants
26
+ # ============================================================================
27
+
28
+ SUPPORTED_HOSTS = {
29
+ "claude_desktop": {
30
+ "name": "Claude Desktop",
31
+ "config_paths": {
32
+ "Darwin": "~/Library/Application Support/Claude/claude_desktop_config.json",
33
+ "Windows": "%APPDATA%/Claude/claude_desktop_config.json",
34
+ "Linux": "~/.config/Claude/claude_desktop_config.json",
35
+ },
36
+ "detection": {
37
+ "Darwin": ["/Applications/Claude.app"],
38
+ "Windows": ["%LOCALAPPDATA%/Programs/Claude/Claude.exe"],
39
+ "Linux": [],
40
+ },
41
+ },
42
+ "cursor": {
43
+ "name": "Cursor",
44
+ "config_paths": {
45
+ "Darwin": ".cursor/mcp.json", # Project-local
46
+ "Windows": ".cursor/mcp.json",
47
+ "Linux": ".cursor/mcp.json",
48
+ },
49
+ "detection": {
50
+ "Darwin": ["/Applications/Cursor.app"],
51
+ "Windows": ["%LOCALAPPDATA%/Programs/Cursor/Cursor.exe"],
52
+ "Linux": ["/usr/bin/cursor", "~/.local/bin/cursor"],
53
+ },
54
+ },
55
+ "vscode": {
56
+ "name": "VS Code",
57
+ "config_paths": {
58
+ "Darwin": ".vscode/settings.json", # Project-local
59
+ "Windows": ".vscode/settings.json",
60
+ "Linux": ".vscode/settings.json",
61
+ },
62
+ "detection": {
63
+ "Darwin": ["/Applications/Visual Studio Code.app"],
64
+ "Windows": ["%LOCALAPPDATA%/Programs/Microsoft VS Code/Code.exe"],
65
+ "Linux": ["/usr/bin/code", "/snap/bin/code"],
66
+ },
67
+ },
68
+ "windsurf": {
69
+ "name": "Windsurf",
70
+ "config_paths": {
71
+ "Darwin": ".windsurf/mcp.json",
72
+ "Windows": ".windsurf/mcp.json",
73
+ "Linux": ".windsurf/mcp.json",
74
+ },
75
+ "detection": {
76
+ "Darwin": ["/Applications/Windsurf.app"],
77
+ "Windows": [],
78
+ "Linux": [],
79
+ },
80
+ },
81
+ }
82
+
83
+
84
+ # ============================================================================
85
+ # Utility Functions
86
+ # ============================================================================
87
+
88
+ def get_os() -> str:
89
+ """Get current operating system."""
90
+ return platform.system()
91
+
92
+
93
+ def expand_path(path: str) -> Path:
94
+ """Expand environment variables and user home in path."""
95
+ expanded = os.path.expandvars(os.path.expanduser(path))
96
+ return Path(expanded)
97
+
98
+
99
+ def is_host_installed(host_id: str) -> bool:
100
+ """Check if an AI host is installed."""
101
+ host = SUPPORTED_HOSTS.get(host_id)
102
+ if not host:
103
+ return False
104
+
105
+ os_name = get_os()
106
+ detection_paths = host["detection"].get(os_name, [])
107
+
108
+ for path in detection_paths:
109
+ expanded = expand_path(path)
110
+ if expanded.exists():
111
+ return True
112
+
113
+ return False
114
+
115
+
116
+ def detect_installed_hosts() -> List[str]:
117
+ """Detect which AI hosts are installed on this system."""
118
+ installed = []
119
+ for host_id in SUPPORTED_HOSTS:
120
+ if is_host_installed(host_id):
121
+ installed.append(host_id)
122
+ return installed
123
+
124
+
125
+ def get_config_path(host_id: str, project_root: Path) -> Optional[Path]:
126
+ """Get the config file path for a host."""
127
+ host = SUPPORTED_HOSTS.get(host_id)
128
+ if not host:
129
+ return None
130
+
131
+ os_name = get_os()
132
+ config_path = host["config_paths"].get(os_name)
133
+ if not config_path:
134
+ return None
135
+
136
+ # Check if it's a project-local path (starts with .)
137
+ if config_path.startswith("."):
138
+ return project_root / config_path
139
+ else:
140
+ return expand_path(config_path)
141
+
142
+
143
+ def backup_config(config_path: Path) -> Optional[Path]:
144
+ """Create a backup of existing config file."""
145
+ if not config_path.exists():
146
+ return None
147
+
148
+ backup_path = config_path.with_suffix(config_path.suffix + ".backup")
149
+ shutil.copy2(config_path, backup_path)
150
+ return backup_path
151
+
152
+
153
+ def load_json_config(path: Path) -> Dict:
154
+ """Load JSON config file, return empty dict if not exists."""
155
+ if not path.exists():
156
+ return {}
157
+
158
+ try:
159
+ with open(path, "r", encoding="utf-8") as f:
160
+ return json.load(f)
161
+ except json.JSONDecodeError:
162
+ return {}
163
+
164
+
165
+ def save_json_config(path: Path, config: Dict) -> bool:
166
+ """Save config to JSON file."""
167
+ try:
168
+ path.parent.mkdir(parents=True, exist_ok=True)
169
+ with open(path, "w", encoding="utf-8") as f:
170
+ json.dump(config, f, indent=2)
171
+ return True
172
+ except Exception as e:
173
+ print(f"Error saving config: {e}")
174
+ return False
175
+
176
+
177
+ # ============================================================================
178
+ # Configuration Functions
179
+ # ============================================================================
180
+
181
+ def generate_mcp_config(
182
+ project_root: Path,
183
+ mcp_server_path: Path,
184
+ kit_path: Path
185
+ ) -> Dict:
186
+ """Generate MCP server configuration."""
187
+ return {
188
+ "command": "node",
189
+ "args": [str(mcp_server_path)],
190
+ "env": {
191
+ "PROJECT_ROOT": str(project_root),
192
+ "AGENT_KIT_PATH": str(kit_path),
193
+ },
194
+ }
195
+
196
+
197
+ def configure_claude_desktop(
198
+ project_root: Path,
199
+ mcp_server_path: Path,
200
+ kit_path: Path,
201
+ dry_run: bool = False
202
+ ) -> Tuple[bool, str]:
203
+ """Configure Claude Desktop to use Agent Kit MCP."""
204
+ config_path = get_config_path("claude_desktop", project_root)
205
+ if not config_path:
206
+ return False, "Could not determine Claude Desktop config path"
207
+
208
+ # Load existing config
209
+ config = load_json_config(config_path)
210
+
211
+ # Initialize mcpServers if not exists
212
+ if "mcpServers" not in config:
213
+ config["mcpServers"] = {}
214
+
215
+ # Check if already configured
216
+ if "agent-kit" in config["mcpServers"]:
217
+ existing = config["mcpServers"]["agent-kit"]
218
+ if existing.get("env", {}).get("PROJECT_ROOT") == str(project_root):
219
+ return True, "Already configured for this project"
220
+
221
+ # Add our server config
222
+ config["mcpServers"]["agent-kit"] = generate_mcp_config(
223
+ project_root, mcp_server_path, kit_path
224
+ )
225
+
226
+ if dry_run:
227
+ return True, f"Would update: {config_path}"
228
+
229
+ # Backup and save
230
+ backup = backup_config(config_path)
231
+ if backup:
232
+ print(f" Backed up to: {backup}")
233
+
234
+ if save_json_config(config_path, config):
235
+ return True, f"Configured: {config_path}"
236
+ else:
237
+ return False, "Failed to save config"
238
+
239
+
240
+ def configure_cursor(
241
+ project_root: Path,
242
+ mcp_server_path: Path,
243
+ kit_path: Path,
244
+ dry_run: bool = False
245
+ ) -> Tuple[bool, str]:
246
+ """Configure Cursor to use Agent Kit MCP (project-local)."""
247
+ config_path = get_config_path("cursor", project_root)
248
+ if not config_path:
249
+ return False, "Could not determine Cursor config path"
250
+
251
+ # For Cursor, use relative paths since it's project-local
252
+ relative_mcp_path = ".agent/mcp-gateway/dist/index.js"
253
+
254
+ config = load_json_config(config_path)
255
+
256
+ if "mcpServers" not in config:
257
+ config["mcpServers"] = {}
258
+
259
+ config["mcpServers"]["agent-kit"] = {
260
+ "command": "node",
261
+ "args": [relative_mcp_path],
262
+ "env": {
263
+ "PROJECT_ROOT": ".",
264
+ },
265
+ }
266
+
267
+ if dry_run:
268
+ return True, f"Would create: {config_path}"
269
+
270
+ if save_json_config(config_path, config):
271
+ return True, f"Created: {config_path}"
272
+ else:
273
+ return False, "Failed to save config"
274
+
275
+
276
+ def configure_vscode(
277
+ project_root: Path,
278
+ mcp_server_path: Path,
279
+ kit_path: Path,
280
+ dry_run: bool = False
281
+ ) -> Tuple[bool, str]:
282
+ """Configure VS Code settings for MCP (if MCP extension is installed)."""
283
+ config_path = get_config_path("vscode", project_root)
284
+ if not config_path:
285
+ return False, "Could not determine VS Code config path"
286
+
287
+ config = load_json_config(config_path)
288
+
289
+ # Add MCP config (format may vary by extension)
290
+ if "mcp.servers" not in config:
291
+ config["mcp.servers"] = {}
292
+
293
+ config["mcp.servers"]["agent-kit"] = {
294
+ "command": "node",
295
+ "args": ["${workspaceFolder}/.agent/mcp-gateway/dist/index.js"],
296
+ "env": {
297
+ "PROJECT_ROOT": "${workspaceFolder}",
298
+ },
299
+ }
300
+
301
+ if dry_run:
302
+ return True, f"Would update: {config_path}"
303
+
304
+ if save_json_config(config_path, config):
305
+ return True, f"Updated: {config_path}"
306
+ else:
307
+ return False, "Failed to save config"
308
+
309
+
310
+ def configure_windsurf(
311
+ project_root: Path,
312
+ mcp_server_path: Path,
313
+ kit_path: Path,
314
+ dry_run: bool = False
315
+ ) -> Tuple[bool, str]:
316
+ """Configure Windsurf to use Agent Kit MCP (project-local)."""
317
+ config_path = get_config_path("windsurf", project_root)
318
+ if not config_path:
319
+ return False, "Could not determine Windsurf config path"
320
+
321
+ relative_mcp_path = ".agent/mcp-gateway/dist/index.js"
322
+
323
+ config = load_json_config(config_path)
324
+
325
+ if "mcpServers" not in config:
326
+ config["mcpServers"] = {}
327
+
328
+ config["mcpServers"]["agent-kit"] = {
329
+ "command": "node",
330
+ "args": [relative_mcp_path],
331
+ "env": {
332
+ "PROJECT_ROOT": ".",
333
+ },
334
+ }
335
+
336
+ if dry_run:
337
+ return True, f"Would create: {config_path}"
338
+
339
+ if save_json_config(config_path, config):
340
+ return True, f"Created: {config_path}"
341
+ else:
342
+ return False, "Failed to save config"
343
+
344
+
345
+ # ============================================================================
346
+ # Clipboard Helper
347
+ # ============================================================================
348
+
349
+ def copy_to_clipboard(text: str) -> bool:
350
+ """Copy text to system clipboard."""
351
+ os_name = get_os()
352
+
353
+ try:
354
+ if os_name == "Darwin":
355
+ process = subprocess.Popen(
356
+ ["pbcopy"],
357
+ stdin=subprocess.PIPE,
358
+ )
359
+ process.communicate(text.encode("utf-8"))
360
+ return process.returncode == 0
361
+ elif os_name == "Windows":
362
+ process = subprocess.Popen(
363
+ ["clip"],
364
+ stdin=subprocess.PIPE,
365
+ )
366
+ process.communicate(text.encode("utf-16"))
367
+ return process.returncode == 0
368
+ elif os_name == "Linux":
369
+ # Try xclip first, then xsel
370
+ for cmd in [["xclip", "-selection", "clipboard"], ["xsel", "--clipboard", "--input"]]:
371
+ try:
372
+ process = subprocess.Popen(cmd, stdin=subprocess.PIPE)
373
+ process.communicate(text.encode("utf-8"))
374
+ if process.returncode == 0:
375
+ return True
376
+ except FileNotFoundError:
377
+ continue
378
+ return False
379
+ except Exception:
380
+ return False
381
+
382
+ return False
383
+
384
+
385
+ # ============================================================================
386
+ # Main Setup Function
387
+ # ============================================================================
388
+
389
+ def setup_hosts(
390
+ project_root: Path,
391
+ hosts: Optional[List[str]] = None,
392
+ dry_run: bool = False,
393
+ force: bool = False
394
+ ) -> Dict[str, Tuple[bool, str]]:
395
+ """
396
+ Configure all detected AI hosts.
397
+
398
+ Args:
399
+ project_root: Path to the project root
400
+ hosts: Specific hosts to configure (None = all detected)
401
+ dry_run: If True, only show what would be done
402
+ force: If True, reconfigure even if already set up
403
+
404
+ Returns:
405
+ Dict mapping host_id to (success, message)
406
+ """
407
+ results = {}
408
+
409
+ # Determine MCP server path
410
+ mcp_server_path = project_root / ".agent" / "mcp-gateway" / "dist" / "index.js"
411
+ kit_path = project_root / ".agent"
412
+
413
+ # Check if MCP server is built
414
+ if not mcp_server_path.exists():
415
+ print("⚠️ MCP Gateway not built. Building now...")
416
+ build_result = subprocess.run(
417
+ ["npm", "run", "build"],
418
+ cwd=str(project_root / ".agent" / "mcp-gateway"),
419
+ capture_output=True,
420
+ text=True,
421
+ )
422
+ if build_result.returncode != 0:
423
+ return {"error": (False, "Failed to build MCP Gateway")}
424
+
425
+ # Determine which hosts to configure
426
+ if hosts:
427
+ target_hosts = hosts
428
+ else:
429
+ target_hosts = detect_installed_hosts()
430
+ # Always include project-local configs
431
+ target_hosts.extend(["cursor", "vscode", "windsurf"])
432
+ target_hosts = list(set(target_hosts))
433
+
434
+ # Configure each host
435
+ configurators = {
436
+ "claude_desktop": configure_claude_desktop,
437
+ "cursor": configure_cursor,
438
+ "vscode": configure_vscode,
439
+ "windsurf": configure_windsurf,
440
+ }
441
+
442
+ for host_id in target_hosts:
443
+ if host_id not in configurators:
444
+ results[host_id] = (False, f"Unknown host: {host_id}")
445
+ continue
446
+
447
+ print(f"\n🔧 Configuring {SUPPORTED_HOSTS[host_id]['name']}...")
448
+ success, message = configurators[host_id](
449
+ project_root, mcp_server_path, kit_path, dry_run
450
+ )
451
+ results[host_id] = (success, message)
452
+
453
+ status = "✅" if success else "❌"
454
+ print(f" {status} {message}")
455
+
456
+ return results
457
+
458
+
459
+ # ============================================================================
460
+ # CLI Entry Point
461
+ # ============================================================================
462
+
463
+ def main():
464
+ parser = argparse.ArgumentParser(
465
+ description="Auto-configure AI hosts for Agent Kit MCP"
466
+ )
467
+ parser.add_argument(
468
+ "--project-root",
469
+ default=".",
470
+ help="Project root directory",
471
+ )
472
+ parser.add_argument(
473
+ "--list",
474
+ action="store_true",
475
+ help="List detected AI hosts only",
476
+ )
477
+ parser.add_argument(
478
+ "--dry-run",
479
+ action="store_true",
480
+ help="Show what would be done without making changes",
481
+ )
482
+ parser.add_argument(
483
+ "--hosts",
484
+ nargs="+",
485
+ choices=list(SUPPORTED_HOSTS.keys()),
486
+ help="Specific hosts to configure",
487
+ )
488
+ parser.add_argument(
489
+ "--copy-config",
490
+ action="store_true",
491
+ help="Copy config to clipboard for manual setup",
492
+ )
493
+
494
+ args = parser.parse_args()
495
+ project_root = Path(args.project_root).resolve()
496
+
497
+ print("🤖 Agent Kit - AI Host Auto-Configuration")
498
+ print(f"📁 Project: {project_root}")
499
+ print(f"💻 OS: {get_os()}")
500
+
501
+ # List mode
502
+ if args.list:
503
+ print("\n📋 Detected AI Hosts:")
504
+ installed = detect_installed_hosts()
505
+ for host_id, host in SUPPORTED_HOSTS.items():
506
+ status = "✅ Installed" if host_id in installed else "❌ Not found"
507
+ print(f" - {host['name']}: {status}")
508
+ return 0
509
+
510
+ # Copy config to clipboard mode
511
+ if args.copy_config:
512
+ mcp_server_path = project_root / ".agent" / "mcp-gateway" / "dist" / "index.js"
513
+ config = {
514
+ "mcpServers": {
515
+ "agent-kit": {
516
+ "command": "node",
517
+ "args": [str(mcp_server_path)],
518
+ "env": {
519
+ "PROJECT_ROOT": str(project_root),
520
+ },
521
+ }
522
+ }
523
+ }
524
+ config_json = json.dumps(config, indent=2)
525
+
526
+ if copy_to_clipboard(config_json):
527
+ print("\n✅ Config copied to clipboard!")
528
+ print("\n📋 Paste this into your AI host's MCP configuration:")
529
+ print(config_json)
530
+ else:
531
+ print("\n⚠️ Could not copy to clipboard. Here's the config:")
532
+ print(config_json)
533
+ return 0
534
+
535
+ # Normal configuration mode
536
+ results = setup_hosts(
537
+ project_root,
538
+ hosts=args.hosts,
539
+ dry_run=args.dry_run,
540
+ )
541
+
542
+ # Summary
543
+ print("\n" + "=" * 50)
544
+ print("📊 Configuration Summary:")
545
+ success_count = sum(1 for success, _ in results.values() if success)
546
+ total_count = len(results)
547
+ print(f" ✅ {success_count}/{total_count} hosts configured successfully")
548
+
549
+ if success_count > 0:
550
+ print("\n🎉 Setup complete! Your AI hosts are now connected to Agent Kit.")
551
+ print(" Restart your AI host to apply changes.")
552
+
553
+ return 0 if success_count == total_count else 1
554
+
555
+
556
+ if __name__ == "__main__":
557
+ sys.exit(main())