JARVIS / tools /vscode_tools.py
Khanna, Videh Rakesh Rakesh
feat: add device control, app automation, tests, and other updates
8576f52
"""JARVIS VS Code & Copilot Tools — open editors, run commands, assign tasks to Copilot."""
import subprocess
import os
import json
from tools import tool
def _run_osascript(script: str, timeout: int = 10) -> str:
result = subprocess.run(
["osascript", "-e", script],
capture_output=True, text=True, timeout=timeout,
)
return result.stdout.strip()
def _vscode_cli(*args, timeout: int = 15) -> str:
"""Run VS Code CLI command."""
code_paths = [
"/usr/local/bin/code",
"/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code",
os.path.expanduser("~/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code"),
]
code_cmd = None
for p in code_paths:
if os.path.exists(p):
code_cmd = p
break
if code_cmd is None:
# Try PATH
result = subprocess.run(["which", "code"], capture_output=True, text=True)
if result.returncode == 0:
code_cmd = result.stdout.strip()
else:
return "Error: VS Code CLI ('code') not found. Install from VS Code: Cmd+Shift+P → 'Shell Command: Install code command'"
result = subprocess.run(
[code_cmd] + list(args),
capture_output=True, text=True, timeout=timeout,
)
output = result.stdout.strip()
if result.stderr.strip():
output += f"\n{result.stderr.strip()}"
return output or "(done)"
# ─── VS Code Operations ──────────────────────────
@tool(
name="vscode_open",
description="Open a file or folder in VS Code",
parameters={
"type": "object",
"properties": {
"path": {"type": "string", "description": "File or folder path to open"},
"new_window": {"type": "boolean", "description": "Open in new window (default false)"},
},
"required": ["path"],
},
)
def vscode_open(path: str, new_window: bool = False) -> str:
path = os.path.expanduser(path)
args = ["--goto", path] if os.path.isfile(path) else [path]
if new_window:
args.insert(0, "--new-window")
return _vscode_cli(*args)
@tool(
name="vscode_open_terminal",
description="Open VS Code's integrated terminal in a specific folder",
parameters={
"type": "object",
"properties": {
"folder": {"type": "string", "description": "Folder to open terminal in (defaults to current project)"},
},
},
)
def vscode_open_terminal(folder: str = "") -> str:
folder = os.path.expanduser(folder) if folder else os.getcwd()
# Open folder in VS Code, then use AppleScript to open integrated terminal
_vscode_cli(folder)
_run_osascript('''
tell application "Visual Studio Code" to activate
delay 0.5
tell application "System Events"
keystroke "`" using {control down}
end tell
''')
return f"VS Code terminal opened in {folder}"
@tool(
name="vscode_run_command",
description="Execute a VS Code command (like from Command Palette). Use for any VS Code action.",
parameters={
"type": "object",
"properties": {
"command": {"type": "string", "description": "VS Code command ID (e.g. 'workbench.action.togglePanel', 'editor.action.formatDocument')"},
},
"required": ["command"],
},
)
def vscode_run_command(command: str) -> str:
# Use AppleScript to trigger Command Palette and type the command
_run_osascript(f'''
tell application "Visual Studio Code" to activate
delay 0.3
tell application "System Events"
keystroke "p" using {{shift down, command down}}
delay 0.3
keystroke ">{command}"
delay 0.2
keystroke return
end tell
''')
return f"Executed VS Code command: {command}"
@tool(
name="copilot_chat",
description="Send a task/prompt to GitHub Copilot Chat in VS Code. Opens Copilot Chat and types your message.",
parameters={
"type": "object",
"properties": {
"message": {"type": "string", "description": "The task or question to send to Copilot"},
"agent": {"type": "string", "description": "Copilot agent to use: 'workspace' for @workspace, 'terminal' for @terminal, empty for default"},
},
"required": ["message"],
},
)
def copilot_chat(message: str, agent: str = "") -> str:
# Sanitize message for AppleScript
safe_msg = message.replace('"', '\\"').replace("\\", "\\\\")
agent_prefix = ""
if agent == "workspace":
agent_prefix = "@workspace "
elif agent == "terminal":
agent_prefix = "@terminal "
full_msg = f"{agent_prefix}{safe_msg}"
_run_osascript(f'''
tell application "Visual Studio Code" to activate
delay 0.3
tell application "System Events"
-- Open Copilot Chat (Ctrl+Cmd+I)
keystroke "i" using {{control down, command down}}
delay 0.5
keystroke "{full_msg}"
delay 0.2
keystroke return
end tell
''', timeout=15)
return f"Sent to Copilot Chat: {full_msg[:100]}"
@tool(
name="copilot_inline",
description="Use Copilot inline edit (Cmd+I) on the currently open file in VS Code with a specific instruction",
parameters={
"type": "object",
"properties": {
"instruction": {"type": "string", "description": "What to tell Copilot to do (e.g. 'add error handling', 'refactor this function')"},
},
"required": ["instruction"],
},
)
def copilot_inline(instruction: str) -> str:
safe_instr = instruction.replace('"', '\\"').replace("\\", "\\\\")
_run_osascript(f'''
tell application "Visual Studio Code" to activate
delay 0.3
tell application "System Events"
keystroke "i" using {{command down}}
delay 0.5
keystroke "{safe_instr}"
delay 0.2
keystroke return
end tell
''', timeout=15)
return f"Copilot inline edit triggered: {instruction[:80]}"
@tool(
name="vscode_list_extensions",
description="List installed VS Code extensions",
parameters={"type": "object", "properties": {}},
)
def vscode_list_extensions() -> str:
output = _vscode_cli("--list-extensions")
extensions = output.strip().split("\n")
return f"Installed extensions ({len(extensions)}):\n" + "\n".join(f" • {e}" for e in extensions[:30])
@tool(
name="vscode_diff",
description="Open a diff view between two files in VS Code",
parameters={
"type": "object",
"properties": {
"file1": {"type": "string", "description": "First file path"},
"file2": {"type": "string", "description": "Second file path"},
},
"required": ["file1", "file2"],
},
)
def vscode_diff(file1: str, file2: str) -> str:
f1 = os.path.expanduser(file1)
f2 = os.path.expanduser(file2)
return _vscode_cli("--diff", f1, f2)