gemini-computer-use 0.4.3 → 0.4.5
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 -1086
- package/cli.js +56 -0
- package/package.json +14 -24
- package/LICENSE +0 -21
- package/bin/cli.js +0 -122
- package/core/__init__.py +0 -0
- package/core/agent.py +0 -767
- package/core/agent_harness.py +0 -67
- package/core/code_cache.py +0 -244
- package/core/device.py +0 -2400
- package/core/domain.py +0 -303
- package/core/hooks.py +0 -61
- package/core/mcp_tools.py +0 -3497
- package/core/policies.py +0 -132
- package/core/schemas.py +0 -49
- package/core/server.py +0 -972
- package/core/subagents.py +0 -55
- package/core/termux.py +0 -916
- package/core/triggers.py +0 -70
- package/core/updater.py +0 -1713
- package/core/version.py +0 -31
- package/core/vitals.py +0 -181
- package/core/web_share.py +0 -814
- package/gateway.py +0 -2862
- package/install-gui.cmd +0 -40
- package/install-gui.ps1 +0 -1882
- package/install-gui.strings.json +0 -211
- package/install.ps1 +0 -1287
- package/install.sh +0 -2013
- package/ops/doctor.ps1 +0 -735
- package/ops/mesh-domain.sh +0 -86
- package/ops/nginx/README.md +0 -77
- package/ops/nginx/antigravity-mesh-mcp.conf +0 -172
- package/ops/nginx/mesh-domain.vhost.template +0 -58
- package/ops/nginx/render-domain.sh +0 -123
- package/ops/update.ps1 +0 -373
- package/ops/windows/README.md +0 -298
- package/ops/windows/agent-watchdog.ps1 +0 -575
- package/ops/windows/run-hidden.vbs +0 -64
- package/skills/orchestrator.md +0 -26
package/core/agent_harness.py
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import uuid
|
|
3
|
-
from typing import Optional, List
|
|
4
|
-
from google.antigravity import LocalAgentConfig, types
|
|
5
|
-
from core.hooks import get_mesh_hooks
|
|
6
|
-
from core.triggers import create_mesh_watchdog_trigger, create_config_trigger
|
|
7
|
-
from core.policies import get_mesh_policies, ALLOWED_WORKSPACES
|
|
8
|
-
from core.subagents import get_mesh_subagents, get_root_capabilities_config
|
|
9
|
-
|
|
10
|
-
# Derived from the coordinator workspace so the harness works wherever that root
|
|
11
|
-
# is: the documented /root/agy-gdrive-runner on Linux, %USERPROFILE%\agy-gdrive-runner
|
|
12
|
-
# on Windows. A hardcoded POSIX literal was rejected there by the SDK
|
|
13
|
-
# ("app_data_dir must be an absolute path") because os.path.isabs('/root/...') is
|
|
14
|
-
# False on Windows. os.path.abspath keeps it absolute even if the operator pointed
|
|
15
|
-
# MESH_COORDINATOR_WORKSPACE at a relative path.
|
|
16
|
-
_COORDINATOR_ROOT = os.path.abspath(ALLOWED_WORKSPACES[0])
|
|
17
|
-
DEFAULT_SAVE_DIR = os.path.join(_COORDINATOR_ROOT, ".state", "sessions")
|
|
18
|
-
DEFAULT_APP_DATA_DIR = os.path.join(_COORDINATOR_ROOT, ".state", "artifacts")
|
|
19
|
-
|
|
20
|
-
ROOT_SYSTEM_INSTRUCTIONS = (
|
|
21
|
-
"You are the Root Orchestrator for the Antigravity Remote Execution Mesh. "
|
|
22
|
-
"Execute commands strictly through native tools and verified subagents. "
|
|
23
|
-
"Adhere to Zero Drive Queue Policy and Hard Error Halt invariants."
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
def create_agent_config(
|
|
27
|
-
conversation_id: Optional[str] = None,
|
|
28
|
-
save_dir: Optional[str] = None,
|
|
29
|
-
app_data_dir: Optional[str] = None,
|
|
30
|
-
interactive: bool = True,
|
|
31
|
-
max_model_calls: int = 30,
|
|
32
|
-
) -> LocalAgentConfig:
|
|
33
|
-
resolved_save_dir = save_dir or DEFAULT_SAVE_DIR
|
|
34
|
-
resolved_app_data_dir = app_data_dir or DEFAULT_APP_DATA_DIR
|
|
35
|
-
resolved_conv_id = conversation_id or str(uuid.uuid4())
|
|
36
|
-
|
|
37
|
-
os.makedirs(resolved_save_dir, exist_ok=True)
|
|
38
|
-
os.makedirs(resolved_app_data_dir, exist_ok=True)
|
|
39
|
-
|
|
40
|
-
hooks = get_mesh_hooks()
|
|
41
|
-
triggers = [
|
|
42
|
-
create_mesh_watchdog_trigger(interval_seconds=60.0),
|
|
43
|
-
create_config_trigger(path="server_facts.json"),
|
|
44
|
-
]
|
|
45
|
-
policies = get_mesh_policies()
|
|
46
|
-
subagents = get_mesh_subagents()
|
|
47
|
-
capabilities = get_root_capabilities_config()
|
|
48
|
-
|
|
49
|
-
budget = types.BudgetConfig(
|
|
50
|
-
max_model_calls=max_model_calls,
|
|
51
|
-
max_tool_calls=60,
|
|
52
|
-
max_total_tokens=200_000,
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
return LocalAgentConfig(
|
|
56
|
-
system_instructions=ROOT_SYSTEM_INSTRUCTIONS,
|
|
57
|
-
conversation_id=resolved_conv_id,
|
|
58
|
-
save_dir=resolved_save_dir,
|
|
59
|
-
app_data_dir=resolved_app_data_dir,
|
|
60
|
-
hooks=hooks,
|
|
61
|
-
triggers=triggers,
|
|
62
|
-
policies=policies,
|
|
63
|
-
subagents=subagents,
|
|
64
|
-
capabilities=capabilities,
|
|
65
|
-
workspaces=ALLOWED_WORKSPACES,
|
|
66
|
-
budget_config=budget,
|
|
67
|
-
)
|
package/core/code_cache.py
DELETED
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
import ast
|
|
2
|
-
import os
|
|
3
|
-
import json
|
|
4
|
-
from typing import List, Dict, Optional, Any
|
|
5
|
-
from pydantic import BaseModel, Field
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def _index_key(path: str) -> str:
|
|
9
|
-
"""Canonical, platform-stable key for a file inside the index.
|
|
10
|
-
|
|
11
|
-
``os.path.normpath`` returns backslashes on Windows, so the same repository
|
|
12
|
-
produced ``core\\schemas.py`` there and ``core/schemas.py`` on Linux: the
|
|
13
|
-
cache written on one platform did not match on the other and symbols were
|
|
14
|
-
reported with a separator the model could not paste back into a command.
|
|
15
|
-
Forward slashes work for every Windows API too, so they are used everywhere.
|
|
16
|
-
"""
|
|
17
|
-
return os.path.normpath(path).replace("\\", "/")
|
|
18
|
-
|
|
19
|
-
class CodeSymbol(BaseModel):
|
|
20
|
-
name: str
|
|
21
|
-
kind: str # "class", "function", "async_function"
|
|
22
|
-
file_path: str
|
|
23
|
-
line_start: int
|
|
24
|
-
line_end: int
|
|
25
|
-
docstring: Optional[str] = None
|
|
26
|
-
|
|
27
|
-
class FileEntry(BaseModel):
|
|
28
|
-
path: str
|
|
29
|
-
mtime: float
|
|
30
|
-
size: int
|
|
31
|
-
symbols: List[CodeSymbol] = Field(default_factory=list)
|
|
32
|
-
|
|
33
|
-
class CodeIndex:
|
|
34
|
-
IGNORE_DIRS = {
|
|
35
|
-
".git",
|
|
36
|
-
"__pycache__",
|
|
37
|
-
".pytest_cache",
|
|
38
|
-
".state",
|
|
39
|
-
"live_logs",
|
|
40
|
-
"node_modules",
|
|
41
|
-
".gemini",
|
|
42
|
-
".agents",
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
def __init__(self, root_dir: str = ".", cache_file: str = ".state/code_index.json"):
|
|
46
|
-
self.root_dir = root_dir
|
|
47
|
-
self.cache_file = cache_file
|
|
48
|
-
self.files: Dict[str, FileEntry] = {}
|
|
49
|
-
self.symbol_map: Dict[str, List[CodeSymbol]] = {}
|
|
50
|
-
self._content_cache: Dict[str, tuple[float, List[str]]] = {}
|
|
51
|
-
self._load_cache()
|
|
52
|
-
|
|
53
|
-
def _load_cache(self) -> None:
|
|
54
|
-
if os.path.exists(self.cache_file):
|
|
55
|
-
try:
|
|
56
|
-
with open(self.cache_file, "r", encoding="utf-8") as f:
|
|
57
|
-
data = json.load(f)
|
|
58
|
-
for path, entry_data in data.get("files", {}).items():
|
|
59
|
-
entry = FileEntry.model_validate(entry_data)
|
|
60
|
-
self.files[path] = entry
|
|
61
|
-
for sym in entry.symbols:
|
|
62
|
-
self.symbol_map.setdefault(sym.name, []).append(sym)
|
|
63
|
-
except Exception:
|
|
64
|
-
self.files = {}
|
|
65
|
-
self.symbol_map = {}
|
|
66
|
-
|
|
67
|
-
def _save_cache(self) -> None:
|
|
68
|
-
try:
|
|
69
|
-
os.makedirs(os.path.dirname(os.path.abspath(self.cache_file)), exist_ok=True)
|
|
70
|
-
data = {
|
|
71
|
-
"files": {k: v.model_dump() for k, v in self.files.items()}
|
|
72
|
-
}
|
|
73
|
-
tmp_file = self.cache_file + ".tmp"
|
|
74
|
-
with open(tmp_file, "w", encoding="utf-8") as f:
|
|
75
|
-
json.dump(data, f, indent=2)
|
|
76
|
-
os.replace(tmp_file, self.cache_file)
|
|
77
|
-
except Exception:
|
|
78
|
-
pass
|
|
79
|
-
|
|
80
|
-
def _parse_py_file(self, file_path: str) -> List[CodeSymbol]:
|
|
81
|
-
symbols: List[CodeSymbol] = []
|
|
82
|
-
try:
|
|
83
|
-
with open(file_path, "r", encoding="utf-8", errors="replace") as f:
|
|
84
|
-
code = f.read()
|
|
85
|
-
tree = ast.parse(code, filename=file_path)
|
|
86
|
-
for node in ast.iter_child_nodes(tree):
|
|
87
|
-
if isinstance(node, ast.ClassDef):
|
|
88
|
-
doc = ast.get_docstring(node)
|
|
89
|
-
end_lineno = getattr(node, "end_lineno", node.lineno)
|
|
90
|
-
symbols.append(CodeSymbol(
|
|
91
|
-
name=node.name,
|
|
92
|
-
kind="class",
|
|
93
|
-
file_path=file_path,
|
|
94
|
-
line_start=node.lineno,
|
|
95
|
-
line_end=end_lineno,
|
|
96
|
-
docstring=doc,
|
|
97
|
-
))
|
|
98
|
-
for item in node.body:
|
|
99
|
-
if isinstance(item, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
100
|
-
m_doc = ast.get_docstring(item)
|
|
101
|
-
m_end = getattr(item, "end_lineno", item.lineno)
|
|
102
|
-
symbols.append(CodeSymbol(
|
|
103
|
-
name=f"{node.name}.{item.name}",
|
|
104
|
-
kind="method",
|
|
105
|
-
file_path=file_path,
|
|
106
|
-
line_start=item.lineno,
|
|
107
|
-
line_end=m_end,
|
|
108
|
-
docstring=m_doc,
|
|
109
|
-
))
|
|
110
|
-
elif isinstance(node, ast.AsyncFunctionDef):
|
|
111
|
-
doc = ast.get_docstring(node)
|
|
112
|
-
end_lineno = getattr(node, "end_lineno", node.lineno)
|
|
113
|
-
symbols.append(CodeSymbol(
|
|
114
|
-
name=node.name,
|
|
115
|
-
kind="async_function",
|
|
116
|
-
file_path=file_path,
|
|
117
|
-
line_start=node.lineno,
|
|
118
|
-
line_end=end_lineno,
|
|
119
|
-
docstring=doc,
|
|
120
|
-
))
|
|
121
|
-
elif isinstance(node, ast.FunctionDef):
|
|
122
|
-
doc = ast.get_docstring(node)
|
|
123
|
-
end_lineno = getattr(node, "end_lineno", node.lineno)
|
|
124
|
-
symbols.append(CodeSymbol(
|
|
125
|
-
name=node.name,
|
|
126
|
-
kind="function",
|
|
127
|
-
file_path=file_path,
|
|
128
|
-
line_start=node.lineno,
|
|
129
|
-
line_end=end_lineno,
|
|
130
|
-
docstring=doc,
|
|
131
|
-
))
|
|
132
|
-
except Exception:
|
|
133
|
-
pass
|
|
134
|
-
return symbols
|
|
135
|
-
|
|
136
|
-
def build_or_update(self) -> Dict[str, int]:
|
|
137
|
-
total_files = 0
|
|
138
|
-
parsed_files = 0
|
|
139
|
-
cache_hits = 0
|
|
140
|
-
current_seen: set[str] = set()
|
|
141
|
-
|
|
142
|
-
for root, dirs, files in os.walk(self.root_dir):
|
|
143
|
-
dirs[:] = [d for d in dirs if d not in self.IGNORE_DIRS]
|
|
144
|
-
for file in files:
|
|
145
|
-
if not file.endswith(".py"):
|
|
146
|
-
continue
|
|
147
|
-
file_path = _index_key(os.path.join(root, file))
|
|
148
|
-
current_seen.add(file_path)
|
|
149
|
-
total_files += 1
|
|
150
|
-
|
|
151
|
-
try:
|
|
152
|
-
stat = os.stat(file_path)
|
|
153
|
-
except OSError:
|
|
154
|
-
continue
|
|
155
|
-
|
|
156
|
-
if file_path in self.files and self.files[file_path].mtime == stat.st_mtime:
|
|
157
|
-
cache_hits += 1
|
|
158
|
-
else:
|
|
159
|
-
parsed_files += 1
|
|
160
|
-
symbols = self._parse_py_file(file_path)
|
|
161
|
-
self.files[file_path] = FileEntry(
|
|
162
|
-
path=file_path,
|
|
163
|
-
mtime=stat.st_mtime,
|
|
164
|
-
size=stat.st_size,
|
|
165
|
-
symbols=symbols,
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
# Remove deleted files
|
|
169
|
-
for old_path in list(self.files.keys()):
|
|
170
|
-
if old_path not in current_seen:
|
|
171
|
-
del self.files[old_path]
|
|
172
|
-
|
|
173
|
-
# Rebuild symbol map
|
|
174
|
-
self.symbol_map.clear()
|
|
175
|
-
for entry in self.files.values():
|
|
176
|
-
for sym in entry.symbols:
|
|
177
|
-
self.symbol_map.setdefault(sym.name, []).append(sym)
|
|
178
|
-
|
|
179
|
-
self._save_cache()
|
|
180
|
-
return {
|
|
181
|
-
"total_files": total_files,
|
|
182
|
-
"parsed_files": parsed_files,
|
|
183
|
-
"cache_hits": cache_hits,
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
def find_symbol(self, name: str, exact: bool = True) -> List[CodeSymbol]:
|
|
187
|
-
if exact:
|
|
188
|
-
return self.symbol_map.get(name, [])
|
|
189
|
-
matches: List[CodeSymbol] = []
|
|
190
|
-
name_lower = name.lower()
|
|
191
|
-
for sym_name, sym_list in self.symbol_map.items():
|
|
192
|
-
if name_lower in sym_name.lower():
|
|
193
|
-
matches.extend(sym_list)
|
|
194
|
-
return matches
|
|
195
|
-
|
|
196
|
-
def get_file_outline(self, file_path: str) -> List[CodeSymbol]:
|
|
197
|
-
norm = _index_key(file_path)
|
|
198
|
-
for path, entry in self.files.items():
|
|
199
|
-
if norm == path or norm.endswith(path) or path.endswith(norm):
|
|
200
|
-
return entry.symbols
|
|
201
|
-
return []
|
|
202
|
-
|
|
203
|
-
def get_cached_chunk(self, file_path: str, start_line: int = 1, end_line: int = 100) -> str:
|
|
204
|
-
norm = _index_key(file_path)
|
|
205
|
-
try:
|
|
206
|
-
stat = os.stat(norm)
|
|
207
|
-
mtime = stat.st_mtime
|
|
208
|
-
except OSError:
|
|
209
|
-
return f"Error: File '{file_path}' not found."
|
|
210
|
-
|
|
211
|
-
cached = self._content_cache.get(norm)
|
|
212
|
-
if cached is None or cached[0] != mtime:
|
|
213
|
-
try:
|
|
214
|
-
with open(norm, "r", encoding="utf-8", errors="replace") as f:
|
|
215
|
-
lines = f.readlines()
|
|
216
|
-
self._content_cache[norm] = (mtime, lines)
|
|
217
|
-
except Exception as e:
|
|
218
|
-
return f"Error reading file '{file_path}': {e}"
|
|
219
|
-
else:
|
|
220
|
-
lines = cached[1]
|
|
221
|
-
|
|
222
|
-
total = len(lines)
|
|
223
|
-
s = max(1, start_line) - 1
|
|
224
|
-
e = min(total, end_line)
|
|
225
|
-
slice_lines = lines[s:e]
|
|
226
|
-
return f"[{norm} | Lines {s+1}-{e} of {total}]\n" + "".join(slice_lines)
|
|
227
|
-
|
|
228
|
-
def get_sitemap(self) -> Dict[str, Any]:
|
|
229
|
-
sitemap = {}
|
|
230
|
-
for path, entry in sorted(self.files.items()):
|
|
231
|
-
sitemap[path] = [
|
|
232
|
-
{"name": s.name, "kind": s.kind, "lines": f"{s.line_start}-{s.line_end}"}
|
|
233
|
-
for s in entry.symbols
|
|
234
|
-
]
|
|
235
|
-
return sitemap
|
|
236
|
-
|
|
237
|
-
_GLOBAL_INDEX: Optional[CodeIndex] = None
|
|
238
|
-
|
|
239
|
-
def get_code_index(root_dir: str = ".") -> CodeIndex:
|
|
240
|
-
global _GLOBAL_INDEX
|
|
241
|
-
if _GLOBAL_INDEX is None:
|
|
242
|
-
_GLOBAL_INDEX = CodeIndex(root_dir=root_dir)
|
|
243
|
-
_GLOBAL_INDEX.build_or_update()
|
|
244
|
-
return _GLOBAL_INDEX
|