silicon-cli 1.0.9__tar.gz → 1.0.12__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.
- {silicon_cli-1.0.9/silicon_cli.egg-info → silicon_cli-1.0.12}/PKG-INFO +121 -14
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/README.md +118 -12
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/pyproject.toml +1 -1
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/silicon_cli/__init__.py +1 -1
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/silicon_cli/cli.py +70 -7
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/silicon_cli/config.py +27 -4
- silicon_cli-1.0.12/silicon_cli/docker_runtime.py +831 -0
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/silicon_cli/glassagent.py +1 -1
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/silicon_cli/process.py +18 -2
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/silicon_cli/registry.py +67 -5
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/silicon_cli/stemcell.py +68 -10
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/silicon_cli/sync.py +163 -13
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/silicon_cli/update.py +35 -4
- {silicon_cli-1.0.9 → silicon_cli-1.0.12/silicon_cli.egg-info}/PKG-INFO +121 -14
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/silicon_cli.egg-info/SOURCES.txt +3 -1
- silicon_cli-1.0.12/tests/test_docker_runtime.py +300 -0
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/LICENSE +0 -0
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/setup.cfg +0 -0
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/silicon_cli/interface_cli.py +0 -0
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/silicon_cli/ui.py +0 -0
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/silicon_cli.egg-info/dependency_links.txt +0 -0
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/silicon_cli.egg-info/entry_points.txt +0 -0
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/silicon_cli.egg-info/requires.txt +0 -0
- {silicon_cli-1.0.9 → silicon_cli-1.0.12}/silicon_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: silicon-cli
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.12
|
|
4
4
|
Summary: Silicon CLI — create, run, and manage your silicon instances.
|
|
5
5
|
Author: Saket
|
|
6
6
|
Project-URL: Homepage, https://github.com/saket1225/silicon-cli
|
|
@@ -13,6 +13,7 @@ Requires-Python: >=3.9
|
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
15
|
Requires-Dist: certifi>=2024.2.2
|
|
16
|
+
Dynamic: license-file
|
|
16
17
|
|
|
17
18
|
# silicon-cli
|
|
18
19
|
|
|
@@ -21,7 +22,7 @@ package is named `silicon-cli`, and the code lives here in this `silicon-cli`
|
|
|
21
22
|
repo.
|
|
22
23
|
|
|
23
24
|
The command manages silicon instances on a machine: create them from the
|
|
24
|
-
[silicon-stemcell](https://github.com/
|
|
25
|
+
[silicon-stemcell](https://github.com/teamofsilicons/silicon-stemcell) base,
|
|
25
26
|
start/stop them under an auto-restart watchdog, stream logs, and back them up to
|
|
26
27
|
Glass. It reads the same `~/.silicon/registry.json`, so existing installs carry
|
|
27
28
|
over unchanged.
|
|
@@ -46,6 +47,8 @@ silicon restart <target> Restart silicon(s). target = name, *, all, 1,2,4, o
|
|
|
46
47
|
silicon agent <start|stop|status> [name] Manage the per-silicon glass agent
|
|
47
48
|
silicon status [name] Show instance status
|
|
48
49
|
silicon browser [name] Open a headed browser for login
|
|
50
|
+
silicon browser-profile setup <token> Create a Steel browser profile through Glass
|
|
51
|
+
silicon browser-profile finish <token> <session_id> [before_ids_csv] Finish profile setup
|
|
49
52
|
silicon debug [name] Tail a running instance's logs
|
|
50
53
|
silicon attach [path] Register an existing silicon directory
|
|
51
54
|
silicon pull [api_token] Pull a Glass team or silicon into local folders
|
|
@@ -53,6 +56,14 @@ silicon push [name] [now|stop] Daily 23:59 GMT backups to Glass (now = one-sho
|
|
|
53
56
|
silicon backup [name] [now|stop] Alias for silicon push
|
|
54
57
|
silicon update <target> Update silicon(s) from the latest stemcell
|
|
55
58
|
silicon list List all instances
|
|
59
|
+
silicon docker init [--root ~/silicons] [--image teamofsilicons/silicon-runtime:latest]
|
|
60
|
+
Install/check Docker and enable one-container-per-Silicon runtime
|
|
61
|
+
silicon docker doctor Check/repair Docker runtime setup
|
|
62
|
+
silicon docker login [claude|codex|all]
|
|
63
|
+
Set up shared Claude/Codex auth for Docker silicons
|
|
64
|
+
silicon docker compose Print generated Compose file path
|
|
65
|
+
silicon claude [args...] Run Claude Code with shared Docker auth
|
|
66
|
+
silicon codex [args...] Run Codex with shared Docker auth
|
|
56
67
|
silicon script update Update this CLI itself
|
|
57
68
|
silicon help Show help
|
|
58
69
|
```
|
|
@@ -63,21 +74,117 @@ silicon help Show help
|
|
|
63
74
|
| --- | --- | --- |
|
|
64
75
|
| `SILICON_HOME` | `~/.silicon` | registry + CLI state |
|
|
65
76
|
| `GLASS_SERVER_URL` | `https://glass.teamofsilicons.com` | Glass sync server (pull/push) |
|
|
66
|
-
| `SILICON_STEMCELL_REPO` | `
|
|
67
|
-
| `SILICON_GLASS_CLI_REPO` | `
|
|
77
|
+
| `SILICON_STEMCELL_REPO` | `teamofsilicons/silicon-stemcell` | base for `new` |
|
|
78
|
+
| `SILICON_GLASS_CLI_REPO` | `teamofsilicons/glass` | glass backup CLI |
|
|
68
79
|
| `SILICON_PYTHON` | `python3` | interpreter used to run a silicon's `main.py` |
|
|
69
80
|
| `SILICON_INTERFACE_CLI_PACKAGE` | `@teamofsilicons/silicon-interface-cli` | npm package used to install the Silicon Interface CLI |
|
|
70
81
|
| `SILICON_INTERFACE_CLI_TARBALL` | versioned npm tarball | fallback package URL if registry metadata is briefly unavailable |
|
|
71
82
|
| `SILICON_INTERFACE_CLI_SOURCE` | *(empty)* | local package dir or `silicon-interface.mjs` path for dev installs |
|
|
72
83
|
| `SILICON_INTERFACE_CLI_SKIP` | *(empty)* | set to `1` to skip interface CLI setup |
|
|
73
84
|
| `SILICON_INTERFACE_DAEMON_SKIP` | *(empty)* | set to `1` to install the CLI without starting its listener daemon |
|
|
85
|
+
| `SILICON_RUNTIME` | *(empty)* | default pull uses Docker; set to `local` to opt out |
|
|
86
|
+
| `SILICON_RUNTIME_IMAGE` | `teamofsilicons/silicon-runtime:latest` | runtime image for Docker-backed silicons |
|
|
87
|
+
| `SILICON_DOCKER_ROOT` | `~/silicons` | Docker-backed instance root |
|
|
88
|
+
| `SILICON_DOCKER_COMPOSE` | `<root>/compose.yml` | generated Compose file path |
|
|
89
|
+
| `SILICON_DOCKER_SHARED_HOME` | `<root>/.shared-home` | VM-wide Claude/Codex auth home mounted into every container |
|
|
90
|
+
| `SILICON_DOCKER_SUDO` | *(empty)* | set to `1` to run Docker commands through `sudo docker` |
|
|
91
|
+
| `SILICON_DOCKER_AUTO_INSTALL` | *(empty)* | set to `1` to allow non-interactive Docker install attempts |
|
|
92
|
+
|
|
93
|
+
## Docker runtime
|
|
94
|
+
|
|
95
|
+
Docker mode keeps the existing `silicon` command but runs each Silicon in its own
|
|
96
|
+
container. Mutable instance state lives on the host under `~/silicons/<name>` and
|
|
97
|
+
is bind-mounted at `/silicon` inside the container. Provider secrets are still
|
|
98
|
+
Glass-managed: the container stores only the Silicon's `.glass.json` key and the
|
|
99
|
+
stemcell fetches provider keys from Glass on boot.
|
|
100
|
+
|
|
101
|
+
Claude Code and Codex account state is shared across all Docker-backed silicons
|
|
102
|
+
on the VM. The shared auth home defaults to `~/silicons/.shared-home` and is
|
|
103
|
+
mounted into every container. During an interactive `silicon pull`, the CLI asks
|
|
104
|
+
whether to set up Claude Code, Codex, or both before installing the team.
|
|
105
|
+
|
|
106
|
+
On a fresh Linux server, the host only needs Python and this CLI. `silicon pull`
|
|
107
|
+
checks Docker Engine, Docker Compose v2, the daemon, current-user access, runtime
|
|
108
|
+
config, and the runtime image. When Docker is missing on Linux, it can install
|
|
109
|
+
Docker Engine through Docker's official `get.docker.com` installer, start the
|
|
110
|
+
daemon, and continue.
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
pip install silicon-cli
|
|
114
|
+
silicon pull sct_live_...
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
To run the same checks explicitly:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
silicon docker bootstrap --root ~/silicons --image teamofsilicons/silicon-runtime:latest
|
|
121
|
+
silicon docker doctor
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
To set up or repair shared Claude/Codex login manually:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
silicon docker login # asks which accounts to set up
|
|
128
|
+
silicon docker login claude # Claude Code only
|
|
129
|
+
silicon docker login codex # Codex only
|
|
130
|
+
silicon docker login all # both
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
To use those same shared accounts directly from the VM without installing Claude
|
|
134
|
+
or Codex on the host:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
silicon claude
|
|
138
|
+
silicon codex
|
|
139
|
+
silicon claude --version
|
|
140
|
+
silicon codex --version
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The runtime image contains the Silicon runtime dependencies: Python tooling, git,
|
|
144
|
+
Node, Silicon Browser, Silicon Interface CLI, Claude Code, and Codex. Each
|
|
145
|
+
container creates `/silicon/.venv` and installs that Silicon's `requirements.txt`
|
|
146
|
+
inside the mounted instance folder, so per-Silicon Python dependencies do not
|
|
147
|
+
pollute the host.
|
|
148
|
+
|
|
149
|
+
To force the older host-local install path:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
SILICON_RUNTIME=local silicon pull sct_live_...
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
After that, the normal commands continue to work:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
silicon list
|
|
159
|
+
silicon start all
|
|
160
|
+
silicon stop ada # stops the Silicon process; container stays up
|
|
161
|
+
silicon stop --full ada # stops the container
|
|
162
|
+
silicon debug ada
|
|
163
|
+
silicon update ada
|
|
164
|
+
silicon backup ada now
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The generated Compose file is written to `~/silicons/compose.yml`. You can inspect
|
|
168
|
+
it with:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
silicon docker compose
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Build the runtime image from this repo:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
docker build -f docker/runtime/Dockerfile -t teamofsilicons/silicon-runtime:latest .
|
|
178
|
+
```
|
|
74
179
|
|
|
75
180
|
## Silicon Interface CLI
|
|
76
181
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
182
|
+
For Docker-backed installs, the Silicon Interface CLI is installed inside the
|
|
183
|
+
runtime image/container. For host-local installs, `silicon new`, `silicon install`,
|
|
184
|
+
and `silicon pull` set up the Silicon Interface CLI in the silicon folder when
|
|
185
|
+
Node 22+ is available. When a Glass `.glass.json` is present, setup also starts
|
|
186
|
+
the background listener daemon so the silicon receives live conversation frames
|
|
187
|
+
without polling.
|
|
81
188
|
|
|
82
189
|
`silicon pull` is token-native. Generate a team setup token from Glass >
|
|
83
190
|
Silicons > Team setup token, then run:
|
|
@@ -92,8 +199,8 @@ silicon pull sct_live_...
|
|
|
92
199
|
|
|
93
200
|
The command validates the token with Glass, mints one local silicon API key per
|
|
94
201
|
team silicon, creates one folder per silicon, hydrates the stemcell, writes
|
|
95
|
-
`.glass.json`, `.env`, and `env.py`, registers each instance,
|
|
96
|
-
|
|
202
|
+
`.glass.json`, `.env`, and `env.py`, registers each instance, regenerates Compose
|
|
203
|
+
for Docker-backed installs, and starts each silicon process.
|
|
97
204
|
|
|
98
205
|
During team pull, setup asks for the default brain/fallback settings once. You
|
|
99
206
|
can apply those settings to every silicon, or select specific silicons that
|
|
@@ -102,9 +209,9 @@ Older per-silicon `scs_live_...` tokens still pull just that one silicon.
|
|
|
102
209
|
|
|
103
210
|
Provider API keys for voice, browser profiles, billing, and architecture
|
|
104
211
|
generation are configured on the Glass backend. After the silicon API token is
|
|
105
|
-
validated, `silicon pull` reads the team's provider-key metadata from Glass
|
|
106
|
-
|
|
107
|
-
|
|
212
|
+
validated, `silicon pull` reads the team's provider-key metadata from Glass and
|
|
213
|
+
automatically marks the pulled silicon(s) to use Glass-managed keys when every
|
|
214
|
+
provider is available. Plaintext secrets are never returned to the CLI. A
|
|
108
215
|
Glass-pulled silicon only stores its Glass API token plus a local marker that
|
|
109
216
|
provider keys come from Glass.
|
|
110
217
|
|
|
@@ -5,7 +5,7 @@ package is named `silicon-cli`, and the code lives here in this `silicon-cli`
|
|
|
5
5
|
repo.
|
|
6
6
|
|
|
7
7
|
The command manages silicon instances on a machine: create them from the
|
|
8
|
-
[silicon-stemcell](https://github.com/
|
|
8
|
+
[silicon-stemcell](https://github.com/teamofsilicons/silicon-stemcell) base,
|
|
9
9
|
start/stop them under an auto-restart watchdog, stream logs, and back them up to
|
|
10
10
|
Glass. It reads the same `~/.silicon/registry.json`, so existing installs carry
|
|
11
11
|
over unchanged.
|
|
@@ -30,6 +30,8 @@ silicon restart <target> Restart silicon(s). target = name, *, all, 1,2,4, o
|
|
|
30
30
|
silicon agent <start|stop|status> [name] Manage the per-silicon glass agent
|
|
31
31
|
silicon status [name] Show instance status
|
|
32
32
|
silicon browser [name] Open a headed browser for login
|
|
33
|
+
silicon browser-profile setup <token> Create a Steel browser profile through Glass
|
|
34
|
+
silicon browser-profile finish <token> <session_id> [before_ids_csv] Finish profile setup
|
|
33
35
|
silicon debug [name] Tail a running instance's logs
|
|
34
36
|
silicon attach [path] Register an existing silicon directory
|
|
35
37
|
silicon pull [api_token] Pull a Glass team or silicon into local folders
|
|
@@ -37,6 +39,14 @@ silicon push [name] [now|stop] Daily 23:59 GMT backups to Glass (now = one-sho
|
|
|
37
39
|
silicon backup [name] [now|stop] Alias for silicon push
|
|
38
40
|
silicon update <target> Update silicon(s) from the latest stemcell
|
|
39
41
|
silicon list List all instances
|
|
42
|
+
silicon docker init [--root ~/silicons] [--image teamofsilicons/silicon-runtime:latest]
|
|
43
|
+
Install/check Docker and enable one-container-per-Silicon runtime
|
|
44
|
+
silicon docker doctor Check/repair Docker runtime setup
|
|
45
|
+
silicon docker login [claude|codex|all]
|
|
46
|
+
Set up shared Claude/Codex auth for Docker silicons
|
|
47
|
+
silicon docker compose Print generated Compose file path
|
|
48
|
+
silicon claude [args...] Run Claude Code with shared Docker auth
|
|
49
|
+
silicon codex [args...] Run Codex with shared Docker auth
|
|
40
50
|
silicon script update Update this CLI itself
|
|
41
51
|
silicon help Show help
|
|
42
52
|
```
|
|
@@ -47,21 +57,117 @@ silicon help Show help
|
|
|
47
57
|
| --- | --- | --- |
|
|
48
58
|
| `SILICON_HOME` | `~/.silicon` | registry + CLI state |
|
|
49
59
|
| `GLASS_SERVER_URL` | `https://glass.teamofsilicons.com` | Glass sync server (pull/push) |
|
|
50
|
-
| `SILICON_STEMCELL_REPO` | `
|
|
51
|
-
| `SILICON_GLASS_CLI_REPO` | `
|
|
60
|
+
| `SILICON_STEMCELL_REPO` | `teamofsilicons/silicon-stemcell` | base for `new` |
|
|
61
|
+
| `SILICON_GLASS_CLI_REPO` | `teamofsilicons/glass` | glass backup CLI |
|
|
52
62
|
| `SILICON_PYTHON` | `python3` | interpreter used to run a silicon's `main.py` |
|
|
53
63
|
| `SILICON_INTERFACE_CLI_PACKAGE` | `@teamofsilicons/silicon-interface-cli` | npm package used to install the Silicon Interface CLI |
|
|
54
64
|
| `SILICON_INTERFACE_CLI_TARBALL` | versioned npm tarball | fallback package URL if registry metadata is briefly unavailable |
|
|
55
65
|
| `SILICON_INTERFACE_CLI_SOURCE` | *(empty)* | local package dir or `silicon-interface.mjs` path for dev installs |
|
|
56
66
|
| `SILICON_INTERFACE_CLI_SKIP` | *(empty)* | set to `1` to skip interface CLI setup |
|
|
57
67
|
| `SILICON_INTERFACE_DAEMON_SKIP` | *(empty)* | set to `1` to install the CLI without starting its listener daemon |
|
|
68
|
+
| `SILICON_RUNTIME` | *(empty)* | default pull uses Docker; set to `local` to opt out |
|
|
69
|
+
| `SILICON_RUNTIME_IMAGE` | `teamofsilicons/silicon-runtime:latest` | runtime image for Docker-backed silicons |
|
|
70
|
+
| `SILICON_DOCKER_ROOT` | `~/silicons` | Docker-backed instance root |
|
|
71
|
+
| `SILICON_DOCKER_COMPOSE` | `<root>/compose.yml` | generated Compose file path |
|
|
72
|
+
| `SILICON_DOCKER_SHARED_HOME` | `<root>/.shared-home` | VM-wide Claude/Codex auth home mounted into every container |
|
|
73
|
+
| `SILICON_DOCKER_SUDO` | *(empty)* | set to `1` to run Docker commands through `sudo docker` |
|
|
74
|
+
| `SILICON_DOCKER_AUTO_INSTALL` | *(empty)* | set to `1` to allow non-interactive Docker install attempts |
|
|
75
|
+
|
|
76
|
+
## Docker runtime
|
|
77
|
+
|
|
78
|
+
Docker mode keeps the existing `silicon` command but runs each Silicon in its own
|
|
79
|
+
container. Mutable instance state lives on the host under `~/silicons/<name>` and
|
|
80
|
+
is bind-mounted at `/silicon` inside the container. Provider secrets are still
|
|
81
|
+
Glass-managed: the container stores only the Silicon's `.glass.json` key and the
|
|
82
|
+
stemcell fetches provider keys from Glass on boot.
|
|
83
|
+
|
|
84
|
+
Claude Code and Codex account state is shared across all Docker-backed silicons
|
|
85
|
+
on the VM. The shared auth home defaults to `~/silicons/.shared-home` and is
|
|
86
|
+
mounted into every container. During an interactive `silicon pull`, the CLI asks
|
|
87
|
+
whether to set up Claude Code, Codex, or both before installing the team.
|
|
88
|
+
|
|
89
|
+
On a fresh Linux server, the host only needs Python and this CLI. `silicon pull`
|
|
90
|
+
checks Docker Engine, Docker Compose v2, the daemon, current-user access, runtime
|
|
91
|
+
config, and the runtime image. When Docker is missing on Linux, it can install
|
|
92
|
+
Docker Engine through Docker's official `get.docker.com` installer, start the
|
|
93
|
+
daemon, and continue.
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
pip install silicon-cli
|
|
97
|
+
silicon pull sct_live_...
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
To run the same checks explicitly:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
silicon docker bootstrap --root ~/silicons --image teamofsilicons/silicon-runtime:latest
|
|
104
|
+
silicon docker doctor
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
To set up or repair shared Claude/Codex login manually:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
silicon docker login # asks which accounts to set up
|
|
111
|
+
silicon docker login claude # Claude Code only
|
|
112
|
+
silicon docker login codex # Codex only
|
|
113
|
+
silicon docker login all # both
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
To use those same shared accounts directly from the VM without installing Claude
|
|
117
|
+
or Codex on the host:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
silicon claude
|
|
121
|
+
silicon codex
|
|
122
|
+
silicon claude --version
|
|
123
|
+
silicon codex --version
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The runtime image contains the Silicon runtime dependencies: Python tooling, git,
|
|
127
|
+
Node, Silicon Browser, Silicon Interface CLI, Claude Code, and Codex. Each
|
|
128
|
+
container creates `/silicon/.venv` and installs that Silicon's `requirements.txt`
|
|
129
|
+
inside the mounted instance folder, so per-Silicon Python dependencies do not
|
|
130
|
+
pollute the host.
|
|
131
|
+
|
|
132
|
+
To force the older host-local install path:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
SILICON_RUNTIME=local silicon pull sct_live_...
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
After that, the normal commands continue to work:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
silicon list
|
|
142
|
+
silicon start all
|
|
143
|
+
silicon stop ada # stops the Silicon process; container stays up
|
|
144
|
+
silicon stop --full ada # stops the container
|
|
145
|
+
silicon debug ada
|
|
146
|
+
silicon update ada
|
|
147
|
+
silicon backup ada now
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
The generated Compose file is written to `~/silicons/compose.yml`. You can inspect
|
|
151
|
+
it with:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
silicon docker compose
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Build the runtime image from this repo:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
docker build -f docker/runtime/Dockerfile -t teamofsilicons/silicon-runtime:latest .
|
|
161
|
+
```
|
|
58
162
|
|
|
59
163
|
## Silicon Interface CLI
|
|
60
164
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
165
|
+
For Docker-backed installs, the Silicon Interface CLI is installed inside the
|
|
166
|
+
runtime image/container. For host-local installs, `silicon new`, `silicon install`,
|
|
167
|
+
and `silicon pull` set up the Silicon Interface CLI in the silicon folder when
|
|
168
|
+
Node 22+ is available. When a Glass `.glass.json` is present, setup also starts
|
|
169
|
+
the background listener daemon so the silicon receives live conversation frames
|
|
170
|
+
without polling.
|
|
65
171
|
|
|
66
172
|
`silicon pull` is token-native. Generate a team setup token from Glass >
|
|
67
173
|
Silicons > Team setup token, then run:
|
|
@@ -76,8 +182,8 @@ silicon pull sct_live_...
|
|
|
76
182
|
|
|
77
183
|
The command validates the token with Glass, mints one local silicon API key per
|
|
78
184
|
team silicon, creates one folder per silicon, hydrates the stemcell, writes
|
|
79
|
-
`.glass.json`, `.env`, and `env.py`, registers each instance,
|
|
80
|
-
|
|
185
|
+
`.glass.json`, `.env`, and `env.py`, registers each instance, regenerates Compose
|
|
186
|
+
for Docker-backed installs, and starts each silicon process.
|
|
81
187
|
|
|
82
188
|
During team pull, setup asks for the default brain/fallback settings once. You
|
|
83
189
|
can apply those settings to every silicon, or select specific silicons that
|
|
@@ -86,9 +192,9 @@ Older per-silicon `scs_live_...` tokens still pull just that one silicon.
|
|
|
86
192
|
|
|
87
193
|
Provider API keys for voice, browser profiles, billing, and architecture
|
|
88
194
|
generation are configured on the Glass backend. After the silicon API token is
|
|
89
|
-
validated, `silicon pull` reads the team's provider-key metadata from Glass
|
|
90
|
-
|
|
91
|
-
|
|
195
|
+
validated, `silicon pull` reads the team's provider-key metadata from Glass and
|
|
196
|
+
automatically marks the pulled silicon(s) to use Glass-managed keys when every
|
|
197
|
+
provider is available. Plaintext secrets are never returned to the CLI. A
|
|
92
198
|
Glass-pulled silicon only stores its Glass API token plus a local marker that
|
|
93
199
|
provider keys come from Glass.
|
|
94
200
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""Silicon CLI — manage silicon instances. Python port of the original bash manager."""
|
|
2
|
-
__version__ = "1.0.
|
|
2
|
+
__version__ = "1.0.10"
|
|
@@ -5,12 +5,13 @@ import subprocess
|
|
|
5
5
|
import sys
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
|
-
from . import glassagent, process, registry, stemcell, sync, ui, update
|
|
8
|
+
from . import docker_runtime, glassagent, process, registry, stemcell, sync, ui, update
|
|
9
9
|
from .config import python_run_cmd
|
|
10
10
|
|
|
11
11
|
COMMANDS = ["start", "stop", "restart", "status", "browser", "debug", "attach",
|
|
12
12
|
"pull", "push", "backup", "update", "update-check", "check-update",
|
|
13
|
-
"list", "install", "new", "help", "script", "agent"
|
|
13
|
+
"browser-profile", "list", "install", "new", "help", "script", "agent",
|
|
14
|
+
"docker", "claude", "codex"]
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
# ----------------------------------------------------------------- commands
|
|
@@ -24,17 +25,21 @@ def cmd_list() -> None:
|
|
|
24
25
|
print(f" {ui.DIM}{'#':<4}{'NAME':<22}{'STATUS':<10}PATH{ui.RESET}")
|
|
25
26
|
print(f" {ui.DIM}{'---':<4}{'----':<22}{'------':<10}----{ui.RESET}")
|
|
26
27
|
for i in rows:
|
|
27
|
-
if process.
|
|
28
|
+
if process.install_is_running(i):
|
|
28
29
|
pid = process.get_pid(i.pid_file)
|
|
29
30
|
status = f"{ui.GREEN}● running{ui.RESET}"
|
|
30
|
-
extra = f" {ui.DIM}(PID {pid}){ui.RESET}"
|
|
31
|
+
extra = f" {ui.DIM}(Docker){ui.RESET}" if i.is_docker else f" {ui.DIM}(PID {pid}){ui.RESET}"
|
|
31
32
|
else:
|
|
32
|
-
status
|
|
33
|
+
status = f"{ui.DIM}○ stopped{ui.RESET}"
|
|
34
|
+
extra = f" {ui.DIM}(Docker){ui.RESET}" if i.is_docker else ""
|
|
33
35
|
print(f" {i.index + 1:<4}{i.name:<22}{status}{extra} {ui.DIM}{i.path}{ui.RESET}")
|
|
34
36
|
print()
|
|
35
37
|
|
|
36
38
|
|
|
37
39
|
def _print_status(inst) -> None:
|
|
40
|
+
if inst.is_docker:
|
|
41
|
+
docker_runtime.print_status(inst)
|
|
42
|
+
return
|
|
38
43
|
if process.is_running(inst.pid_file):
|
|
39
44
|
pid = process.get_pid(inst.pid_file)
|
|
40
45
|
print(f"\n{ui.BOLD}{inst.name}{ui.RESET} {ui.GREEN}● running{ui.RESET} (PID {pid})")
|
|
@@ -60,13 +65,19 @@ def cmd_status(target: str | None) -> None:
|
|
|
60
65
|
|
|
61
66
|
def cmd_browser(target: str | None) -> None:
|
|
62
67
|
inst = registry.resolve_one(target)
|
|
68
|
+
if inst.is_docker:
|
|
69
|
+
docker_runtime.run_silicon(inst, ["browser", inst.name])
|
|
70
|
+
return
|
|
63
71
|
ui.info(f"Opening browser for '{inst.name}'...")
|
|
64
|
-
subprocess.run([python_run_cmd(), "main.py", "browser"], cwd=inst.path)
|
|
72
|
+
subprocess.run([python_run_cmd(inst.path), "main.py", "browser"], cwd=inst.path)
|
|
65
73
|
|
|
66
74
|
|
|
67
75
|
def cmd_debug(target: str | None) -> None:
|
|
68
76
|
inst = registry.resolve_one(target)
|
|
69
|
-
if
|
|
77
|
+
if inst.is_docker:
|
|
78
|
+
docker_runtime.debug(inst)
|
|
79
|
+
return
|
|
80
|
+
if not process.install_is_running(inst):
|
|
70
81
|
ui.error(f"'{inst.name}' is not running. Start it first with: silicon start {inst.name}")
|
|
71
82
|
sys.exit(1)
|
|
72
83
|
log_file = Path(inst.path) / ".silicon.log"
|
|
@@ -121,6 +132,11 @@ def cmd_agent(subcmd: str | None, target: str | None) -> None:
|
|
|
121
132
|
ui.error("Usage: silicon agent <start|stop|status> [name]")
|
|
122
133
|
sys.exit(1)
|
|
123
134
|
inst = registry.resolve_one(target)
|
|
135
|
+
if inst.is_docker:
|
|
136
|
+
code = docker_runtime.run_silicon(inst, ["agent", subcmd, inst.name])
|
|
137
|
+
if code:
|
|
138
|
+
sys.exit(code)
|
|
139
|
+
return
|
|
124
140
|
if subcmd == "start":
|
|
125
141
|
glassagent.start(inst.path)
|
|
126
142
|
elif subcmd == "stop":
|
|
@@ -137,6 +153,28 @@ def cmd_agent(subcmd: str | None, target: str | None) -> None:
|
|
|
137
153
|
|
|
138
154
|
|
|
139
155
|
def cmd_new(target: str | None) -> None:
|
|
156
|
+
if docker_runtime.enabled():
|
|
157
|
+
docker_runtime.ensure_ready(auto_init=False, install=True, pull_image=True, quiet=True)
|
|
158
|
+
docker_target = docker_runtime.target_path(target)
|
|
159
|
+
stemcell.hydrate(
|
|
160
|
+
str(docker_target),
|
|
161
|
+
install_deps=False,
|
|
162
|
+
setup_interface=False,
|
|
163
|
+
register_install=False,
|
|
164
|
+
)
|
|
165
|
+
name = docker_target.name
|
|
166
|
+
sj = docker_target / "silicon.json"
|
|
167
|
+
if sj.exists():
|
|
168
|
+
import json
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
data = json.loads(sj.read_text())
|
|
172
|
+
name = (data.get("address") or data.get("name") or name).strip() or name
|
|
173
|
+
except Exception:
|
|
174
|
+
pass
|
|
175
|
+
docker_runtime.register_instance(name, docker_target)
|
|
176
|
+
ui.info(f"Run 'silicon start {name}' when you're ready.")
|
|
177
|
+
return
|
|
140
178
|
if target:
|
|
141
179
|
stemcell.hydrate(target)
|
|
142
180
|
return
|
|
@@ -163,6 +201,10 @@ def cmd_help() -> None:
|
|
|
163
201
|
silicon agent <start|stop|status> [name] Manage glass agent
|
|
164
202
|
silicon status [name] Show instance status
|
|
165
203
|
silicon browser [name] Open headed browser for login
|
|
204
|
+
silicon browser-profile setup <token>
|
|
205
|
+
Create a Steel browser profile through Glass
|
|
206
|
+
silicon browser-profile finish <token> <session_id> [before_ids_csv]
|
|
207
|
+
Finish a browser profile setup session
|
|
166
208
|
silicon debug [name] Attach to running instance (live logs)
|
|
167
209
|
silicon attach [path] Register an existing silicon instance
|
|
168
210
|
silicon pull [api_token] Pull a Glass team or silicon into local folders
|
|
@@ -174,6 +216,11 @@ def cmd_help() -> None:
|
|
|
174
216
|
silicon update check [name] Trigger this silicon's system update check now
|
|
175
217
|
silicon update-check [name] Trigger this silicon's system update check now
|
|
176
218
|
silicon list List all instances
|
|
219
|
+
silicon docker init Install/check Docker and enable Docker-backed installs
|
|
220
|
+
silicon docker doctor Repair/check Docker runtime setup
|
|
221
|
+
silicon docker login Set up shared Claude/Codex auth for Docker silicons
|
|
222
|
+
silicon claude [args...] Run Claude Code with shared Docker auth
|
|
223
|
+
silicon codex [args...] Run Codex with shared Docker auth
|
|
177
224
|
silicon script update Update the silicon CLI itself
|
|
178
225
|
silicon install Install a new instance
|
|
179
226
|
silicon help Show this help
|
|
@@ -220,8 +267,24 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
220
267
|
cmd_status(a1)
|
|
221
268
|
elif cmd == "browser":
|
|
222
269
|
cmd_browser(a1)
|
|
270
|
+
elif cmd == "browser-profile":
|
|
271
|
+
if a1 == "setup":
|
|
272
|
+
sync.browser_profile_setup(a2)
|
|
273
|
+
elif a1 == "finish":
|
|
274
|
+
sync.browser_profile_finish(
|
|
275
|
+
a2,
|
|
276
|
+
argv[3] if len(argv) > 3 else None,
|
|
277
|
+
argv[4] if len(argv) > 4 else None,
|
|
278
|
+
)
|
|
279
|
+
else:
|
|
280
|
+
ui.error("Usage: silicon browser-profile <setup|finish> ...")
|
|
281
|
+
sys.exit(1)
|
|
223
282
|
elif cmd == "debug":
|
|
224
283
|
cmd_debug(a1)
|
|
284
|
+
elif cmd == "docker":
|
|
285
|
+
docker_runtime.cmd_docker(argv[1:])
|
|
286
|
+
elif cmd in ("claude", "codex"):
|
|
287
|
+
docker_runtime.run_shared_tool(cmd, argv[1:])
|
|
225
288
|
elif cmd == "attach":
|
|
226
289
|
cmd_attach(a1)
|
|
227
290
|
elif cmd == "pull":
|
|
@@ -15,12 +15,12 @@ CLI_SOURCE_FILE = REGISTRY_DIR / "cli-source" # where `silicon script update` r
|
|
|
15
15
|
GLASS_SERVER_URL = os.environ.get("GLASS_SERVER_URL", "https://glass.teamofsilicons.com").rstrip("/")
|
|
16
16
|
|
|
17
17
|
# Stemcell — the base every new silicon is hydrated from.
|
|
18
|
-
STEMCELL_REPO = os.environ.get("SILICON_STEMCELL_REPO", "
|
|
18
|
+
STEMCELL_REPO = os.environ.get("SILICON_STEMCELL_REPO", "teamofsilicons/silicon-stemcell")
|
|
19
19
|
STEMCELL_GIT_URL = f"https://github.com/{STEMCELL_REPO}.git"
|
|
20
20
|
STEMCELL_ZIP_URL = f"https://github.com/{STEMCELL_REPO}/archive/refs/heads/main.zip"
|
|
21
21
|
|
|
22
22
|
# Glass CLI (used by pull/push for backups).
|
|
23
|
-
GLASS_CLI_REPO = os.environ.get("SILICON_GLASS_CLI_REPO", "
|
|
23
|
+
GLASS_CLI_REPO = os.environ.get("SILICON_GLASS_CLI_REPO", "teamofsilicons/glass")
|
|
24
24
|
|
|
25
25
|
# Silicon Interface CLI. During local development, silicon-cli will auto-detect
|
|
26
26
|
# a sibling silicon-interface checkout; in production this package spec is used.
|
|
@@ -41,6 +41,29 @@ SILICON_INTERFACE_DAEMON_SKIP = os.environ.get("SILICON_INTERFACE_DAEMON_SKIP",
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
def
|
|
45
|
-
"""The
|
|
44
|
+
def venv_python(path: str | os.PathLike) -> str | None:
|
|
45
|
+
"""The silicon's own .venv interpreter, if one exists."""
|
|
46
|
+
sub = "Scripts/python.exe" if os.name == "nt" else "bin/python"
|
|
47
|
+
cand = Path(path) / ".venv" / sub
|
|
48
|
+
return str(cand) if cand.exists() else None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def base_python_cmd() -> str:
|
|
52
|
+
"""The interpreter used to CREATE a silicon's venv (not this CLI's venv)."""
|
|
46
53
|
return os.environ.get("SILICON_PYTHON") or shutil.which("python3") or shutil.which("python") or "python3"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def python_run_cmd(path: str | os.PathLike | None = None) -> str:
|
|
57
|
+
"""The interpreter used to RUN a silicon's code (not this CLI's venv).
|
|
58
|
+
|
|
59
|
+
SILICON_PYTHON always wins; otherwise prefer the silicon's own .venv —
|
|
60
|
+
system interpreters are often externally managed (PEP 668) and never
|
|
61
|
+
received the silicon's dependencies.
|
|
62
|
+
"""
|
|
63
|
+
if os.environ.get("SILICON_PYTHON"):
|
|
64
|
+
return os.environ["SILICON_PYTHON"]
|
|
65
|
+
if path:
|
|
66
|
+
venv = venv_python(path)
|
|
67
|
+
if venv:
|
|
68
|
+
return venv
|
|
69
|
+
return shutil.which("python3") or shutil.which("python") or "python3"
|