scios-cli 0.3.1__tar.gz → 0.4.0__tar.gz
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.
- {scios_cli-0.3.1 → scios_cli-0.4.0}/PKG-INFO +1 -1
- {scios_cli-0.3.1 → scios_cli-0.4.0}/pyproject.toml +1 -1
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/ag/create_flow.py +97 -46
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/ag/local_runner.py +1 -1
- scios_cli-0.4.0/scios_cli/ag/plugin.py +371 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/ag/scaffold.py +18 -5
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/app.py +37 -0
- scios_cli-0.4.0/scios_cli/commands/ag.py +1319 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/login.py +29 -1
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/run.py +58 -45
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/setup.py +164 -3
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli.egg-info/PKG-INFO +1 -1
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli.egg-info/SOURCES.txt +1 -0
- scios_cli-0.3.1/scios_cli/commands/ag.py +0 -450
- {scios_cli-0.3.1 → scios_cli-0.4.0}/LICENSE +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/README.md +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/__init__.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/__main__.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/ag/__init__.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/ag/api_client.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/ag/dashboards.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/ag/manifest.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/ag/sync_core.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/auth_store.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/__init__.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/agent.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/bench.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/chat.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/db.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/deploy.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/export.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/houdini.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/langfuse.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/logs.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/profile.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/sync.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/train.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/trust.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/video.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/commands/workspace.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/config.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/houdini.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/houdini_recorder.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/install.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/main.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/mcp/__init__.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/mcp/server_core.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli/mcp/server_maxwell.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli.egg-info/dependency_links.txt +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli.egg-info/entry_points.txt +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli.egg-info/requires.txt +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/scios_cli.egg-info/top_level.txt +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/setup.cfg +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/setup.py +0 -0
- {scios_cli-0.3.1 → scios_cli-0.4.0}/tests/test_ag.py +0 -0
|
@@ -86,9 +86,17 @@ def create_and_build(
|
|
|
86
86
|
max_wall_clock_min: int,
|
|
87
87
|
wait: bool,
|
|
88
88
|
launch: bool,
|
|
89
|
+
build: bool = False,
|
|
89
90
|
log: Callable[[str], None] = print,
|
|
90
91
|
) -> dict:
|
|
91
|
-
"""
|
|
92
|
+
"""Cold-start: create workspace + refine goal + idea.
|
|
93
|
+
|
|
94
|
+
When build=False (default for `scios ag create`): stops after creating the
|
|
95
|
+
idea. The scientist reviews the refined goal and idea before proceeding.
|
|
96
|
+
When build=True (used by `scios ag go`): also kicks off build-execute.
|
|
97
|
+
|
|
98
|
+
Returns {idea_id, folder, status}.
|
|
99
|
+
"""
|
|
92
100
|
from scios_cli.ag import scaffold as scaffold_mod
|
|
93
101
|
from scios_cli.ag import sync_core
|
|
94
102
|
|
|
@@ -101,11 +109,8 @@ def create_and_build(
|
|
|
101
109
|
log(f" workspace {workspace_id}")
|
|
102
110
|
|
|
103
111
|
log(f"② Refining the goal (AI auto-amend, same as /dashboard/plan) …")
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
# exactly what the web /dashboard/plan page does. Fall back to the raw prompt
|
|
107
|
-
# only if the refinement call is unavailable.
|
|
108
|
-
title, description, target, details = goal[:120], goal, None, None
|
|
112
|
+
title, description, target_metrics, details = goal[:120], goal, None, None
|
|
113
|
+
methodology, constraints = None, None
|
|
109
114
|
try:
|
|
110
115
|
sess = client.maxwell_create_session(workspace_id=workspace_id)
|
|
111
116
|
session_id = sess.get("id") or sess.get("sessionId") or sess.get("session_id")
|
|
@@ -113,7 +118,7 @@ def create_and_build(
|
|
|
113
118
|
sug = client.suggest_all_fields(session_id, research_context=goal)
|
|
114
119
|
title = sug.get("title") or title
|
|
115
120
|
description = sug.get("description") or description
|
|
116
|
-
|
|
121
|
+
target_metrics = sug.get("targetMetrics") or sug.get("target_metrics") or None
|
|
117
122
|
methodology = sug.get("methodology")
|
|
118
123
|
constraints = sug.get("constraints")
|
|
119
124
|
parts = [p for p in (
|
|
@@ -121,14 +126,14 @@ def create_and_build(
|
|
|
121
126
|
(f"## Constraints\n{constraints}" if constraints else None),
|
|
122
127
|
) if p]
|
|
123
128
|
details = "\n\n".join(parts) or None
|
|
124
|
-
log(f" ✨ refined → \"{title}\"" + (f" | target: {
|
|
129
|
+
log(f" ✨ refined → \"{title}\"" + (f" | target: {target_metrics[:60]}" if target_metrics else ""))
|
|
125
130
|
except SciosAPIError as e:
|
|
126
131
|
log(f" (auto-amend unavailable: {e}; using raw prompt)")
|
|
127
132
|
|
|
128
133
|
log(f"③ Creating research goal …")
|
|
129
134
|
rg = client.create_research_goal(
|
|
130
135
|
workspace_id=workspace_id, title=title, description=description,
|
|
131
|
-
target=
|
|
136
|
+
target=target_metrics, details=details, original_prompt=goal,
|
|
132
137
|
)
|
|
133
138
|
goal_id = rg.get("id") or rg.get("goalId")
|
|
134
139
|
log(f" goal {goal_id}")
|
|
@@ -141,31 +146,52 @@ def create_and_build(
|
|
|
141
146
|
raise SystemExit(1)
|
|
142
147
|
log(f" idea {idea_id}")
|
|
143
148
|
|
|
149
|
+
# Write manifest + idea.md so the scientist can review
|
|
150
|
+
target_folder = Path(folder).expanduser().resolve() if folder else (Path.cwd() / f"scios-{name}")
|
|
151
|
+
target_folder.mkdir(parents=True, exist_ok=True)
|
|
152
|
+
|
|
153
|
+
host = endpoint.rstrip("/").removesuffix("/api/v1").rstrip("/")
|
|
154
|
+
m = Manifest(
|
|
155
|
+
idea_id=idea_id, endpoint=endpoint, token="",
|
|
156
|
+
execution=ExecutionConfig(mode="local", host_url=host),
|
|
157
|
+
)
|
|
158
|
+
m.budget.compute_scale = scale
|
|
159
|
+
m.budget.optimizer_iterations = budget_iterations
|
|
160
|
+
m.budget.max_wall_clock_min = max_wall_clock_min
|
|
161
|
+
save(target_folder, m)
|
|
162
|
+
|
|
163
|
+
# Write idea.md for the scientist to review
|
|
164
|
+
_write_idea_md(target_folder, idea_id=idea_id, workspace_id=workspace_id,
|
|
165
|
+
goal_id=goal_id, title=title, description=description,
|
|
166
|
+
target_metrics=target_metrics, methodology=methodology,
|
|
167
|
+
constraints=constraints, host=host)
|
|
168
|
+
|
|
169
|
+
if not build:
|
|
170
|
+
# ── Stage-by-stage mode (default for `scios ag create`) ──
|
|
171
|
+
# Stop here. The scientist reviews idea.md, then says "run it" to
|
|
172
|
+
# kick off build-execute via `scios ag run`.
|
|
173
|
+
log(f"")
|
|
174
|
+
log(f"✨ Idea created: {idea_id}")
|
|
175
|
+
log(f" Folder: {target_folder}")
|
|
176
|
+
log(f" Review: {target_folder / 'idea.md'}")
|
|
177
|
+
log(f"")
|
|
178
|
+
log(f" Next steps:")
|
|
179
|
+
log(f" • Review idea.md — the AI-refined research goal")
|
|
180
|
+
log(f" • scios ag status — check build progress")
|
|
181
|
+
log(f" • scios ag run — kick off build-execute")
|
|
182
|
+
log(f" • scios ag explain — see scores after completion")
|
|
183
|
+
return {"idea_id": idea_id, "folder": str(target_folder), "status": "created"}
|
|
184
|
+
|
|
185
|
+
# ── Full pipeline mode (used by `scios ag go`) ──
|
|
144
186
|
log(f"⑤ Kicking off build-execute (scale={scale}, iterations={budget_iterations}) …")
|
|
145
187
|
stage_config = _build_stage_config(scale, budget_iterations, max_wall_clock_min)
|
|
146
188
|
client.trigger_build_execute(idea_id, stage_config=stage_config)
|
|
147
189
|
|
|
148
|
-
target = Path(folder).expanduser().resolve() if folder else (Path.cwd() / f"scios-{name}")
|
|
149
|
-
|
|
150
190
|
if not wait:
|
|
151
|
-
# Nothing to project yet — the workflow is built asynchronously. Write a
|
|
152
|
-
# minimal manifest so `ag status`/`ag mount` work once it's ready, and
|
|
153
|
-
# tell the user how to resume. (Mounting now would 404: no workflow yet.)
|
|
154
|
-
host = endpoint.rstrip("/").removesuffix("/api/v1").rstrip("/")
|
|
155
|
-
m = Manifest(
|
|
156
|
-
idea_id=idea_id, endpoint=endpoint, token="",
|
|
157
|
-
execution=ExecutionConfig(mode="local", host_url=host),
|
|
158
|
-
)
|
|
159
|
-
m.budget.compute_scale = scale
|
|
160
|
-
m.budget.optimizer_iterations = budget_iterations
|
|
161
|
-
m.budget.max_wall_clock_min = max_wall_clock_min
|
|
162
|
-
target.mkdir(parents=True, exist_ok=True)
|
|
163
|
-
save(target, m)
|
|
164
191
|
log(f"✨ Build-execute started for idea {idea_id} (scale={scale}).")
|
|
165
|
-
log(f"
|
|
166
|
-
log(f"
|
|
167
|
-
|
|
168
|
-
return {"idea_id": idea_id, "folder": str(target), "status": "building"}
|
|
192
|
+
log(f" Track progress: scios ag status --folder {target_folder}")
|
|
193
|
+
log(f" When ready: scios ag mount {idea_id} --folder {target_folder}")
|
|
194
|
+
return {"idea_id": idea_id, "folder": str(target_folder), "status": "building"}
|
|
169
195
|
|
|
170
196
|
log("⑤ Waiting for build-execute to finish …")
|
|
171
197
|
|
|
@@ -179,26 +205,51 @@ def create_and_build(
|
|
|
179
205
|
final = {"status": "unknown"}
|
|
180
206
|
log(f" build-execute {final.get('status')} (scios_score={final.get('scios_score')})")
|
|
181
207
|
|
|
182
|
-
log(f"⑥ Mounting → {
|
|
183
|
-
sync_core.mount(client, idea_id,
|
|
208
|
+
log(f"⑥ Mounting → {target_folder}")
|
|
209
|
+
sync_core.mount(client, idea_id, target_folder, log=log)
|
|
210
|
+
save(target_folder, m)
|
|
211
|
+
scaffold_mod.scaffold(target_folder, m, log=log)
|
|
184
212
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
idea_id=idea_id, endpoint=endpoint, token="",
|
|
188
|
-
execution=ExecutionConfig(mode="local", host_url=host),
|
|
189
|
-
)
|
|
190
|
-
m.budget.compute_scale = scale
|
|
191
|
-
m.budget.optimizer_iterations = budget_iterations
|
|
192
|
-
m.budget.max_wall_clock_min = max_wall_clock_min
|
|
193
|
-
save(target, m)
|
|
194
|
-
scaffold_mod.scaffold(target, m, log=log)
|
|
195
|
-
|
|
196
|
-
log(f"✨ Ready: {target}")
|
|
197
|
-
log(f" Open in Antigravity: antigravity {target}")
|
|
213
|
+
log(f"✨ Ready: {target_folder}")
|
|
214
|
+
log(f" Open in Antigravity: antigravity {target_folder}")
|
|
198
215
|
if launch:
|
|
199
|
-
_launch_editor(
|
|
200
|
-
|
|
201
|
-
return {"idea_id": idea_id, "folder": str(
|
|
216
|
+
_launch_editor(target_folder, log)
|
|
217
|
+
|
|
218
|
+
return {"idea_id": idea_id, "folder": str(target_folder), "status": "created"}
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def _write_idea_md(
|
|
222
|
+
folder: Path, *, idea_id: str, workspace_id: str, goal_id: str,
|
|
223
|
+
title: str, description: str, target_metrics: str | None,
|
|
224
|
+
methodology: str | None, constraints: str | None, host: str,
|
|
225
|
+
) -> None:
|
|
226
|
+
"""Write idea.md for the scientist to review before proceeding."""
|
|
227
|
+
lines = [
|
|
228
|
+
f"# {title}",
|
|
229
|
+
"",
|
|
230
|
+
f"**Idea ID:** `{idea_id}`",
|
|
231
|
+
f"**Workspace:** `{workspace_id}`",
|
|
232
|
+
f"**Goal:** `{goal_id}`",
|
|
233
|
+
f"**View on Scios:** [{host}/ideas/{idea_id}]({host}/ideas/{idea_id})",
|
|
234
|
+
"",
|
|
235
|
+
"## Description",
|
|
236
|
+
description or "(no description)",
|
|
237
|
+
]
|
|
238
|
+
if target_metrics:
|
|
239
|
+
lines += ["", "## Target Metrics", target_metrics]
|
|
240
|
+
if methodology:
|
|
241
|
+
lines += ["", "## Methodology", methodology]
|
|
242
|
+
if constraints:
|
|
243
|
+
lines += ["", "## Constraints", constraints]
|
|
244
|
+
lines += [
|
|
245
|
+
"",
|
|
246
|
+
"---",
|
|
247
|
+
"*Review this goal. When ready, tell the agent to proceed:*",
|
|
248
|
+
"- **\"run it\"** → kicks off the full build-execute pipeline",
|
|
249
|
+
"- **\"architect it\"** → step-by-step control (architect → convert → vibe → run)",
|
|
250
|
+
"- **\"status\"** → check current progress",
|
|
251
|
+
]
|
|
252
|
+
(folder / "idea.md").write_text("\n".join(lines) + "\n")
|
|
202
253
|
|
|
203
254
|
|
|
204
255
|
def _launch_editor(folder: Path, log: Callable[[str], None]) -> None:
|
|
@@ -159,7 +159,7 @@ def _run_node(
|
|
|
159
159
|
# Match the backend orchestrator's init_args EXACTLY (agent_orchestrator.py):
|
|
160
160
|
# only name + model. Passing the raw node `configuration` collides with fields
|
|
161
161
|
# the primitive __init__ already sets (e.g. `description`) → TypeError.
|
|
162
|
-
init_args = {"name": agent_name, "model": "gemini-3.
|
|
162
|
+
init_args = {"name": agent_name, "model": "gemini-3.6-flash"}
|
|
163
163
|
|
|
164
164
|
node_dir = work_dir / node_id
|
|
165
165
|
node_dir.mkdir(parents=True, exist_ok=True)
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
"""Antigravity Plugin — installs Scios as a global plugin.
|
|
2
|
+
|
|
3
|
+
Two install modes:
|
|
4
|
+
1. From repo: copies packages/scios-skills/ (the canonical plugin source)
|
|
5
|
+
to both ~/.gemini/config/plugins/scios/ (IDE) and
|
|
6
|
+
~/.gemini/antigravity-cli/plugins/scios/ (CLI).
|
|
7
|
+
2. From pip install (no repo): generates plugin files inline with the same
|
|
8
|
+
content.
|
|
9
|
+
|
|
10
|
+
Plugin layout:
|
|
11
|
+
~/.gemini/config/plugins/scios/
|
|
12
|
+
├── plugin.json
|
|
13
|
+
├── mcp_config.json (scios-core + scios-maxwell)
|
|
14
|
+
├── hooks.json (ruff format-on-save)
|
|
15
|
+
├── skills/
|
|
16
|
+
│ └── scios/
|
|
17
|
+
│ ├── SKILL.md
|
|
18
|
+
│ ├── AGENTS.md
|
|
19
|
+
│ ├── docs/
|
|
20
|
+
│ └── resources/
|
|
21
|
+
├── rules/
|
|
22
|
+
│ └── scios-conventions.md
|
|
23
|
+
└── sidecars/
|
|
24
|
+
├── scios-sync/
|
|
25
|
+
│ └── sidecar.json
|
|
26
|
+
└── scios-notifier/
|
|
27
|
+
├── sidecar.json
|
|
28
|
+
└── notify.sh
|
|
29
|
+
|
|
30
|
+
Sidecar config lives at ~/.gemini/config/config.json (user-controlled enable/disable).
|
|
31
|
+
"""
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import json
|
|
35
|
+
import shutil
|
|
36
|
+
from pathlib import Path
|
|
37
|
+
from typing import Callable
|
|
38
|
+
|
|
39
|
+
# Both Antigravity surfaces get the same plugin content
|
|
40
|
+
PLUGIN_DIRS = [
|
|
41
|
+
Path.home() / ".gemini" / "config" / "plugins" / "scios", # IDE
|
|
42
|
+
Path.home() / ".gemini" / "antigravity-cli" / "plugins" / "scios", # CLI
|
|
43
|
+
]
|
|
44
|
+
# Primary dir for backward compat with code that reads PLUGIN_DIR
|
|
45
|
+
PLUGIN_DIR = PLUGIN_DIRS[0]
|
|
46
|
+
CONFIG_FILE = Path.home() / ".gemini" / "config" / "config.json"
|
|
47
|
+
|
|
48
|
+
SCIOS_BIN = shutil.which("scios") or "scios"
|
|
49
|
+
|
|
50
|
+
# Items to skip when copying plugin source
|
|
51
|
+
_SKIP = {"node_modules", ".git", "bin", "package.json", "package-lock.json", ".npmignore", "README.md"}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def plugin_installed() -> bool:
|
|
55
|
+
"""Check if the global Antigravity plugin is installed."""
|
|
56
|
+
return (PLUGIN_DIR / "plugin.json").exists()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _find_plugin_source() -> Path | None:
|
|
60
|
+
"""Find the canonical plugin source in the repo."""
|
|
61
|
+
# Walk up from this file to find packages/scios-skills/
|
|
62
|
+
here = Path(__file__).resolve()
|
|
63
|
+
for parent in [here.parent.parent.parent.parent, here.parent.parent.parent.parent.parent]:
|
|
64
|
+
candidate = parent / "packages" / "scios-skills"
|
|
65
|
+
if (candidate / "plugin.json").exists():
|
|
66
|
+
return candidate
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _copy_tree(src: Path, dest: Path) -> None:
|
|
71
|
+
"""Recursively copy src to dest, skipping npm/git metadata."""
|
|
72
|
+
dest.mkdir(parents=True, exist_ok=True)
|
|
73
|
+
for item in src.iterdir():
|
|
74
|
+
if item.name in _SKIP:
|
|
75
|
+
continue
|
|
76
|
+
target = dest / item.name
|
|
77
|
+
if item.is_dir():
|
|
78
|
+
_copy_tree(item, target)
|
|
79
|
+
else:
|
|
80
|
+
target.write_bytes(item.read_bytes())
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def install_plugin(
|
|
84
|
+
*,
|
|
85
|
+
enable_notifier: bool = False,
|
|
86
|
+
log: Callable[[str], None] = print,
|
|
87
|
+
) -> None:
|
|
88
|
+
"""Install the Scios plugin to all Antigravity plugin directories."""
|
|
89
|
+
|
|
90
|
+
plugin_src = _find_plugin_source()
|
|
91
|
+
|
|
92
|
+
for plugin_dir in PLUGIN_DIRS:
|
|
93
|
+
# Clean old install to remove stale files from previous versions
|
|
94
|
+
if plugin_dir.exists():
|
|
95
|
+
shutil.rmtree(plugin_dir)
|
|
96
|
+
|
|
97
|
+
if plugin_src:
|
|
98
|
+
# Mode 1: Copy from repo source (canonical, always current)
|
|
99
|
+
_copy_tree(plugin_src, plugin_dir)
|
|
100
|
+
log(f" ✓ Copied plugin from repo → {plugin_dir}")
|
|
101
|
+
else:
|
|
102
|
+
# Mode 2: Generate inline (pip-installed CLI without repo)
|
|
103
|
+
_generate_plugin_inline(plugin_dir, log=log)
|
|
104
|
+
|
|
105
|
+
# Add sidecars (not in the npm package — they need absolute paths)
|
|
106
|
+
_install_sidecars(plugin_dir, log=log)
|
|
107
|
+
|
|
108
|
+
# Update config.json to enable sidecars
|
|
109
|
+
_update_config(enable_sync=True, enable_notifier=enable_notifier)
|
|
110
|
+
log(f" ✓ config.json (sync: enabled, notifier: {'enabled' if enable_notifier else 'disabled — use --enable-notifier'})")
|
|
111
|
+
|
|
112
|
+
log(f"\n✓ Scios plugin installed → {len(PLUGIN_DIRS)} location(s)")
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _generate_plugin_inline(plugin_dir: Path, *, log: Callable[[str], None] = print) -> None:
|
|
116
|
+
"""Generate plugin files from inline content (no repo available)."""
|
|
117
|
+
|
|
118
|
+
# ── plugin.json ──
|
|
119
|
+
_write_json(plugin_dir / "plugin.json", {
|
|
120
|
+
"$schema": "https://antigravity.google/schemas/v1/plugin.json",
|
|
121
|
+
"name": "scios",
|
|
122
|
+
"description": "Scios autonomous scientific research platform — create ideas, build multi-agent workflows, run experiments, optimize iteratively, and audit results. Powered by the Scios API.",
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
# ── mcp_config.json ──
|
|
126
|
+
_write_json(plugin_dir / "mcp_config.json", {
|
|
127
|
+
"mcpServers": {
|
|
128
|
+
"scios-core": {
|
|
129
|
+
"command": SCIOS_BIN,
|
|
130
|
+
"args": ["mcp", "core"],
|
|
131
|
+
"env": {},
|
|
132
|
+
},
|
|
133
|
+
"scios-maxwell": {
|
|
134
|
+
"command": SCIOS_BIN,
|
|
135
|
+
"args": ["mcp", "maxwell"],
|
|
136
|
+
"env": {},
|
|
137
|
+
},
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
log(" ✓ mcp_config.json (scios-core + scios-maxwell)")
|
|
141
|
+
|
|
142
|
+
# ── hooks.json ──
|
|
143
|
+
_write_json(plugin_dir / "hooks.json", {
|
|
144
|
+
"scios-auto-format": {
|
|
145
|
+
"PostToolUse": [
|
|
146
|
+
{
|
|
147
|
+
"matcher": "edit_file",
|
|
148
|
+
"hooks": [
|
|
149
|
+
{
|
|
150
|
+
"type": "command",
|
|
151
|
+
"command": "sh",
|
|
152
|
+
"args": ["-c", "command -v ruff >/dev/null 2>&1 && ruff format \"$ANTIGRAVITY_TOOL_ARG_TARGET_FILE\" 2>/dev/null || true"],
|
|
153
|
+
"timeout": 10,
|
|
154
|
+
"description": "Auto-format Python agent files with ruff after edits",
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
})
|
|
161
|
+
log(" ✓ hooks.json (ruff format-on-save)")
|
|
162
|
+
|
|
163
|
+
# ── skills/scios/SKILL.md ──
|
|
164
|
+
skill_dir = plugin_dir / "skills" / "scios"
|
|
165
|
+
skill_dir.mkdir(parents=True, exist_ok=True)
|
|
166
|
+
(skill_dir / "SKILL.md").write_text(_SKILL_MD)
|
|
167
|
+
log(" ✓ skills/scios/SKILL.md")
|
|
168
|
+
|
|
169
|
+
# ── rules/scios-conventions.md ──
|
|
170
|
+
rules_dir = plugin_dir / "rules"
|
|
171
|
+
rules_dir.mkdir(parents=True, exist_ok=True)
|
|
172
|
+
(rules_dir / "scios-conventions.md").write_text(_RULES)
|
|
173
|
+
log(" ✓ rules/scios-conventions.md")
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def _install_sidecars(plugin_dir: Path, *, log: Callable[[str], None] = print) -> None:
|
|
177
|
+
"""Install sidecar definitions (need absolute paths, can't be in npm package)."""
|
|
178
|
+
|
|
179
|
+
# ── sidecars/scios-sync/ ──
|
|
180
|
+
sync_dir = plugin_dir / "sidecars" / "scios-sync"
|
|
181
|
+
sync_dir.mkdir(parents=True, exist_ok=True)
|
|
182
|
+
_write_json(sync_dir / "sidecar.json", {
|
|
183
|
+
"description": "Auto-sync: watches agents/*.py and pushes edits to the Scios backend",
|
|
184
|
+
"display_name": "Scios Sync",
|
|
185
|
+
"command": SCIOS_BIN,
|
|
186
|
+
"args": ["ag", "sync"],
|
|
187
|
+
"restart_policy": "on-failure",
|
|
188
|
+
})
|
|
189
|
+
log(" ✓ sidecars/scios-sync (auto-sync agent code)")
|
|
190
|
+
|
|
191
|
+
# ── sidecars/scios-notifier/ ──
|
|
192
|
+
notifier_dir = plugin_dir / "sidecars" / "scios-notifier"
|
|
193
|
+
notifier_dir.mkdir(parents=True, exist_ok=True)
|
|
194
|
+
(notifier_dir / "notify.sh").write_text(_NOTIFIER_SCRIPT)
|
|
195
|
+
(notifier_dir / "notify.sh").chmod(0o755)
|
|
196
|
+
_write_json(notifier_dir / "sidecar.json", {
|
|
197
|
+
"description": "Polls build-execute status every 60s and notifies via agentapi when done",
|
|
198
|
+
"display_name": "Scios Notifier",
|
|
199
|
+
"builtin": "schedule",
|
|
200
|
+
"args": [
|
|
201
|
+
"*/1 * * * *",
|
|
202
|
+
"/bin/bash",
|
|
203
|
+
str(notifier_dir / "notify.sh"),
|
|
204
|
+
],
|
|
205
|
+
})
|
|
206
|
+
log(" ✓ sidecars/scios-notifier (status polling, opt-in)")
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def uninstall_plugin(*, log: Callable[[str], None] = print) -> None:
|
|
210
|
+
"""Remove the plugin from all directories and config entries."""
|
|
211
|
+
for plugin_dir in PLUGIN_DIRS:
|
|
212
|
+
if plugin_dir.exists():
|
|
213
|
+
shutil.rmtree(plugin_dir)
|
|
214
|
+
log(f"✓ Removed {plugin_dir}")
|
|
215
|
+
_update_config(remove=True)
|
|
216
|
+
log("✓ Removed sidecar config from config.json")
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def _update_config(
|
|
220
|
+
*,
|
|
221
|
+
enable_sync: bool = True,
|
|
222
|
+
enable_notifier: bool = False,
|
|
223
|
+
remove: bool = False,
|
|
224
|
+
) -> None:
|
|
225
|
+
"""Update ~/.gemini/config/config.json to enable/disable Scios sidecars."""
|
|
226
|
+
config: dict = {}
|
|
227
|
+
if CONFIG_FILE.exists():
|
|
228
|
+
try:
|
|
229
|
+
config = json.loads(CONFIG_FILE.read_text())
|
|
230
|
+
except (json.JSONDecodeError, OSError):
|
|
231
|
+
config = {}
|
|
232
|
+
|
|
233
|
+
sidecars = config.setdefault("sidecars", {})
|
|
234
|
+
|
|
235
|
+
if remove:
|
|
236
|
+
sidecars.pop("scios/scios-sync", None)
|
|
237
|
+
sidecars.pop("scios/scios-notifier", None)
|
|
238
|
+
else:
|
|
239
|
+
sidecars["scios/scios-sync"] = {"enabled": enable_sync}
|
|
240
|
+
sidecars["scios/scios-notifier"] = {"enabled": enable_notifier}
|
|
241
|
+
|
|
242
|
+
CONFIG_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
243
|
+
CONFIG_FILE.write_text(json.dumps(config, indent=2) + "\n")
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def _write_json(path: Path, data: dict) -> None:
|
|
247
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
248
|
+
path.write_text(json.dumps(data, indent=2) + "\n")
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
# ---------------------------------------------------------------------------
|
|
252
|
+
# Inlined content (used when repo source is not available)
|
|
253
|
+
# ---------------------------------------------------------------------------
|
|
254
|
+
|
|
255
|
+
_SKILL_MD = """\
|
|
256
|
+
---
|
|
257
|
+
name: scios
|
|
258
|
+
description: >
|
|
259
|
+
Drive the Scios autonomous scientific research platform. Use this skill
|
|
260
|
+
whenever the user asks to do research, run experiments, or explore scientific
|
|
261
|
+
questions. The skill runs a stage-by-stage pipeline: create idea → architect
|
|
262
|
+
→ convert to workflow → generate agent code → execute → explain scores →
|
|
263
|
+
optimize.
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
# Scios — Research Pipeline Skill
|
|
267
|
+
|
|
268
|
+
## Architecture
|
|
269
|
+
|
|
270
|
+
The skill delegates exclusively to the `scios` CLI for all backend interactions.
|
|
271
|
+
There are no fallback scripts — the CLI is the single source of truth.
|
|
272
|
+
|
|
273
|
+
Agents can also use the **scios-core** and **scios-maxwell** MCP tools bundled
|
|
274
|
+
with this plugin for structured tool-call interactions.
|
|
275
|
+
|
|
276
|
+
## Quick Start
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
scios ag go "Your research question here"
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Stage-by-Stage
|
|
283
|
+
|
|
284
|
+
| # | Command | Purpose |
|
|
285
|
+
|---|---------|---------|
|
|
286
|
+
| 1 | `scios ag create "<goal>"` | Create workspace + idea |
|
|
287
|
+
| 2 | `scios ag architect` | Refine hypothesis & methodology |
|
|
288
|
+
| 3 | `scios ag convert` | Build workflow DAG |
|
|
289
|
+
| 4 | `scios ag vibe` | Generate agent code |
|
|
290
|
+
| 5 | `scios ag run` | Execute workflow |
|
|
291
|
+
| 6 | `scios ag explain` | Scores, traces, failures |
|
|
292
|
+
| 7 | `scios ag optimize [-n N]` | Improve iteratively |
|
|
293
|
+
| 8 | `scios ag diff` | See what optimizer changed |
|
|
294
|
+
|
|
295
|
+
## Auth
|
|
296
|
+
|
|
297
|
+
1. `SCIOS_API_TOKEN` env var (first priority)
|
|
298
|
+
2. `~/.scios/credentials.json` (written by `scios login`)
|
|
299
|
+
|
|
300
|
+
## Hard Rules
|
|
301
|
+
|
|
302
|
+
- Run one stage, report, STOP. Never chain without user asking.
|
|
303
|
+
- Never present unaudited results — always show verified scores.
|
|
304
|
+
- If something fails, report root cause. No fallbacks, no retries.
|
|
305
|
+
"""
|
|
306
|
+
|
|
307
|
+
_RULES = """\
|
|
308
|
+
# Scios Workspace Conventions
|
|
309
|
+
|
|
310
|
+
This folder is a **Scios research workspace** projected from the Scios backend by
|
|
311
|
+
the `scios ag` CLI. Treat the backend DB as the single source of truth — these
|
|
312
|
+
files are a synced *view*.
|
|
313
|
+
|
|
314
|
+
## Folder map
|
|
315
|
+
- `agents/*.py` — vibed agent code. **Two-way synced**: editing a file pushes it
|
|
316
|
+
to the backend (via `scios ag push-code` or `scios ag sync`). The first line
|
|
317
|
+
`# AGENT_ID: <uuid>` is the sync key — **never delete or edit it**.
|
|
318
|
+
- `workflows/definition.json` — the workflow DAG (read-only projection).
|
|
319
|
+
- `execution/` — metrics.json, trace_summary.md, logs.json (read-only).
|
|
320
|
+
- `datasets/` — inline data, `.url` shortcuts (gs://), or `.metadata.json`.
|
|
321
|
+
- `dashboards/` — generated result dashboards (read-only).
|
|
322
|
+
- `scios.toml` — the only local-authoritative file (idea_id, endpoint, mode, budget).
|
|
323
|
+
|
|
324
|
+
## How to work here
|
|
325
|
+
- To change an agent's behaviour, edit its file in `agents/` and save.
|
|
326
|
+
Push with `scios ag push-code <file>` or use `scios ag sync` for auto-push.
|
|
327
|
+
- To run the workflow: `scios ag run` (mode from `scios.toml`).
|
|
328
|
+
- To check progress/scores: `scios ag status` or `scios ag explain`.
|
|
329
|
+
- Prefer the `scios-core` MCP tools (`scios_run`, `scios_status`, `scios_explain`)
|
|
330
|
+
and the `scios-maxwell` MCP assistant over shelling out manually.
|
|
331
|
+
|
|
332
|
+
## Hard rules
|
|
333
|
+
- Never edit files under `execution/`, `workflows/`, `datasets/`, `dashboards/`
|
|
334
|
+
by hand — they are overwritten on the next sync.
|
|
335
|
+
- Never remove the `# AGENT_ID:` header from an agent file.
|
|
336
|
+
- Do not invent new API endpoints; the CLI already wraps the backend.
|
|
337
|
+
- After editing agents, push code before running. After optimize, pull code before editing.
|
|
338
|
+
"""
|
|
339
|
+
|
|
340
|
+
_NOTIFIER_SCRIPT = """\
|
|
341
|
+
#!/usr/bin/env bash
|
|
342
|
+
# Scios status notifier — polls build-execute status, notifies via agentapi when done.
|
|
343
|
+
# Runs as a scheduled sidecar (every 60s). Writes state to $ANTIGRAVITY_EXECUTABLE_DATA_DIR.
|
|
344
|
+
|
|
345
|
+
set -euo pipefail
|
|
346
|
+
|
|
347
|
+
STATE_DIR="${ANTIGRAVITY_EXECUTABLE_DATA_DIR:-/tmp/scios-notifier}"
|
|
348
|
+
mkdir -p "$STATE_DIR"
|
|
349
|
+
LAST_STATUS_FILE="$STATE_DIR/last_status"
|
|
350
|
+
|
|
351
|
+
# Get current status (requires scios.toml in CWD or nearest parent)
|
|
352
|
+
STATUS_JSON=$(scios ag status 2>/dev/null | head -5 || true)
|
|
353
|
+
if [[ -z "$STATUS_JSON" ]]; then
|
|
354
|
+
exit 0 # No workspace mounted, nothing to do
|
|
355
|
+
fi
|
|
356
|
+
|
|
357
|
+
# Extract status and score
|
|
358
|
+
CURRENT_STATUS=$(echo "$STATUS_JSON" | grep -oP 'status:\\s*\\K\\S+' || echo "unknown")
|
|
359
|
+
SCORE=$(echo "$STATUS_JSON" | grep -oP 'scios_score:\\s*\\K\\S+' || echo "—")
|
|
360
|
+
LAST_STATUS=$(cat "$LAST_STATUS_FILE" 2>/dev/null || echo "unknown")
|
|
361
|
+
|
|
362
|
+
# Notify only on state transitions to terminal states
|
|
363
|
+
if [[ "$CURRENT_STATUS" != "$LAST_STATUS" ]]; then
|
|
364
|
+
echo "$CURRENT_STATUS" > "$LAST_STATUS_FILE"
|
|
365
|
+
if [[ "$CURRENT_STATUS" == "completed" ]]; then
|
|
366
|
+
agentapi new-conversation "✅ Scios execution completed — scios_score: $SCORE. Run \\`scios ag explain\\` for details." 2>/dev/null || true
|
|
367
|
+
elif [[ "$CURRENT_STATUS" == "failed" ]]; then
|
|
368
|
+
agentapi new-conversation "❌ Scios execution failed. Run \\`scios ag explain\\` to see what went wrong." 2>/dev/null || true
|
|
369
|
+
fi
|
|
370
|
+
fi
|
|
371
|
+
"""
|
|
@@ -301,16 +301,29 @@ def _write(path: Path, content: str, *, limit: int | None = None) -> None:
|
|
|
301
301
|
|
|
302
302
|
|
|
303
303
|
def scaffold(folder: Path, manifest: Manifest, *, log=print) -> None:
|
|
304
|
-
"""(Re)write all Antigravity + VS Code integration files into `folder`.
|
|
304
|
+
"""(Re)write all Antigravity + VS Code integration files into `folder`.
|
|
305
|
+
|
|
306
|
+
If the global Antigravity plugin is installed (~/.gemini/config/plugins/scios/),
|
|
307
|
+
skip the .agents/ MCP config, rules, skills, and hooks — the plugin provides
|
|
308
|
+
those globally. Only write workspace-specific files (workflows + .vscode).
|
|
309
|
+
"""
|
|
310
|
+
from scios_cli.ag.plugin import plugin_installed
|
|
311
|
+
|
|
305
312
|
agents_dir = folder / ".agents"
|
|
313
|
+
has_global_plugin = plugin_installed()
|
|
314
|
+
|
|
315
|
+
if has_global_plugin:
|
|
316
|
+
log(" ℹ Global Antigravity plugin detected — skipping .agents/ MCP/rules/skills (provided by plugin)")
|
|
317
|
+
else:
|
|
318
|
+
_write(agents_dir / "mcp_config.json", json.dumps(_mcp_config(manifest), indent=2))
|
|
319
|
+
_write(agents_dir / "rules" / "scios.md", _RULES, limit=CHAR_LIMIT)
|
|
320
|
+
_write(agents_dir / "skills" / "scios-workflow" / "SKILL.md", _SKILL)
|
|
321
|
+
_write(agents_dir / "hooks.json", json.dumps(_hooks(), indent=2))
|
|
306
322
|
|
|
307
|
-
|
|
308
|
-
_write(agents_dir / "rules" / "scios.md", _RULES, limit=CHAR_LIMIT)
|
|
309
|
-
_write(agents_dir / "skills" / "scios-workflow" / "SKILL.md", _SKILL)
|
|
323
|
+
# Workflows are always workspace-specific (they reference workspace commands)
|
|
310
324
|
_write(agents_dir / "workflows" / "scios-run.md", _WF_RUN, limit=CHAR_LIMIT)
|
|
311
325
|
_write(agents_dir / "workflows" / "scios-optimize.md", _WF_OPTIMIZE, limit=CHAR_LIMIT)
|
|
312
326
|
_write(agents_dir / "workflows" / "scios-explain.md", _WF_EXPLAIN, limit=CHAR_LIMIT)
|
|
313
|
-
_write(agents_dir / "hooks.json", json.dumps(_hooks(), indent=2))
|
|
314
327
|
|
|
315
328
|
import shutil
|
|
316
329
|
|