scios-cli 0.3.2__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.2 → scios_cli-0.4.0}/PKG-INFO +1 -1
- {scios_cli-0.3.2 → scios_cli-0.4.0}/pyproject.toml +1 -1
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/ag/create_flow.py +97 -46
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/ag/plugin.py +169 -81
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/ag.py +9 -2
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/run.py +49 -17
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/setup.py +9 -6
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli.egg-info/PKG-INFO +1 -1
- {scios_cli-0.3.2 → scios_cli-0.4.0}/LICENSE +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/README.md +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/__init__.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/__main__.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/ag/__init__.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/ag/api_client.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/ag/dashboards.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/ag/local_runner.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/ag/manifest.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/ag/scaffold.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/ag/sync_core.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/app.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/auth_store.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/__init__.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/agent.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/bench.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/chat.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/db.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/deploy.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/export.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/houdini.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/langfuse.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/login.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/logs.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/profile.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/sync.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/train.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/trust.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/video.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/commands/workspace.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/config.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/houdini.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/houdini_recorder.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/install.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/main.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/mcp/__init__.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/mcp/server_core.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli/mcp/server_maxwell.py +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli.egg-info/SOURCES.txt +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli.egg-info/dependency_links.txt +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli.egg-info/entry_points.txt +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli.egg-info/requires.txt +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/scios_cli.egg-info/top_level.txt +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/setup.cfg +0 -0
- {scios_cli-0.3.2 → scios_cli-0.4.0}/setup.py +0 -0
- {scios_cli-0.3.2 → 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:
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
"""Antigravity Plugin — installs Scios as a global plugin
|
|
1
|
+
"""Antigravity Plugin — installs Scios as a global plugin.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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.
|
|
6
9
|
|
|
7
10
|
Plugin layout:
|
|
8
11
|
~/.gemini/config/plugins/scios/
|
|
@@ -10,14 +13,16 @@ Plugin layout:
|
|
|
10
13
|
├── mcp_config.json (scios-core + scios-maxwell)
|
|
11
14
|
├── hooks.json (ruff format-on-save)
|
|
12
15
|
├── skills/
|
|
13
|
-
│ └── scios
|
|
14
|
-
│
|
|
16
|
+
│ └── scios/
|
|
17
|
+
│ ├── SKILL.md
|
|
18
|
+
│ ├── AGENTS.md
|
|
19
|
+
│ ├── docs/
|
|
20
|
+
│ └── resources/
|
|
15
21
|
├── rules/
|
|
16
|
-
│ └── scios.md
|
|
22
|
+
│ └── scios-conventions.md
|
|
17
23
|
└── sidecars/
|
|
18
24
|
├── scios-sync/
|
|
19
|
-
│
|
|
20
|
-
│ └── sync.sh
|
|
25
|
+
│ └── sidecar.json
|
|
21
26
|
└── scios-notifier/
|
|
22
27
|
├── sidecar.json
|
|
23
28
|
└── notify.sh
|
|
@@ -31,42 +36,103 @@ import shutil
|
|
|
31
36
|
from pathlib import Path
|
|
32
37
|
from typing import Callable
|
|
33
38
|
|
|
34
|
-
|
|
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]
|
|
35
46
|
CONFIG_FILE = Path.home() / ".gemini" / "config" / "config.json"
|
|
36
47
|
|
|
37
48
|
SCIOS_BIN = shutil.which("scios") or "scios"
|
|
38
49
|
|
|
50
|
+
# Items to skip when copying plugin source
|
|
51
|
+
_SKIP = {"node_modules", ".git", "bin", "package.json", "package-lock.json", ".npmignore", "README.md"}
|
|
52
|
+
|
|
39
53
|
|
|
40
54
|
def plugin_installed() -> bool:
|
|
41
55
|
"""Check if the global Antigravity plugin is installed."""
|
|
42
56
|
return (PLUGIN_DIR / "plugin.json").exists()
|
|
43
57
|
|
|
44
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
|
+
|
|
45
83
|
def install_plugin(
|
|
46
84
|
*,
|
|
47
85
|
enable_notifier: bool = False,
|
|
48
86
|
log: Callable[[str], None] = print,
|
|
49
87
|
) -> None:
|
|
50
|
-
"""
|
|
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)."""
|
|
51
117
|
|
|
52
118
|
# ── plugin.json ──
|
|
53
|
-
_write_json(
|
|
119
|
+
_write_json(plugin_dir / "plugin.json", {
|
|
120
|
+
"$schema": "https://antigravity.google/schemas/v1/plugin.json",
|
|
54
121
|
"name": "scios",
|
|
55
|
-
"
|
|
56
|
-
"description": "Drive autonomous scientific research — stage-by-stage pipeline, MCP tools, Maxwell assistant.",
|
|
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.",
|
|
57
123
|
})
|
|
58
124
|
|
|
59
125
|
# ── mcp_config.json ──
|
|
60
|
-
_write_json(
|
|
126
|
+
_write_json(plugin_dir / "mcp_config.json", {
|
|
61
127
|
"mcpServers": {
|
|
62
128
|
"scios-core": {
|
|
63
129
|
"command": SCIOS_BIN,
|
|
64
|
-
"args": ["
|
|
130
|
+
"args": ["mcp", "core"],
|
|
65
131
|
"env": {},
|
|
66
132
|
},
|
|
67
133
|
"scios-maxwell": {
|
|
68
134
|
"command": SCIOS_BIN,
|
|
69
|
-
"args": ["
|
|
135
|
+
"args": ["mcp", "maxwell"],
|
|
70
136
|
"env": {},
|
|
71
137
|
},
|
|
72
138
|
}
|
|
@@ -74,32 +140,44 @@ def install_plugin(
|
|
|
74
140
|
log(" ✓ mcp_config.json (scios-core + scios-maxwell)")
|
|
75
141
|
|
|
76
142
|
# ── hooks.json ──
|
|
77
|
-
_write_json(
|
|
78
|
-
"
|
|
79
|
-
"
|
|
143
|
+
_write_json(plugin_dir / "hooks.json", {
|
|
144
|
+
"scios-auto-format": {
|
|
145
|
+
"PostToolUse": [
|
|
80
146
|
{
|
|
81
|
-
"
|
|
82
|
-
"
|
|
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
|
+
]
|
|
83
157
|
}
|
|
84
158
|
]
|
|
85
159
|
}
|
|
86
160
|
})
|
|
87
161
|
log(" ✓ hooks.json (ruff format-on-save)")
|
|
88
162
|
|
|
89
|
-
# ── skills/scios
|
|
90
|
-
skill_dir =
|
|
163
|
+
# ── skills/scios/SKILL.md ──
|
|
164
|
+
skill_dir = plugin_dir / "skills" / "scios"
|
|
91
165
|
skill_dir.mkdir(parents=True, exist_ok=True)
|
|
92
|
-
(skill_dir / "SKILL.md").write_text(
|
|
93
|
-
log(" ✓ skills/scios
|
|
166
|
+
(skill_dir / "SKILL.md").write_text(_SKILL_MD)
|
|
167
|
+
log(" ✓ skills/scios/SKILL.md")
|
|
94
168
|
|
|
95
|
-
# ── rules/scios.md ──
|
|
96
|
-
rules_dir =
|
|
169
|
+
# ── rules/scios-conventions.md ──
|
|
170
|
+
rules_dir = plugin_dir / "rules"
|
|
97
171
|
rules_dir.mkdir(parents=True, exist_ok=True)
|
|
98
|
-
(rules_dir / "scios.md").write_text(_RULES)
|
|
99
|
-
log(" ✓ rules/scios.md")
|
|
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)."""
|
|
100
178
|
|
|
101
179
|
# ── sidecars/scios-sync/ ──
|
|
102
|
-
sync_dir =
|
|
180
|
+
sync_dir = plugin_dir / "sidecars" / "scios-sync"
|
|
103
181
|
sync_dir.mkdir(parents=True, exist_ok=True)
|
|
104
182
|
_write_json(sync_dir / "sidecar.json", {
|
|
105
183
|
"description": "Auto-sync: watches agents/*.py and pushes edits to the Scios backend",
|
|
@@ -111,7 +189,7 @@ def install_plugin(
|
|
|
111
189
|
log(" ✓ sidecars/scios-sync (auto-sync agent code)")
|
|
112
190
|
|
|
113
191
|
# ── sidecars/scios-notifier/ ──
|
|
114
|
-
notifier_dir =
|
|
192
|
+
notifier_dir = plugin_dir / "sidecars" / "scios-notifier"
|
|
115
193
|
notifier_dir.mkdir(parents=True, exist_ok=True)
|
|
116
194
|
(notifier_dir / "notify.sh").write_text(_NOTIFIER_SCRIPT)
|
|
117
195
|
(notifier_dir / "notify.sh").chmod(0o755)
|
|
@@ -127,18 +205,13 @@ def install_plugin(
|
|
|
127
205
|
})
|
|
128
206
|
log(" ✓ sidecars/scios-notifier (status polling, opt-in)")
|
|
129
207
|
|
|
130
|
-
# ── config.json (enable sidecars) ──
|
|
131
|
-
_update_config(enable_sync=True, enable_notifier=enable_notifier)
|
|
132
|
-
log(f" ✓ config.json (sync: enabled, notifier: {'enabled' if enable_notifier else 'disabled — use --enable-notifier'})")
|
|
133
|
-
|
|
134
|
-
log(f"\n✓ Scios plugin installed → {PLUGIN_DIR}")
|
|
135
|
-
|
|
136
208
|
|
|
137
209
|
def uninstall_plugin(*, log: Callable[[str], None] = print) -> None:
|
|
138
|
-
"""Remove the plugin
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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}")
|
|
142
215
|
_update_config(remove=True)
|
|
143
216
|
log("✓ Removed sidecar config from config.json")
|
|
144
217
|
|
|
@@ -176,48 +249,62 @@ def _write_json(path: Path, data: dict) -> None:
|
|
|
176
249
|
|
|
177
250
|
|
|
178
251
|
# ---------------------------------------------------------------------------
|
|
179
|
-
# Inlined content (
|
|
252
|
+
# Inlined content (used when repo source is not available)
|
|
180
253
|
# ---------------------------------------------------------------------------
|
|
181
254
|
|
|
182
|
-
|
|
255
|
+
_SKILL_MD = """\
|
|
183
256
|
---
|
|
184
|
-
name: scios
|
|
185
|
-
description:
|
|
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.
|
|
186
264
|
---
|
|
187
265
|
|
|
188
|
-
# Scios
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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.
|
|
214
305
|
"""
|
|
215
306
|
|
|
216
307
|
_RULES = """\
|
|
217
|
-
---
|
|
218
|
-
trigger: always_on
|
|
219
|
-
---
|
|
220
|
-
|
|
221
308
|
# Scios Workspace Conventions
|
|
222
309
|
|
|
223
310
|
This folder is a **Scios research workspace** projected from the Scios backend by
|
|
@@ -226,7 +313,7 @@ files are a synced *view*.
|
|
|
226
313
|
|
|
227
314
|
## Folder map
|
|
228
315
|
- `agents/*.py` — vibed agent code. **Two-way synced**: editing a file pushes it
|
|
229
|
-
to the backend (via
|
|
316
|
+
to the backend (via `scios ag push-code` or `scios ag sync`). The first line
|
|
230
317
|
`# AGENT_ID: <uuid>` is the sync key — **never delete or edit it**.
|
|
231
318
|
- `workflows/definition.json` — the workflow DAG (read-only projection).
|
|
232
319
|
- `execution/` — metrics.json, trace_summary.md, logs.json (read-only).
|
|
@@ -235,18 +322,19 @@ files are a synced *view*.
|
|
|
235
322
|
- `scios.toml` — the only local-authoritative file (idea_id, endpoint, mode, budget).
|
|
236
323
|
|
|
237
324
|
## How to work here
|
|
238
|
-
- To change an agent's behaviour, edit its file in `agents/` and save.
|
|
239
|
-
|
|
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.
|
|
240
327
|
- To run the workflow: `scios ag run` (mode from `scios.toml`).
|
|
241
328
|
- To check progress/scores: `scios ag status` or `scios ag explain`.
|
|
242
|
-
- Prefer the `scios-core` MCP tools (`scios_run`, `scios_status`, `
|
|
243
|
-
|
|
329
|
+
- Prefer the `scios-core` MCP tools (`scios_run`, `scios_status`, `scios_explain`)
|
|
330
|
+
and the `scios-maxwell` MCP assistant over shelling out manually.
|
|
244
331
|
|
|
245
332
|
## Hard rules
|
|
246
333
|
- Never edit files under `execution/`, `workflows/`, `datasets/`, `dashboards/`
|
|
247
334
|
by hand — they are overwritten on the next sync.
|
|
248
335
|
- Never remove the `# AGENT_ID:` header from an agent file.
|
|
249
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.
|
|
250
338
|
"""
|
|
251
339
|
|
|
252
340
|
_NOTIFIER_SCRIPT = """\
|
|
@@ -287,16 +287,22 @@ def create(
|
|
|
287
287
|
scale: str = typer.Option("small", "--scale", help="compute_scale: small|medium|large"),
|
|
288
288
|
budget_iterations: int = typer.Option(3, "--budget-iterations", help="Optimizer iterations"),
|
|
289
289
|
max_wall_clock_min: int = typer.Option(60, "--max-wall-clock-min", help="Wall-clock budget (minutes)"),
|
|
290
|
-
wait: bool = typer.Option(
|
|
290
|
+
wait: bool = typer.Option(False, "--wait/--no-wait", help="Wait for build-execute to finish, then mount (default: no-wait)"),
|
|
291
291
|
launch: bool = typer.Option(False, "--launch/--no-launch", help="Open the folder when done"),
|
|
292
292
|
):
|
|
293
|
-
"""Create a workspace+goal+idea
|
|
293
|
+
"""Create a workspace+goal+idea. Does NOT kick off build-execute by default.
|
|
294
|
+
|
|
295
|
+
The scientist reviews the refined goal (idea.md) before deciding to proceed.
|
|
296
|
+
Use `scios ag run` to kick off build-execute after review.
|
|
297
|
+
Use `scios ag go` for the full pipeline in one shot.
|
|
298
|
+
"""
|
|
294
299
|
from scios_cli.ag.create_flow import create_and_build
|
|
295
300
|
|
|
296
301
|
create_and_build(
|
|
297
302
|
goal=goal, folder=folder, endpoint=endpoint, token=_resolve_token(token),
|
|
298
303
|
scale=scale, budget_iterations=budget_iterations,
|
|
299
304
|
max_wall_clock_min=max_wall_clock_min, wait=wait, launch=launch,
|
|
305
|
+
build=False,
|
|
300
306
|
log=lambda x: console.print(x),
|
|
301
307
|
)
|
|
302
308
|
|
|
@@ -759,6 +765,7 @@ def go(
|
|
|
759
765
|
token=_resolve_token(token),
|
|
760
766
|
scale=scale, budget_iterations=budget_iterations,
|
|
761
767
|
max_wall_clock_min=max_wall_clock_min, wait=True, launch=False,
|
|
768
|
+
build=True,
|
|
762
769
|
log=lambda x: console.print(x),
|
|
763
770
|
)
|
|
764
771
|
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
import os
|
|
5
|
+
from pathlib import Path
|
|
5
6
|
import secrets
|
|
7
|
+
import shutil
|
|
6
8
|
import subprocess
|
|
7
9
|
|
|
8
10
|
import typer
|
|
@@ -309,36 +311,64 @@ def _get_lsb_codename() -> str:
|
|
|
309
311
|
return r.stdout.strip() if r.returncode == 0 else "rodete"
|
|
310
312
|
|
|
311
313
|
|
|
314
|
+
def _is_glinux() -> bool:
|
|
315
|
+
"""Check if running on gLinux (Rodete/Debian-derived Google desktop OS)."""
|
|
316
|
+
if os.path.exists("/etc/glinux") or os.path.exists("/etc/glinux_version"):
|
|
317
|
+
return True
|
|
318
|
+
if shutil.which("glinux-add-repo") or os.path.exists("/usr/sbin/glinux-add-repo") or os.path.exists("/usr/bin/glinux-add-repo"):
|
|
319
|
+
return True
|
|
320
|
+
try:
|
|
321
|
+
if os.path.exists("/etc/os-release"):
|
|
322
|
+
content = Path("/etc/os-release").read_text()
|
|
323
|
+
if "go/glinux" in content or "glinux" in content.lower():
|
|
324
|
+
return True
|
|
325
|
+
if os.path.exists("/etc/lsb-release"):
|
|
326
|
+
content = Path("/etc/lsb-release").read_text()
|
|
327
|
+
if "GOOGLE_ID=Goobuntu" in content or "GOOGLE_CODENAME=" in content:
|
|
328
|
+
return True
|
|
329
|
+
except Exception:
|
|
330
|
+
pass
|
|
331
|
+
return False
|
|
332
|
+
|
|
333
|
+
|
|
312
334
|
def _ensure_docker_access() -> None:
|
|
313
335
|
"""Check that the current user can access Docker without sudo.
|
|
314
336
|
|
|
315
|
-
If Docker is not installed on gLinux, offers to install it.
|
|
316
|
-
If the docker socket is not accessible, guides the user to fix
|
|
337
|
+
If Docker is not installed or not working on gLinux, offers to install/configure it.
|
|
338
|
+
If the docker socket is not accessible, guides the user to fix permissions.
|
|
317
339
|
"""
|
|
318
|
-
|
|
319
|
-
r = subprocess.run(["docker", "info"], capture_output=True, text=True)
|
|
320
|
-
if r.returncode == 0:
|
|
321
|
-
return # Docker is accessible
|
|
340
|
+
is_glinux = _is_glinux()
|
|
322
341
|
|
|
323
|
-
|
|
324
|
-
|
|
342
|
+
# Check if docker binary exists on PATH
|
|
343
|
+
if not shutil.which("docker"):
|
|
344
|
+
if is_glinux:
|
|
345
|
+
_install_docker_glinux()
|
|
346
|
+
else:
|
|
347
|
+
console.print("[error]Docker is not installed or not in PATH.[/error]")
|
|
348
|
+
console.print("[muted]Install Docker: https://docs.docker.com/engine/install/[/muted]")
|
|
349
|
+
raise typer.Exit(1)
|
|
325
350
|
|
|
326
|
-
#
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
if daemon_missing:
|
|
351
|
+
# Check if docker daemon is reachable
|
|
352
|
+
try:
|
|
353
|
+
r = subprocess.run(["docker", "info"], capture_output=True, text=True)
|
|
354
|
+
except FileNotFoundError:
|
|
331
355
|
if is_glinux:
|
|
332
356
|
_install_docker_glinux()
|
|
333
357
|
else:
|
|
334
|
-
console.print("[error]Docker
|
|
358
|
+
console.print("[error]Docker is not installed or not in PATH.[/error]")
|
|
335
359
|
console.print("[muted]Install Docker: https://docs.docker.com/engine/install/[/muted]")
|
|
336
360
|
raise typer.Exit(1)
|
|
337
361
|
|
|
362
|
+
if r.returncode == 0:
|
|
363
|
+
return # Docker is accessible
|
|
364
|
+
|
|
365
|
+
stderr = (r.stderr or "").lower()
|
|
366
|
+
|
|
367
|
+
# Check for permission denied error
|
|
338
368
|
if "permission denied" in stderr:
|
|
339
|
-
# Check if user is configured in docker group (even if shell hasn't refreshed)
|
|
340
369
|
import getpass
|
|
341
370
|
import grp
|
|
371
|
+
|
|
342
372
|
username = getpass.getuser()
|
|
343
373
|
try:
|
|
344
374
|
docker_group = grp.getgrnam("docker")
|
|
@@ -347,7 +377,6 @@ def _ensure_docker_access() -> None:
|
|
|
347
377
|
in_group_configured = False
|
|
348
378
|
|
|
349
379
|
if in_group_configured:
|
|
350
|
-
# User is in docker group but current shell session hasn't picked it up
|
|
351
380
|
console.print("[warning]⚠ Docker permission denied — your shell hasn't picked up the 'docker' group yet.[/warning]")
|
|
352
381
|
console.print()
|
|
353
382
|
console.print(" Run one of these to fix it:")
|
|
@@ -366,7 +395,10 @@ def _ensure_docker_access() -> None:
|
|
|
366
395
|
|
|
367
396
|
raise typer.Exit(1)
|
|
368
397
|
|
|
369
|
-
#
|
|
398
|
+
# If docker info failed for any other reason on gLinux (daemon stopped, socket missing, etc.)
|
|
399
|
+
if is_glinux:
|
|
400
|
+
_install_docker_glinux()
|
|
401
|
+
|
|
370
402
|
console.print(f"[error]Docker is not available: {r.stderr.strip()}[/error]")
|
|
371
403
|
console.print("[muted]Check Docker installation — see go/installdocker[/muted]")
|
|
372
404
|
raise typer.Exit(1)
|
|
@@ -101,21 +101,22 @@ _SKILL_TARGETS = None # lazy
|
|
|
101
101
|
|
|
102
102
|
|
|
103
103
|
def _get_skill_targets():
|
|
104
|
-
"""Global agent skill directories."""
|
|
104
|
+
"""Global agent skill directories (non-Antigravity platforms)."""
|
|
105
105
|
global _SKILL_TARGETS
|
|
106
106
|
if _SKILL_TARGETS is None:
|
|
107
107
|
from pathlib import Path
|
|
108
108
|
home = Path.home()
|
|
109
109
|
_SKILL_TARGETS = [
|
|
110
|
-
("
|
|
111
|
-
("Claude Code",
|
|
112
|
-
("OpenCode",
|
|
110
|
+
("Cline / Roo", home / ".agents" / "skills" / "scios"),
|
|
111
|
+
("Claude Code", home / ".claude" / "skills" / "scios"),
|
|
112
|
+
("OpenCode", home / ".config" / "opencode" / "skills" / "scios"),
|
|
113
113
|
]
|
|
114
114
|
return _SKILL_TARGETS
|
|
115
115
|
|
|
116
116
|
|
|
117
117
|
def _find_skill_source():
|
|
118
118
|
"""Find skill source directory (repo or None)."""
|
|
119
|
+
# The canonical source is packages/scios-skills/skills/scios/
|
|
119
120
|
for candidate in [
|
|
120
121
|
REPO_ROOT / "packages" / "scios-skills" / "skills" / "scios",
|
|
121
122
|
REPO_ROOT / ".agents" / "skills" / "scios",
|
|
@@ -126,10 +127,12 @@ def _find_skill_source():
|
|
|
126
127
|
|
|
127
128
|
|
|
128
129
|
def ensure_skill_updated(*, quiet: bool = False) -> bool:
|
|
129
|
-
"""Ensure the global scios skill is installed
|
|
130
|
+
"""Ensure the global scios skill is installed to non-Antigravity agent platforms.
|
|
130
131
|
|
|
131
|
-
|
|
132
|
+
For Antigravity, the plugin install (ensure_plugin_updated) handles everything.
|
|
133
|
+
This function handles Cline, Claude Code, OpenCode etc. which only read SKILL.md.
|
|
132
134
|
|
|
135
|
+
Called automatically after `scios login` and available via `scios setup skill`.
|
|
133
136
|
Returns True if the skill was installed/updated, False if skipped.
|
|
134
137
|
"""
|
|
135
138
|
targets = _get_skill_targets()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|