@clawscarf/cli 0.1.0-alpha.1 → 0.1.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/deploy/execution/network/node-ingress.cfg +1 -1
- package/package.json +1 -1
- package/recipes/team-server/recipe.json +1 -1
- package/release/README.md +41 -13
- package/release/components.json +16 -0
- package/release/operator.md +13 -1
- package/runtime/releases/0.1.0-alpha.2.json +63 -0
- package/scripts/controller.js +6 -0
- package/scripts/deployment/browser-node-compose.js +0 -1
- package/scripts/deployment/certificates.js +1 -1
- package/scripts/deployment/compose.js +3 -5
- package/scripts/deployment/configuration.js +5 -5
- package/scripts/deployment/controller-compose.js +14 -6
- package/scripts/deployment/model-gateway-compose.js +6 -0
- package/scripts/deployment/model-gateway.js +9 -1
- package/scripts/deployment/networks.js +21 -0
- package/scripts/deployment/prepare.js +11 -5
- package/scripts/installation/installer/prompts.js +5 -1
- package/scripts/installation/prerequisites.js +10 -5
- package/scripts/installation/resolve.js +6 -5
- package/scripts/installation/runtime.js +3 -3
- package/scripts/release/definition.js +30 -3
- package/runtime/releases/0.1.0-alpha.1.json +0 -37
|
@@ -32,4 +32,4 @@ frontend native_node
|
|
|
32
32
|
default_backend native_gateway
|
|
33
33
|
|
|
34
34
|
backend native_gateway
|
|
35
|
-
server gateway "
|
|
35
|
+
server gateway "application:${CLAWSCARF_NODE_GATEWAY_PORT}" resolvers docker init-addr libc,none
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "team-server",
|
|
3
3
|
"version": "0.1.0",
|
|
4
|
-
"runtime": "../../runtime/releases/0.1.0-alpha.
|
|
4
|
+
"runtime": "../../runtime/releases/0.1.0-alpha.2.json",
|
|
5
5
|
"name": "Team server",
|
|
6
6
|
"description": "A protected OpenClaw server for your team, with hosted login, managed models and optional Connections.",
|
|
7
7
|
"maturity": "supported",
|
package/release/README.md
CHANGED
|
@@ -14,9 +14,10 @@ Recipes and packs ship with the CLI; there is no separate registry or dependency
|
|
|
14
14
|
The [model catalog](../deploy/models/catalog.json) is also a CLI asset. Recipe IDs select
|
|
15
15
|
catalog entries; model protocols and limits have one definition.
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## Published and development use
|
|
18
18
|
|
|
19
19
|
```sh
|
|
20
|
+
npm install -g @clawscarf/cli@next
|
|
20
21
|
clawscarf configure
|
|
21
22
|
# Or use staging for hosted login and Connections:
|
|
22
23
|
clawscarf configure --cloud-url https://cloud-staging.clawscarf.com
|
|
@@ -33,7 +34,13 @@ locally built Docker image IDs and checksum-pinned OpenShell tools under ignored
|
|
|
33
34
|
published, clean-machine release**. Definitions belong in the tracked directories
|
|
34
35
|
above. Compiled images, binaries and test artifacts are not source definitions.
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
Published candidates include macOS arm64 and Linux arm64/x86-64 tools, with Linux
|
|
38
|
+
container images for both architectures. Windows uses the Linux CLI inside WSL2
|
|
39
|
+
(experimental);
|
|
40
|
+
Docker Desktop must expose its Linux engine to that distribution. Intel Mac is blocked
|
|
41
|
+
by the pinned upstream OpenShell release lacking a Darwin x86-64 executable.
|
|
42
|
+
See the [upstream support matrix](https://docs.nvidia.com/openshell/reference/support-matrix)
|
|
43
|
+
for host requirements. Setup validates the host,
|
|
37
44
|
tools and ports; it pulls registry images by digest and downloads missing runtime tools
|
|
38
45
|
when their definition supplies an HTTPS URL and SHA-256. It cannot recover a missing
|
|
39
46
|
local development image ID. See the
|
|
@@ -66,15 +73,23 @@ silently replaced. Docker verifies image digests. No start command resolves late
|
|
|
66
73
|
with an exact version, such as `0.1.0-alpha.1`. It:
|
|
67
74
|
|
|
68
75
|
1. Runs checks and tests the compiled operator outside the checkout on macOS arm64.
|
|
69
|
-
2. Builds the pinned OpenClaw source and ClawScarf images on Linux arm64,
|
|
70
|
-
runtime capabilities and the Chromium sandbox,
|
|
76
|
+
2. Builds the pinned OpenClaw source and ClawScarf images on Linux arm64 and x86-64,
|
|
77
|
+
checks runtime capabilities and the Chromium sandbox, then starts a protected
|
|
78
|
+
installation with private LiteLLM networking and verifies stop/start retention.
|
|
79
|
+
It publishes image indexes containing both architectures to GHCR.
|
|
71
80
|
3. Downloads checksum-pinned OpenShell tools, records the image digests, and assembles
|
|
72
|
-
|
|
81
|
+
one runtime archive per host platform, individual executable assets, npm CLI,
|
|
82
|
+
checksums and notices.
|
|
73
83
|
4. Installs the resulting npm archive into a temporary prefix and checks its CLI/catalog.
|
|
74
84
|
|
|
75
85
|
The [image builder](../scripts/release/build-images.sh) and
|
|
76
86
|
[candidate assembler](../scripts/release/candidate.ts) contain the build commands;
|
|
77
|
-
Actions
|
|
87
|
+
GitHub Actions orchestrates the build and supplies registry credentials. Image builds
|
|
88
|
+
and Linux installation checks use Depot ARM64/x86-64 runners; macOS checks and packaging
|
|
89
|
+
use GitHub-hosted runners. The Depot Managed Runners app connects the ClawScarf organization
|
|
90
|
+
to the RAW Labs Depot organization. The image job installs Docker 29.5.3 on its
|
|
91
|
+
disposable runner for the network features required by installations.
|
|
92
|
+
The source recipe pins the development
|
|
78
93
|
runtime. Packaging resolves that same runtime to the candidate's immutable definition;
|
|
79
94
|
it does not make recipes select latest. The first release uses the same CLI/runtime
|
|
80
95
|
version. Recipe versions remain independent; bump them when defaults, pack selection
|
|
@@ -92,20 +107,33 @@ GitHub Release and publishes the already-built npm tarball. It never rebuilds im
|
|
|
92
107
|
or packages. Prereleases use npm's `next` tag; stable versions use `latest`. Repeating
|
|
93
108
|
a GitHub upload is allowed only when the existing checksums match exactly.
|
|
94
109
|
|
|
95
|
-
Repository setup
|
|
110
|
+
Repository setup:
|
|
96
111
|
|
|
97
112
|
- GHCR image packages must be publicly readable; a private candidate digest is not
|
|
98
113
|
usable by an unauthenticated installer. The build uses GitHub's scoped job token.
|
|
99
|
-
-
|
|
100
|
-
`@clawscarf
|
|
101
|
-
|
|
102
|
-
-
|
|
114
|
+
- The GitHub `release` environment restricts deployment to `main`. The npm
|
|
115
|
+
organization `@clawscarf` owns the public `@clawscarf/cli` package.
|
|
116
|
+
- npm trusted publishing is configured for repository `clawscarf/clawscarf`, workflow
|
|
117
|
+
[publish-release.yml](../.github/workflows/publish-release.yml), environment `release`.
|
|
118
|
+
The first tested tarball was published using the owner's authenticated npm CLI because
|
|
119
|
+
npm requires a package to exist before configuring trust. Subsequent publication
|
|
120
|
+
uses the workflow's short-lived identity rather than a stored npm token. That next
|
|
121
|
+
workflow publication has not yet been exercised.
|
|
122
|
+
- Transitive notices/source review remains open in [TODO.md](../TODO.md).
|
|
103
123
|
Debian copyright files remain in the images; runtime assets include upstream notices
|
|
104
124
|
and the image build exports its network-tool sources. Those files are not a claim of
|
|
105
125
|
a completed license audit. Pinned Debian packages still depend on mirror retention.
|
|
106
126
|
|
|
107
|
-
|
|
108
|
-
|
|
127
|
+
[Candidate 35524428880](https://github.com/clawscarf/clawscarf/actions/runs/35524428880)
|
|
128
|
+
passed its checks, compiled archive test and all eight image builds. The same artifacts
|
|
129
|
+
are available in the [0.1.0-alpha.1 GitHub prerelease](https://github.com/clawscarf/clawscarf/releases/tag/v0.1.0-alpha.1).
|
|
130
|
+
The identical CLI tarball is published as `@clawscarf/cli@0.1.0-alpha.1`, tagged `next`.
|
|
131
|
+
All eight GHCR images were verified anonymously readable by digest. The packaged CLI
|
|
132
|
+
passed fresh setup on the development Mac, staging hosted administrator login, real
|
|
133
|
+
GPT-6 Astra inference and stop/start with retained chat history. Published tool URLs
|
|
134
|
+
passed download and SHA-256 verification. Disposable installation containers, volumes
|
|
135
|
+
and networks were deleted afterward. This does not establish a newly provisioned
|
|
136
|
+
host, production first-time signup, Linux/WSL or changed-version upgrades.
|
|
109
137
|
|
|
110
138
|
## Assemble runtime artifacts
|
|
111
139
|
|
package/release/components.json
CHANGED
|
@@ -12,12 +12,28 @@
|
|
|
12
12
|
"darwin-arm64": {
|
|
13
13
|
"url": "https://github.com/NVIDIA/OpenShell/releases/download/v0.0.116/openshell-aarch64-apple-darwin.tar.gz",
|
|
14
14
|
"sha256": "e582f2374053bebac8e6aaeb4a369931b7d4bb97bd55055e2c02e85502627e22"
|
|
15
|
+
},
|
|
16
|
+
"linux-arm64": {
|
|
17
|
+
"url": "https://github.com/NVIDIA/OpenShell/releases/download/v0.0.116/openshell-aarch64-unknown-linux-musl.tar.gz",
|
|
18
|
+
"sha256": "7a949c48d1e000cd280869eea1e203e24816b9cfefc575b68a8b72b939cb3f43"
|
|
19
|
+
},
|
|
20
|
+
"linux-x64": {
|
|
21
|
+
"url": "https://github.com/NVIDIA/OpenShell/releases/download/v0.0.116/openshell-x86_64-unknown-linux-musl.tar.gz",
|
|
22
|
+
"sha256": "4fb4476d80a1875a0b83547ec3aba999cf0a2e2d75f95f2f709b622e2103520e"
|
|
15
23
|
}
|
|
16
24
|
},
|
|
17
25
|
"gateway": {
|
|
18
26
|
"darwin-arm64": {
|
|
19
27
|
"url": "https://github.com/NVIDIA/OpenShell/releases/download/v0.0.116/openshell-gateway-aarch64-apple-darwin.tar.gz",
|
|
20
28
|
"sha256": "f192d3d737c125264e13ef73458541df2ca6a9eb2fa599736a7f2587d5d2ce8d"
|
|
29
|
+
},
|
|
30
|
+
"linux-arm64": {
|
|
31
|
+
"url": "https://github.com/NVIDIA/OpenShell/releases/download/v0.0.116/openshell-gateway-aarch64-unknown-linux-gnu.tar.gz",
|
|
32
|
+
"sha256": "292c379193a339220234ffea585350901468bb8f4076e2076bc074e8ed18974b"
|
|
33
|
+
},
|
|
34
|
+
"linux-x64": {
|
|
35
|
+
"url": "https://github.com/NVIDIA/OpenShell/releases/download/v0.0.116/openshell-gateway-x86_64-unknown-linux-gnu.tar.gz",
|
|
36
|
+
"sha256": "59c6da724eae7a00c28826f9191efbdf4fbaa5c768afdc8dea6a80a949ebcc89"
|
|
21
37
|
}
|
|
22
38
|
},
|
|
23
39
|
"gatewayImage": "ghcr.io/nvidia/openshell/gateway:0.0.116@sha256:05cf77bbb022a739aed6f22daa0e7e164415f4ab273b5f84319e46d91eb8f645"
|
package/release/operator.md
CHANGED
|
@@ -9,6 +9,17 @@ registry images by digest. Local development image IDs cannot be downloaded. The
|
|
|
9
9
|
package is named `@clawscarf/cli` and exposes the `clawscarf` command. Development archives
|
|
10
10
|
remain private; the release candidate builder makes the package publishable. [Release contents](README.md) defines the publication model.
|
|
11
11
|
|
|
12
|
+
## Install from npm
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
npm install -g @clawscarf/cli@next
|
|
16
|
+
clawscarf configure
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The `next` tag selects the current alpha. Use an exact version instead when needed.
|
|
20
|
+
npm installs the CLI dependencies; runtime images and tools are fetched during setup.
|
|
21
|
+
See [release contents](README.md) for supported platforms and verification.
|
|
22
|
+
|
|
12
23
|
## Run the archive
|
|
13
24
|
|
|
14
25
|
Verify the archive against its accompanying `SHA256SUMS`, then extract it into a new
|
|
@@ -28,7 +39,8 @@ Dependencies are installed from the included frozen lockfile. Its root importer
|
|
|
28
39
|
contains only the production dependencies referenced by the staged operator;
|
|
29
40
|
publisher and browser dependencies are omitted. Locked transitive versions are retained.
|
|
30
41
|
No TypeScript compiler, contributor source or build step is needed to run the commands.
|
|
31
|
-
|
|
42
|
+
Platform support is determined by the selected runtime definition. Published candidates
|
|
43
|
+
include macOS arm64 and Linux arm64/x86-64 tools; Windows runs the Linux CLI inside WSL2.
|
|
32
44
|
|
|
33
45
|
The installer reviews recipe settings before credentials, prepares the installation,
|
|
34
46
|
and offers **Start now**. It starts Docker services and protected OpenShell containers, then exits; closing
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"version": "0.1.0-alpha.2",
|
|
4
|
+
"sourceRevision": "dc08bf392bad89efabce65bdd56e93c508553203",
|
|
5
|
+
"platforms": [
|
|
6
|
+
"darwin-arm64",
|
|
7
|
+
"linux-arm64",
|
|
8
|
+
"linux-x64"
|
|
9
|
+
],
|
|
10
|
+
"images": {
|
|
11
|
+
"postgres": "postgres@sha256:742f40ea20b9ff2ff31db5458d127452988a2164df9e17441e191f3b72252193",
|
|
12
|
+
"gateway": "ghcr.io/clawscarf/clawscarf/runtime@sha256:01105abab6d0b6330b55022187dd3367d552c2b66f6ddca5c0bb0279740a9bd3",
|
|
13
|
+
"companion": "ghcr.io/clawscarf/clawscarf/companion@sha256:1cb04a8c4ec5a65c74095b54dfa63a0154621158348f7e8315b30e0679d8a3d0",
|
|
14
|
+
"openshellClient": "ghcr.io/clawscarf/clawscarf/openshell-client@sha256:9aef63fd71cf55b8eb3971db1f49f2f5c9a467f782b699059f599dce2ea3beb4",
|
|
15
|
+
"relay": "ghcr.io/clawscarf/clawscarf/browser-relay@sha256:a80196a2dcc9a7835947ba69bd75c7e704db1b5cedac28bbc8670a675eeb5dec",
|
|
16
|
+
"models": "ghcr.io/berriai/litellm:v1.100.1@sha256:a3715fa7ad8387941ab697259bd2881d68931657247a41984f90fae6d11c62bf",
|
|
17
|
+
"browser": {
|
|
18
|
+
"chromium": "ghcr.io/clawscarf/clawscarf/browser@sha256:6c8e0302ad8ce118440f4794772149cf4a621e9fa9d580492e24269efcc7618d",
|
|
19
|
+
"node": "ghcr.io/clawscarf/clawscarf/browser-node@sha256:47c9f847167eb8a9956b600f4f97310ede7428833f60bdbacfd3c0f91fee7da6",
|
|
20
|
+
"dns": "ghcr.io/clawscarf/clawscarf/browser-dns@sha256:f83d0bc00f8f71d6d809b5057eb5edbf4573b5e1565a8292dbe36021802c4c0b",
|
|
21
|
+
"egress": "ghcr.io/clawscarf/clawscarf/browser-egress@sha256:a863dcfe890596aa8824d2c35e503afe5ddeeb763d3eef83ce582eb4ea6fa595"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"tools": {
|
|
25
|
+
"openshell": {
|
|
26
|
+
"version": "0.0.116",
|
|
27
|
+
"cli": {
|
|
28
|
+
"darwin-arm64": {
|
|
29
|
+
"file": "tools/darwin-arm64/openshell",
|
|
30
|
+
"sha256": "0baeeffe0e4c184b08fde910ac9e8815fb0b8cfb808e49c0e634d7db65fb03bb",
|
|
31
|
+
"url": "https://github.com/clawscarf/clawscarf/releases/download/v0.1.0-alpha.2/openshell-darwin-arm64"
|
|
32
|
+
},
|
|
33
|
+
"linux-arm64": {
|
|
34
|
+
"file": "tools/linux-arm64/openshell",
|
|
35
|
+
"sha256": "84df9f059b16b66c83748606cc87d9edcda84b57effea19543f5c368aba7eb18",
|
|
36
|
+
"url": "https://github.com/clawscarf/clawscarf/releases/download/v0.1.0-alpha.2/openshell-linux-arm64"
|
|
37
|
+
},
|
|
38
|
+
"linux-x64": {
|
|
39
|
+
"file": "tools/linux-x64/openshell",
|
|
40
|
+
"sha256": "24e85062073d512d1951c76cd3890b7bce1ab01cc36a08f88b3b43c067a402da",
|
|
41
|
+
"url": "https://github.com/clawscarf/clawscarf/releases/download/v0.1.0-alpha.2/openshell-linux-x64"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"gateway": {
|
|
45
|
+
"darwin-arm64": {
|
|
46
|
+
"file": "tools/darwin-arm64/openshell-gateway",
|
|
47
|
+
"sha256": "298706259ef18350f334c222e981e91583558511d50bce22727c689d261203e6",
|
|
48
|
+
"url": "https://github.com/clawscarf/clawscarf/releases/download/v0.1.0-alpha.2/openshell-gateway-darwin-arm64"
|
|
49
|
+
},
|
|
50
|
+
"linux-arm64": {
|
|
51
|
+
"file": "tools/linux-arm64/openshell-gateway",
|
|
52
|
+
"sha256": "0e660428e655e7481f34ba8a4b351554400baf791863d32555c98dddb3f09ae2",
|
|
53
|
+
"url": "https://github.com/clawscarf/clawscarf/releases/download/v0.1.0-alpha.2/openshell-gateway-linux-arm64"
|
|
54
|
+
},
|
|
55
|
+
"linux-x64": {
|
|
56
|
+
"file": "tools/linux-x64/openshell-gateway",
|
|
57
|
+
"sha256": "780fc7ad871e2163f3fb866a2d0254ee682fc0d83e6261a84b350c8dcdd9f47b",
|
|
58
|
+
"url": "https://github.com/clawscarf/clawscarf/releases/download/v0.1.0-alpha.2/openshell-gateway-linux-x64"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
package/scripts/controller.js
CHANGED
|
@@ -11,6 +11,7 @@ const settingsSchema = z.strictObject({
|
|
|
11
11
|
port: z.number().int().min(1024).max(65535),
|
|
12
12
|
gateway: z.string().min(1),
|
|
13
13
|
cli: z.string().min(1),
|
|
14
|
+
hostGatewayIp: z.ipv4().optional(),
|
|
14
15
|
});
|
|
15
16
|
const releaseInput = JSON.parse(await readFile(new URL("../release/components.json", import.meta.url), "utf8"));
|
|
16
17
|
const release = z
|
|
@@ -75,6 +76,7 @@ gateway_id = ${JSON.stringify(settings.name)}
|
|
|
75
76
|
ttl_secs = 0
|
|
76
77
|
[openshell.drivers.docker]
|
|
77
78
|
network_name = ${JSON.stringify(settings.name)}
|
|
79
|
+
${settings.hostGatewayIp ? `host_gateway_ip = ${JSON.stringify(settings.hostGatewayIp)}` : ""}
|
|
78
80
|
sandbox_namespace = ${JSON.stringify(settings.name)}
|
|
79
81
|
supervisor_image = ${JSON.stringify(release.supervisorImage)}
|
|
80
82
|
image_pull_policy = "IfNotPresent"
|
|
@@ -91,6 +93,7 @@ command
|
|
|
91
93
|
.requiredOption("--directory <path>", "New private controller directory")
|
|
92
94
|
.requiredOption("--gateway <path>", "Verified openshell-gateway executable")
|
|
93
95
|
.requiredOption("--cli <path>", "Verified openshell executable")
|
|
96
|
+
.option("--host-gateway-ip <address>", "Controller address on the runtime bridge")
|
|
94
97
|
.option("--name <name>", "Isolated controller name", "clawscarf")
|
|
95
98
|
.option("--port <port>", "Loopback controller port", "17671")
|
|
96
99
|
.action(async (options) => {
|
|
@@ -101,6 +104,7 @@ command
|
|
|
101
104
|
port: Number(options.port),
|
|
102
105
|
gateway: resolve(options.gateway),
|
|
103
106
|
cli: resolve(options.cli),
|
|
107
|
+
hostGatewayIp: options.hostGatewayIp,
|
|
104
108
|
});
|
|
105
109
|
await verifyExecutable(settings.gateway);
|
|
106
110
|
await verifyExecutable(settings.cli);
|
|
@@ -115,6 +119,8 @@ command
|
|
|
115
119
|
"localhost",
|
|
116
120
|
"--server-san",
|
|
117
121
|
"host.openshell.internal",
|
|
122
|
+
"--server-san",
|
|
123
|
+
"controller.clawscarf.internal",
|
|
118
124
|
], { timeout: 30000 });
|
|
119
125
|
const mtls = join(directory, "config/openshell/gateways", settings.name, "mtls");
|
|
120
126
|
await mkdir(mtls, { recursive: true, mode: 0o700 });
|
|
@@ -41,7 +41,6 @@ export function browserNodeServices(state, directory, browserAddress, prepared)
|
|
|
41
41
|
image: state.input.relayImage,
|
|
42
42
|
user: String(process.getuid?.() ?? 1000),
|
|
43
43
|
networks: { machine: { ipv4_address: addresses.ingress }, default: {} },
|
|
44
|
-
extra_hosts: ["host.docker.internal:host-gateway"],
|
|
45
44
|
environment: {
|
|
46
45
|
CLAWSCARF_NODE_INGRESS_ADDRESS: addresses.ingress,
|
|
47
46
|
CLAWSCARF_NODE_GATEWAY_PORT: String(state.input.ports.native),
|
|
@@ -64,7 +64,7 @@ export async function ensureCertificates(directory) {
|
|
|
64
64
|
"-subj",
|
|
65
65
|
"/CN=ClawScarf local management",
|
|
66
66
|
"-addext",
|
|
67
|
-
"subjectAltName=DNS:localhost,DNS:host.docker.internal,IP:127.0.0.1",
|
|
67
|
+
"subjectAltName=DNS:localhost,DNS:host.docker.internal,DNS:models.clawscarf.internal,IP:127.0.0.1",
|
|
68
68
|
"-addext",
|
|
69
69
|
"basicConstraints=critical,CA:TRUE",
|
|
70
70
|
]);
|
|
@@ -6,7 +6,7 @@ import { resourceNames } from "./state.js";
|
|
|
6
6
|
import { run } from "./process.js";
|
|
7
7
|
import { modelGatewayServices } from "./model-gateway-compose.js";
|
|
8
8
|
import { postgresImage } from "./images.js";
|
|
9
|
-
export function composeConfiguration(state, directory, browserAddress, browserMachine) {
|
|
9
|
+
export function composeConfiguration(state, directory, controllerAddress, browserAddress, browserMachine, controllerSocketGroup = 0) {
|
|
10
10
|
const { input, ownerId } = state;
|
|
11
11
|
const names = resourceNames(state);
|
|
12
12
|
const privateDirectory = join(directory, "private");
|
|
@@ -23,7 +23,7 @@ export function composeConfiguration(state, directory, browserAddress, browserMa
|
|
|
23
23
|
const configuration = {
|
|
24
24
|
name: names.project,
|
|
25
25
|
services: {
|
|
26
|
-
...controllerServices(directory, state),
|
|
26
|
+
...controllerServices(directory, state, controllerAddress, controllerSocketGroup),
|
|
27
27
|
...modelGatewayServices(directory, state),
|
|
28
28
|
...(input.browser && browserAddress && browserMachine
|
|
29
29
|
? browserNodeServices(state, directory, browserAddress, browserMachine)
|
|
@@ -153,9 +153,7 @@ export function composeConfiguration(state, directory, browserAddress, browserMa
|
|
|
153
153
|
},
|
|
154
154
|
},
|
|
155
155
|
networks: {
|
|
156
|
-
|
|
157
|
-
? { runtime: { external: true, name: names.sandbox } }
|
|
158
|
-
: {}),
|
|
156
|
+
runtime: { external: true, name: names.sandbox },
|
|
159
157
|
default: { external: true, name: `${names.project}_default` },
|
|
160
158
|
...(input.browser
|
|
161
159
|
? {
|
|
@@ -187,8 +187,8 @@ export const localInput = z
|
|
|
187
187
|
export function parseLocalInput(value) {
|
|
188
188
|
return localInput.parse(value);
|
|
189
189
|
}
|
|
190
|
-
export function managementOrigin(
|
|
191
|
-
return
|
|
190
|
+
export function managementOrigin() {
|
|
191
|
+
return "https://localhost:18801";
|
|
192
192
|
}
|
|
193
193
|
function mountedPrivateFile(directory, path, name) {
|
|
194
194
|
absolutePath.parse(path);
|
|
@@ -224,10 +224,10 @@ export function generateLocalConfiguration(options) {
|
|
|
224
224
|
port: 18801,
|
|
225
225
|
},
|
|
226
226
|
runtime: {
|
|
227
|
-
origin: `http://
|
|
228
|
-
managementOrigin: managementOrigin(
|
|
227
|
+
origin: `http://application:${String(input.ports.native)}`,
|
|
228
|
+
managementOrigin: managementOrigin(),
|
|
229
229
|
widgetOrigin,
|
|
230
|
-
widgetUpstream: `http://
|
|
230
|
+
widgetUpstream: `http://widgets:${String(input.ports.nativeWidgets)}`,
|
|
231
231
|
},
|
|
232
232
|
...(input.team.certificateFile
|
|
233
233
|
? {
|
|
@@ -2,13 +2,14 @@ import { join } from "node:path";
|
|
|
2
2
|
import { openshellGatewayImage } from "./images.js";
|
|
3
3
|
import { resourceNames } from "./state.js";
|
|
4
4
|
/** OpenShell alone receives Docker authority. Forwarders receive only client credentials. */
|
|
5
|
-
export function controllerServices(directory, state) {
|
|
5
|
+
export function controllerServices(directory, state, address, socketGroup) {
|
|
6
6
|
const controller = join(directory, "controller");
|
|
7
7
|
const { input } = state;
|
|
8
8
|
const name = resourceNames(state).sandbox;
|
|
9
9
|
const port = input.ports.controller;
|
|
10
10
|
const forward = (target, port) => ({
|
|
11
11
|
image: input.openshellClientImage,
|
|
12
|
+
user: `${String(process.getuid?.() ?? 1000)}:${String(process.getgid?.() ?? 1000)}`,
|
|
12
13
|
init: true,
|
|
13
14
|
read_only: true,
|
|
14
15
|
cap_drop: ["ALL"],
|
|
@@ -21,23 +22,31 @@ export function controllerServices(directory, state) {
|
|
|
21
22
|
XDG_DATA_HOME: "/tmp/data",
|
|
22
23
|
},
|
|
23
24
|
volumes: [`${join(controller, "config")}:/controller/config:ro`],
|
|
24
|
-
extra_hosts: ["host.openshell.internal:host-gateway"],
|
|
25
25
|
command: [
|
|
26
26
|
"forward",
|
|
27
|
-
"
|
|
27
|
+
"service",
|
|
28
|
+
"--target-port",
|
|
29
|
+
String(port),
|
|
30
|
+
"--local",
|
|
28
31
|
`0.0.0.0:${String(port)}`,
|
|
29
32
|
target,
|
|
30
33
|
"--gateway",
|
|
31
34
|
name,
|
|
32
35
|
"--gateway-endpoint",
|
|
33
|
-
`https://
|
|
36
|
+
`https://controller.clawscarf.internal:${String(input.ports.controller)}`,
|
|
34
37
|
],
|
|
35
38
|
ports: [`127.0.0.1:${String(port)}:${String(port)}`],
|
|
36
39
|
});
|
|
37
40
|
return {
|
|
38
41
|
controller: {
|
|
39
42
|
image: openshellGatewayImage,
|
|
40
|
-
user:
|
|
43
|
+
user: `${String(process.getuid?.() ?? 1000)}:${String(process.getgid?.() ?? 1000)}`,
|
|
44
|
+
// Desktop exposes a root-group socket; Linux Engine uses the host socket's group.
|
|
45
|
+
group_add: [...new Set(["0", String(socketGroup)])],
|
|
46
|
+
networks: {
|
|
47
|
+
default: { aliases: ["controller.clawscarf.internal"] },
|
|
48
|
+
runtime: { ipv4_address: address },
|
|
49
|
+
},
|
|
41
50
|
command: ["--config", join(controller, "gateway.toml")],
|
|
42
51
|
environment: {
|
|
43
52
|
XDG_CONFIG_HOME: join(controller, "config"),
|
|
@@ -51,7 +60,6 @@ export function controllerServices(directory, state) {
|
|
|
51
60
|
"/var/run/docker.sock:/var/run/docker.sock",
|
|
52
61
|
],
|
|
53
62
|
ports: [`127.0.0.1:${String(port)}:${String(port)}`],
|
|
54
|
-
extra_hosts: ["host.openshell.internal:host-gateway"],
|
|
55
63
|
},
|
|
56
64
|
application: forward(name, input.ports.native),
|
|
57
65
|
widgets: forward(name, input.ports.nativeWidgets),
|
|
@@ -28,6 +28,12 @@ export function modelGatewayServices(directory, state) {
|
|
|
28
28
|
},
|
|
29
29
|
models: {
|
|
30
30
|
image: input.image,
|
|
31
|
+
user: `${String(process.getuid?.() ?? 1000)}:${String(process.getgid?.() ?? 1000)}`,
|
|
32
|
+
environment: { HOME: "/tmp" },
|
|
33
|
+
networks: {
|
|
34
|
+
default: {},
|
|
35
|
+
runtime: { aliases: ["models.clawscarf.internal"] },
|
|
36
|
+
},
|
|
31
37
|
init: true,
|
|
32
38
|
read_only: true,
|
|
33
39
|
cap_drop: ["ALL"],
|
|
@@ -43,6 +43,14 @@ export async function prepareModelGateway(directory, state, options = {}) {
|
|
|
43
43
|
return;
|
|
44
44
|
const loaded = await loadGatewayConfiguration(input.configurationFile, input.upstreamEnvironmentFile);
|
|
45
45
|
const root = join(directory, "private/models");
|
|
46
|
+
let baseUrl = "https://models.clawscarf.internal:4000/v1";
|
|
47
|
+
if (options.replaceConfiguration) {
|
|
48
|
+
const current = configurationSchema.parse(JSON.parse(await readFile(join(root, "native.json"), "utf8")));
|
|
49
|
+
if (current.mode !== "litellm")
|
|
50
|
+
throw new LocalSetupError("invalid_model_setup", "Expected an existing model gateway.");
|
|
51
|
+
// Model choices do not change the installation's retained network endpoint.
|
|
52
|
+
baseUrl = current.baseUrl;
|
|
53
|
+
}
|
|
46
54
|
await mkdir(root, { recursive: true, mode: 0o700 });
|
|
47
55
|
for (const [name, prefix] of [
|
|
48
56
|
["master-key", "sk-"],
|
|
@@ -74,7 +82,7 @@ export async function prepareModelGateway(directory, state, options = {}) {
|
|
|
74
82
|
await publish(join(root, "models.json"), JSON.stringify(liteLlmConfiguration(loaded.configuration)));
|
|
75
83
|
await publish(join(root, "native.json"), JSON.stringify({
|
|
76
84
|
...loaded.configuration,
|
|
77
|
-
baseUrl
|
|
85
|
+
baseUrl,
|
|
78
86
|
}));
|
|
79
87
|
}
|
|
80
88
|
export async function prepareModelCredential(directory, state) {
|
|
@@ -264,6 +264,10 @@ export async function ensureLocalNetworks(directory, state, command = run) {
|
|
|
264
264
|
"create",
|
|
265
265
|
"--driver",
|
|
266
266
|
"bridge",
|
|
267
|
+
// Docker chooses a free subnet; declaring its size permits static endpoints.
|
|
268
|
+
...(intent.purpose !== "companion"
|
|
269
|
+
? ["--subnet", "0.0.0.0/24"]
|
|
270
|
+
: []),
|
|
267
271
|
...(intent.purpose === "runtime" ? ["--attachable"] : []),
|
|
268
272
|
...(["browser", "machine"].includes(intent.purpose)
|
|
269
273
|
? [
|
|
@@ -352,3 +356,20 @@ export async function observedBrowserMachineAddresses(directory, state, command
|
|
|
352
356
|
changed();
|
|
353
357
|
return { node: observed.isolated.address, ingress, dns };
|
|
354
358
|
}
|
|
359
|
+
/** Stable address on the owned runtime bridge for the containerized OpenShell controller. */
|
|
360
|
+
export async function observedControllerAddress(directory, state) {
|
|
361
|
+
await verifyLocalNetworks(directory, state);
|
|
362
|
+
const configs = z
|
|
363
|
+
.array(z.object({ Subnet: z.string(), Gateway: z.string() }))
|
|
364
|
+
.parse(JSON.parse(await run("docker", [
|
|
365
|
+
"network",
|
|
366
|
+
"inspect",
|
|
367
|
+
resourceNames(state).sandbox,
|
|
368
|
+
"--format",
|
|
369
|
+
"{{json .IPAM.Config}}",
|
|
370
|
+
])));
|
|
371
|
+
const config = configs.find((item) => isIP(item.Gateway) === 4);
|
|
372
|
+
if (!config)
|
|
373
|
+
changed();
|
|
374
|
+
return reservedAddress(config).address;
|
|
375
|
+
}
|
|
@@ -8,10 +8,10 @@ import { prepareRelay } from "./relay.js";
|
|
|
8
8
|
import { prepareRuntimePolicy } from "./policy.js";
|
|
9
9
|
import { prepareBrowser, initializeBrowserVolume } from "./browser.js";
|
|
10
10
|
import { readTeamMaterials, prepareTeamFiles } from "./team.js";
|
|
11
|
-
import { readFile, lstat } from "node:fs/promises";
|
|
11
|
+
import { readFile, lstat, stat } from "node:fs/promises";
|
|
12
12
|
import { join, resolve } from "node:path";
|
|
13
13
|
import { prepareInitialModels, withInitialModels, } from "./models.js";
|
|
14
|
-
import { ensureLocalNetworks } from "./networks.js";
|
|
14
|
+
import { ensureLocalNetworks, observedControllerAddress } from "./networks.js";
|
|
15
15
|
import { nodeEntrypoint } from "./entrypoint.js";
|
|
16
16
|
import { ensureCertificates } from "./certificates.js";
|
|
17
17
|
import { z } from "zod";
|
|
@@ -29,8 +29,9 @@ export async function prepareLocal(directoryInput, inputValue, capabilities) {
|
|
|
29
29
|
const input = parseLocalInput(inputValue);
|
|
30
30
|
const connections = await loadInitialConnections(input.connections);
|
|
31
31
|
const teamMaterials = await readTeamMaterials(input.team);
|
|
32
|
-
if (
|
|
33
|
-
|
|
32
|
+
if (!["darwin", "linux"].includes(process.platform) ||
|
|
33
|
+
!["arm64", "x64"].includes(process.arch))
|
|
34
|
+
throw new LocalSetupError("platform_unqualified", "Use macOS or Linux (including WSL2) with Linux Docker containers.");
|
|
34
35
|
for (const image of [
|
|
35
36
|
input.runtimeImage,
|
|
36
37
|
input.openshellClientImage,
|
|
@@ -71,6 +72,7 @@ export async function prepareLocal(directoryInput, inputValue, capabilities) {
|
|
|
71
72
|
const connectionsEndpoint = await prepareInitialConnections(directory, connections);
|
|
72
73
|
await prepareModelGateway(directory, state);
|
|
73
74
|
await ensureLocalNetworks(directory, state);
|
|
75
|
+
const controllerAddress = await observedControllerAddress(directory, state);
|
|
74
76
|
const browser = await prepareBrowser(directory, state);
|
|
75
77
|
const browserMachine = browser
|
|
76
78
|
? await prepareBrowserNode(directory, state, browser.token)
|
|
@@ -86,7 +88,9 @@ export async function prepareLocal(directoryInput, inputValue, capabilities) {
|
|
|
86
88
|
await ensureOwnedVolume(names.browserVolume, state.ownerId);
|
|
87
89
|
await initializeBrowserVolume(state, browser.token);
|
|
88
90
|
}
|
|
89
|
-
await ensurePrivateFile(join(directory, "compose.json"), JSON.stringify(composeConfiguration(state, directory, browser?.address, browserMachine
|
|
91
|
+
await ensurePrivateFile(join(directory, "compose.json"), JSON.stringify(composeConfiguration(state, directory, controllerAddress, browser?.address, browserMachine, process.platform === "linux"
|
|
92
|
+
? (await stat("/var/run/docker.sock")).gid
|
|
93
|
+
: 0), null, 2));
|
|
90
94
|
await prepareModelCredential(directory, state);
|
|
91
95
|
const models = await prepareInitialModels(directory, input.models);
|
|
92
96
|
await prepareRuntimePolicy(directory, models, connectionsEndpoint);
|
|
@@ -151,6 +155,8 @@ export async function prepareLocal(directoryInput, inputValue, capabilities) {
|
|
|
151
155
|
input.openshellGateway,
|
|
152
156
|
"--cli",
|
|
153
157
|
input.openshellCli,
|
|
158
|
+
"--host-gateway-ip",
|
|
159
|
+
controllerAddress,
|
|
154
160
|
"--name",
|
|
155
161
|
names.sandbox,
|
|
156
162
|
"--port",
|
|
@@ -66,7 +66,11 @@ export const terminalPrompts = {
|
|
|
66
66
|
note: clack.note,
|
|
67
67
|
async openBrowser(url) {
|
|
68
68
|
try {
|
|
69
|
-
await promisify(execFile)(process.platform === "darwin"
|
|
69
|
+
await promisify(execFile)(process.platform === "darwin"
|
|
70
|
+
? "open"
|
|
71
|
+
: process.env.WSL_DISTRO_NAME
|
|
72
|
+
? "explorer.exe"
|
|
73
|
+
: "xdg-open", [url], { timeout: 5000 });
|
|
70
74
|
}
|
|
71
75
|
catch {
|
|
72
76
|
process.stderr.write("Could not open a browser. Open the link above manually.\n");
|
|
@@ -12,8 +12,9 @@ import { acquireRuntimeTools } from "./runtime.js";
|
|
|
12
12
|
import { InstallationError } from "./errors.js";
|
|
13
13
|
/** No configuration, credentials or cloud account is needed for these checks. */
|
|
14
14
|
export async function checkHost(command = run) {
|
|
15
|
-
if (
|
|
16
|
-
|
|
15
|
+
if (!["darwin", "linux"].includes(process.platform) ||
|
|
16
|
+
!["arm64", "x64"].includes(process.arch))
|
|
17
|
+
throw new InstallationError("unsupported_platform", "Use macOS or Linux (including WSL2), with an ARM64 or x86-64 processor and Linux Docker containers. Run the Windows CLI inside WSL2.");
|
|
17
18
|
let os;
|
|
18
19
|
try {
|
|
19
20
|
os = await command("docker", ["info", "--format", "{{.OSType}}"]);
|
|
@@ -23,8 +24,8 @@ export async function checkHost(command = run) {
|
|
|
23
24
|
error.commandFailure?.reason === "spawn" &&
|
|
24
25
|
error.commandFailure.systemCode === "ENOENT";
|
|
25
26
|
throw new InstallationError("unavailable", missing
|
|
26
|
-
? "Docker is not installed or is not on PATH. Install Docker
|
|
27
|
-
: "Cannot reach Docker. Start Docker
|
|
27
|
+
? "Docker is not installed or is not on PATH. Install Docker Engine with Compose or Docker Desktop, then run configure again."
|
|
28
|
+
: "Cannot reach Docker. Start Docker and check that your user can access its socket, then try again.");
|
|
28
29
|
}
|
|
29
30
|
if (os.trim() !== "linux")
|
|
30
31
|
throw new InstallationError("unsupported_platform", "Docker must run Linux containers.");
|
|
@@ -32,8 +33,12 @@ export async function checkHost(command = run) {
|
|
|
32
33
|
await command("docker", ["compose", "version"]);
|
|
33
34
|
}
|
|
34
35
|
catch {
|
|
35
|
-
throw new InstallationError("unavailable", "Docker Compose is unavailable. Install or update Docker Desktop, then try again.");
|
|
36
|
+
throw new InstallationError("unavailable", "Docker Compose is unavailable. Install the Docker Compose plugin or update Docker Desktop, then try again.");
|
|
36
37
|
}
|
|
38
|
+
const version = (await command("docker", ["version", "--format", "{{.Server.Version}}"])).trim();
|
|
39
|
+
const major = Number(/^([0-9]+)\./.exec(version)?.[1]);
|
|
40
|
+
if (!Number.isInteger(major) || major < 29)
|
|
41
|
+
throw new InstallationError("unsupported_platform", "Docker Engine 29 or newer is required for automatic subnet allocation with fixed service addresses. Update Docker Engine or Docker Desktop, then try again.");
|
|
37
42
|
}
|
|
38
43
|
/** Stream only Docker's layer progress, never registry error payloads or credentials. */
|
|
39
44
|
export function pullImage(image, report, signal) {
|
|
@@ -3,7 +3,7 @@ import { hostedOidc, hostedConnections } from "../cloud/registration.js";
|
|
|
3
3
|
import { dirname, resolve, join } from "node:path";
|
|
4
4
|
import { loadGatewayConfiguration } from "../deployment/model-gateway.js";
|
|
5
5
|
import { createServer } from "node:net";
|
|
6
|
-
import { releaseSchema } from "../release/definition.js";
|
|
6
|
+
import { releaseSchema, releaseTools } from "../release/definition.js";
|
|
7
7
|
import { parseLocalInput, } from "../deployment/configuration.js";
|
|
8
8
|
import { loadInitialModels } from "../deployment/models.js";
|
|
9
9
|
import { loadInitialConnections, readInitialConnectionToken, } from "../deployment/connections.js";
|
|
@@ -49,10 +49,11 @@ export async function resolveInstallation(configFile, internalPorts) {
|
|
|
49
49
|
if (!release.platforms.some((platform) => platform === `${process.platform}-${process.arch}`))
|
|
50
50
|
throw new InstallationError("unsupported_platform", "This release does not support this host platform.");
|
|
51
51
|
const toolBase = dirname(releasePath);
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
await verifyReleaseTool(
|
|
52
|
+
const tools = releaseTools(release);
|
|
53
|
+
const cli = resolve(toolBase, tools.cli.file);
|
|
54
|
+
const gateway = resolve(toolBase, tools.gateway.file);
|
|
55
|
+
await verifyReleaseTool(cli, tools.cli.sha256);
|
|
56
|
+
await verifyReleaseTool(gateway, tools.gateway.sha256);
|
|
56
57
|
const [controller, management, native, nativeWidgets, database, browser, models,] = internalPorts;
|
|
57
58
|
const inputs = {};
|
|
58
59
|
async function inputFile(value, secret) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { chmod, copyFile, mkdir, open, rename, rm, writeFile, } from "node:fs/promises";
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
|
-
import { releaseSchema } from "../release/definition.js";
|
|
4
|
+
import { releaseSchema, releaseTools } from "../release/definition.js";
|
|
5
5
|
import { readJson, verifyReleaseTool } from "./files.js";
|
|
6
6
|
import { InstallationError } from "./errors.js";
|
|
7
7
|
/** Installation-owned paths survive npm cache cleanup and later CLI updates. */
|
|
@@ -10,7 +10,7 @@ export async function retainRuntime(source, directory) {
|
|
|
10
10
|
const target = join(directory, "runtime");
|
|
11
11
|
await mkdir(join(target, "tools"), { recursive: true, mode: 0o700 });
|
|
12
12
|
for (const name of ["cli", "gateway"]) {
|
|
13
|
-
const tool = release
|
|
13
|
+
const tool = releaseTools(release)[name];
|
|
14
14
|
const original = resolve(dirname(source), tool.file);
|
|
15
15
|
tool.file = `tools/openshell${name === "gateway" ? "-gateway" : ""}`;
|
|
16
16
|
try {
|
|
@@ -34,7 +34,7 @@ export async function acquireRuntimeTools(releaseFile, options) {
|
|
|
34
34
|
const release = releaseSchema.parse(await readJson(releaseFile));
|
|
35
35
|
for (const name of ["cli", "gateway"]) {
|
|
36
36
|
options.signal?.throwIfAborted();
|
|
37
|
-
const tool = release
|
|
37
|
+
const tool = releaseTools(release)[name];
|
|
38
38
|
const file = resolve(dirname(releaseFile), tool.file);
|
|
39
39
|
try {
|
|
40
40
|
await verifyReleaseTool(file, tool.sha256);
|
|
@@ -15,12 +15,18 @@ const file = z.strictObject({
|
|
|
15
15
|
}, "Tool downloads require HTTPS without credentials.")
|
|
16
16
|
.optional(),
|
|
17
17
|
});
|
|
18
|
+
export const hostPlatformSchema = z.enum([
|
|
19
|
+
"darwin-arm64",
|
|
20
|
+
"linux-arm64",
|
|
21
|
+
"linux-x64",
|
|
22
|
+
]);
|
|
23
|
+
const tool = z.union([file, z.partialRecord(hostPlatformSchema, file)]);
|
|
18
24
|
/** Pinned runtime metadata, independent of recipe defaults and deployment state. */
|
|
19
25
|
export const releaseSchema = z.strictObject({
|
|
20
26
|
schemaVersion: z.literal(1),
|
|
21
27
|
version: z.string().regex(/^\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?$/),
|
|
22
28
|
sourceRevision: z.string().regex(/^[a-f0-9]{40}$/),
|
|
23
|
-
platforms: z.array(
|
|
29
|
+
platforms: z.array(hostPlatformSchema).min(1),
|
|
24
30
|
images: z
|
|
25
31
|
.strictObject({
|
|
26
32
|
postgres: z.literal(postgresImage),
|
|
@@ -44,8 +50,29 @@ export const releaseSchema = z.strictObject({
|
|
|
44
50
|
tools: z.strictObject({
|
|
45
51
|
openshell: z.strictObject({
|
|
46
52
|
version: z.string().min(1),
|
|
47
|
-
cli:
|
|
48
|
-
gateway:
|
|
53
|
+
cli: tool,
|
|
54
|
+
gateway: tool,
|
|
49
55
|
}),
|
|
50
56
|
}),
|
|
51
57
|
});
|
|
58
|
+
/** Single-platform development bundles and multi-platform published bundles share resolution. */
|
|
59
|
+
export function releaseTools(release, platform = `${process.platform}-${process.arch}`) {
|
|
60
|
+
const host = hostPlatformSchema.parse(platform);
|
|
61
|
+
if (!release.platforms.includes(host))
|
|
62
|
+
throw new Error(`Runtime ${release.version} does not include ${host}.`);
|
|
63
|
+
const select = (value) => {
|
|
64
|
+
if ("file" in value) {
|
|
65
|
+
if (release.platforms.length !== 1)
|
|
66
|
+
throw new Error("Multi-platform runtimes require a tool for each platform.");
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
const selected = value[host];
|
|
70
|
+
if (!selected)
|
|
71
|
+
throw new Error(`Missing runtime tool for ${host}.`);
|
|
72
|
+
return selected;
|
|
73
|
+
};
|
|
74
|
+
return {
|
|
75
|
+
cli: select(release.tools.openshell.cli),
|
|
76
|
+
gateway: select(release.tools.openshell.gateway),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"schemaVersion": 1,
|
|
3
|
-
"version": "0.1.0-alpha.1",
|
|
4
|
-
"sourceRevision": "a53e95251321e61d8ffd6d06a6984f651c0b0db4",
|
|
5
|
-
"platforms": [
|
|
6
|
-
"darwin-arm64"
|
|
7
|
-
],
|
|
8
|
-
"images": {
|
|
9
|
-
"postgres": "postgres@sha256:742f40ea20b9ff2ff31db5458d127452988a2164df9e17441e191f3b72252193",
|
|
10
|
-
"gateway": "ghcr.io/clawscarf/clawscarf/runtime@sha256:eaa25c8e487970176b95de657df8bf4faff605f9f265ca760197800d9a1e5fcf",
|
|
11
|
-
"companion": "ghcr.io/clawscarf/clawscarf/companion@sha256:97cfeb78ab56ba625b30aafe2249633d9b69f7f3c75de7116453385010e6281f",
|
|
12
|
-
"openshellClient": "ghcr.io/clawscarf/clawscarf/openshell-client@sha256:669f37f654926fc7714783cc8b1b76bae9666895c2a4da959580037d281ebf56",
|
|
13
|
-
"relay": "ghcr.io/clawscarf/clawscarf/browser-relay@sha256:5ee13e9496e3b76e076e91c59a861a10ad7a31a13b145384fba314d7f0b686b5",
|
|
14
|
-
"models": "ghcr.io/berriai/litellm:v1.100.1@sha256:a3715fa7ad8387941ab697259bd2881d68931657247a41984f90fae6d11c62bf",
|
|
15
|
-
"browser": {
|
|
16
|
-
"chromium": "ghcr.io/clawscarf/clawscarf/browser@sha256:28ca9e4007d3b7c1bb9cb8f4bbaf275d1bc36ee2744079326b151b1f9eec78fd",
|
|
17
|
-
"node": "ghcr.io/clawscarf/clawscarf/browser-node@sha256:2837d8b75df69fb39c7f7ca8fa68249d9de6e20d4e028213792de5f8f9ef1bd7",
|
|
18
|
-
"dns": "ghcr.io/clawscarf/clawscarf/browser-dns@sha256:9f14cb85df522014c2bfc068e2b5788568f26b6e8d948cebe1250aff7630847b",
|
|
19
|
-
"egress": "ghcr.io/clawscarf/clawscarf/browser-egress@sha256:bd819dffa4e1f60fbeed3b459a26b3b274300a4e5836bb90cbd080f6681d594c"
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
|
-
"tools": {
|
|
23
|
-
"openshell": {
|
|
24
|
-
"version": "0.0.116",
|
|
25
|
-
"cli": {
|
|
26
|
-
"file": "tools/openshell",
|
|
27
|
-
"sha256": "0baeeffe0e4c184b08fde910ac9e8815fb0b8cfb808e49c0e634d7db65fb03bb",
|
|
28
|
-
"url": "https://github.com/clawscarf/clawscarf/releases/download/v0.1.0-alpha.1/openshell-darwin-arm64"
|
|
29
|
-
},
|
|
30
|
-
"gateway": {
|
|
31
|
-
"file": "tools/openshell-gateway",
|
|
32
|
-
"sha256": "298706259ef18350f334c222e981e91583558511d50bce22727c689d261203e6",
|
|
33
|
-
"url": "https://github.com/clawscarf/clawscarf/releases/download/v0.1.0-alpha.1/openshell-gateway-darwin-arm64"
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|