@octos-org/octos 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -0
- package/bin/octos.js +43 -0
- package/install.js +270 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# @octos-org/octos
|
|
2
|
+
|
|
3
|
+
One-line installer for the [Octos](https://github.com/octos-org/octos) server — a
|
|
4
|
+
Rust-native, API-first Agentic OS.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npm install -g @octos-org/octos
|
|
8
|
+
octos serve
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
This package downloads the prebuilt release bundle for your platform and installs
|
|
12
|
+
the `octos` server **together with its bundled skills** (`news_fetch`,
|
|
13
|
+
`deep-search`, `deep_crawl`, `send_email`, `account_manager`, `voice`, `clock`,
|
|
14
|
+
`weather`). The skills are kept as siblings of the `octos` binary so that
|
|
15
|
+
`octos serve` can discover them at startup.
|
|
16
|
+
|
|
17
|
+
## Supported platforms
|
|
18
|
+
|
|
19
|
+
- macOS Apple Silicon (`darwin-arm64`)
|
|
20
|
+
- Linux x86_64 (`linux-x64`)
|
|
21
|
+
- Linux ARM64 (`linux-arm64`)
|
|
22
|
+
- Windows x64 (`win32-x64`)
|
|
23
|
+
|
|
24
|
+
macOS Intel is not supported (no prebuilt build is published).
|
|
25
|
+
|
|
26
|
+
## Environment overrides
|
|
27
|
+
|
|
28
|
+
- `OCTOS_SKIP_DOWNLOAD=1` — skip the postinstall download (offline / CI).
|
|
29
|
+
- `OCTOS_BUNDLE_URL=<url>` — install from a specific bundle URL (`file://` works).
|
|
30
|
+
- `HTTPS_PROXY` — honored when downloading.
|
|
31
|
+
|
|
32
|
+
## Alternatives
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Homebrew
|
|
36
|
+
brew install octos-org/tap/octos
|
|
37
|
+
|
|
38
|
+
# Shell installer (sets up octos serve as a service)
|
|
39
|
+
curl -fsSL https://github.com/octos-org/octos/releases/latest/download/install.sh | bash
|
|
40
|
+
```
|
package/bin/octos.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Launcher: spawn the real native `octos` binary that postinstall placed in
|
|
3
|
+
// vendor/, forwarding all args, stdio, and the exit code.
|
|
4
|
+
//
|
|
5
|
+
// The skills bundled next to it (vendor/news_fetch, deep-search, ...) are
|
|
6
|
+
// discovered by `octos serve` as siblings of this binary at runtime — so the
|
|
7
|
+
// native binary must run from vendor/, not be copied elsewhere.
|
|
8
|
+
|
|
9
|
+
"use strict";
|
|
10
|
+
|
|
11
|
+
const os = require("os");
|
|
12
|
+
const path = require("path");
|
|
13
|
+
const fs = require("fs");
|
|
14
|
+
const { spawnSync } = require("child_process");
|
|
15
|
+
|
|
16
|
+
const exeSuffix = os.platform() === "win32" ? ".exe" : "";
|
|
17
|
+
const binary = path.join(__dirname, "..", "vendor", "octos" + exeSuffix);
|
|
18
|
+
|
|
19
|
+
if (!fs.existsSync(binary)) {
|
|
20
|
+
console.error(
|
|
21
|
+
"[@octos-org/octos] native binary not found at " +
|
|
22
|
+
binary +
|
|
23
|
+
".\nThe postinstall download did not run (was the package installed with " +
|
|
24
|
+
"--ignore-scripts?).\nReinstall without --ignore-scripts, or run " +
|
|
25
|
+
"`node " +
|
|
26
|
+
path.join(__dirname, "..", "install.js") +
|
|
27
|
+
"` manually."
|
|
28
|
+
);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const result = spawnSync(binary, process.argv.slice(2), { stdio: "inherit" });
|
|
33
|
+
|
|
34
|
+
if (result.error) {
|
|
35
|
+
console.error("[@octos-org/octos] failed to launch octos: " + result.error.message);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Propagate a signal-terminated child as a non-zero exit; otherwise the code.
|
|
40
|
+
if (result.signal) {
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
process.exit(result.status === null ? 1 : result.status);
|
package/install.js
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// postinstall: download the prebuilt octos release bundle for this platform,
|
|
3
|
+
// extract every binary into vendor/, and assert the full skill set is present.
|
|
4
|
+
//
|
|
5
|
+
// The bundle ships `octos` alongside its 8 skill binaries. At `octos serve`
|
|
6
|
+
// startup, bootstrap discovers those skills as SIBLINGS of the resolved
|
|
7
|
+
// `octos` executable, so they must all land in the same dir (vendor/).
|
|
8
|
+
//
|
|
9
|
+
// Escapes:
|
|
10
|
+
// OCTOS_SKIP_DOWNLOAD=1 skip the download entirely (CI / offline installs)
|
|
11
|
+
// OCTOS_BUNDLE_URL=<url> override the download URL (file:// supported for tests)
|
|
12
|
+
|
|
13
|
+
"use strict";
|
|
14
|
+
|
|
15
|
+
const fs = require("fs");
|
|
16
|
+
const os = require("os");
|
|
17
|
+
const path = require("path");
|
|
18
|
+
const https = require("https");
|
|
19
|
+
const http = require("http");
|
|
20
|
+
const { spawnSync } = require("child_process");
|
|
21
|
+
const { URL } = require("url");
|
|
22
|
+
|
|
23
|
+
const VENDOR_DIR = path.join(__dirname, "vendor");
|
|
24
|
+
const REPO = "octos-org/octos";
|
|
25
|
+
|
|
26
|
+
// Every binary the release bundle is expected to contain. `octos` is the
|
|
27
|
+
// server; the rest are the bundled skills discovered as siblings at runtime.
|
|
28
|
+
const EXPECTED_BINS = [
|
|
29
|
+
"octos",
|
|
30
|
+
"news_fetch",
|
|
31
|
+
"deep-search",
|
|
32
|
+
"deep_crawl",
|
|
33
|
+
"send_email",
|
|
34
|
+
"account_manager",
|
|
35
|
+
"voice",
|
|
36
|
+
"clock",
|
|
37
|
+
"weather",
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
function fail(msg) {
|
|
41
|
+
console.error("\n[@octos-org/octos] install failed: " + msg + "\n");
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Map this Node platform/arch to the release triple + archive extension.
|
|
46
|
+
// Mirrors scripts/install.sh platform detection.
|
|
47
|
+
function resolveTarget() {
|
|
48
|
+
const platform = os.platform();
|
|
49
|
+
const arch = os.arch();
|
|
50
|
+
|
|
51
|
+
if (platform === "darwin") {
|
|
52
|
+
if (arch === "arm64") {
|
|
53
|
+
return { triple: "aarch64-apple-darwin", ext: "tar.gz" };
|
|
54
|
+
}
|
|
55
|
+
fail(
|
|
56
|
+
"octos requires Apple Silicon on macOS; no x86_64 macOS build is published."
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
if (platform === "linux") {
|
|
60
|
+
if (arch === "x64") {
|
|
61
|
+
return { triple: "x86_64-unknown-linux-gnu", ext: "tar.gz" };
|
|
62
|
+
}
|
|
63
|
+
if (arch === "arm64") {
|
|
64
|
+
return { triple: "aarch64-unknown-linux-gnu", ext: "tar.gz" };
|
|
65
|
+
}
|
|
66
|
+
fail("Unsupported Linux architecture: " + arch + " (need x64 or arm64).");
|
|
67
|
+
}
|
|
68
|
+
if (platform === "win32") {
|
|
69
|
+
if (arch === "x64") {
|
|
70
|
+
return { triple: "x86_64-pc-windows-msvc", ext: "zip" };
|
|
71
|
+
}
|
|
72
|
+
fail("Unsupported Windows architecture: " + arch + " (need x64).");
|
|
73
|
+
}
|
|
74
|
+
fail("Unsupported platform: " + platform);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Resolve the release tag from the package version. CI sets the package
|
|
78
|
+
// version to the released tag (minus the leading "v"), so the tag is
|
|
79
|
+
// "v" + version. The "0.0.0-managed" placeholder is never published.
|
|
80
|
+
function resolveTag() {
|
|
81
|
+
const version = require("./package.json").version;
|
|
82
|
+
if (version === "0.0.0-managed") {
|
|
83
|
+
fail(
|
|
84
|
+
"package version is the unmanaged placeholder (0.0.0-managed); " +
|
|
85
|
+
"this build was not produced by the publish workflow. " +
|
|
86
|
+
"Set OCTOS_BUNDLE_URL to install manually."
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
return version.startsWith("v") ? version : "v" + version;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function bundleUrl(target) {
|
|
93
|
+
if (process.env.OCTOS_BUNDLE_URL) {
|
|
94
|
+
return process.env.OCTOS_BUNDLE_URL;
|
|
95
|
+
}
|
|
96
|
+
const tag = resolveTag();
|
|
97
|
+
return (
|
|
98
|
+
"https://github.com/" +
|
|
99
|
+
REPO +
|
|
100
|
+
"/releases/download/" +
|
|
101
|
+
tag +
|
|
102
|
+
"/octos-bundle-" +
|
|
103
|
+
target.triple +
|
|
104
|
+
"." +
|
|
105
|
+
target.ext
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Download to a file, following redirects, honoring HTTPS_PROXY when set.
|
|
110
|
+
function download(urlStr, destFile, redirects, cb) {
|
|
111
|
+
if (redirects > 10) {
|
|
112
|
+
return cb(new Error("too many redirects"));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
let url;
|
|
116
|
+
try {
|
|
117
|
+
url = new URL(urlStr);
|
|
118
|
+
} catch (e) {
|
|
119
|
+
return cb(new Error("invalid URL: " + urlStr));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// file:// override — copy locally (used by tests / offline installs).
|
|
123
|
+
// Use fileURLToPath so Windows `file:///C:/...` maps correctly (pathname
|
|
124
|
+
// would yield `/C:/...`).
|
|
125
|
+
if (url.protocol === "file:") {
|
|
126
|
+
try {
|
|
127
|
+
fs.copyFileSync(require("url").fileURLToPath(url), destFile);
|
|
128
|
+
return cb(null);
|
|
129
|
+
} catch (e) {
|
|
130
|
+
return cb(new Error("could not read " + urlStr + ": " + e.message));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Direct request only. Corporate HTTP/HTTPS proxies are NOT supported here
|
|
135
|
+
// (Node core has no CONNECT helper, and absolute-form GET to an HTTP proxy
|
|
136
|
+
// fails for https targets). Behind a proxy: pre-download the bundle and point
|
|
137
|
+
// the installer at it with OCTOS_BUNDLE_URL=file:///path, or set
|
|
138
|
+
// OCTOS_SKIP_DOWNLOAD=1 and place the binaries under vendor/ yourself.
|
|
139
|
+
const transport = url.protocol === "https:" ? https : http;
|
|
140
|
+
const requestOptions = {
|
|
141
|
+
protocol: url.protocol,
|
|
142
|
+
hostname: url.hostname,
|
|
143
|
+
port: url.port,
|
|
144
|
+
path: url.pathname + url.search,
|
|
145
|
+
headers: { "User-Agent": "octos-npm-installer" },
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
transport
|
|
149
|
+
.get(requestOptions, (res) => {
|
|
150
|
+
// Follow redirects (GitHub release assets redirect to a CDN).
|
|
151
|
+
if (
|
|
152
|
+
res.statusCode >= 300 &&
|
|
153
|
+
res.statusCode < 400 &&
|
|
154
|
+
res.headers.location
|
|
155
|
+
) {
|
|
156
|
+
res.resume();
|
|
157
|
+
const next = new URL(res.headers.location, urlStr).toString();
|
|
158
|
+
return download(next, destFile, redirects + 1, cb);
|
|
159
|
+
}
|
|
160
|
+
if (res.statusCode !== 200) {
|
|
161
|
+
res.resume();
|
|
162
|
+
return cb(
|
|
163
|
+
new Error("HTTP " + res.statusCode + " fetching " + urlStr)
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
const out = fs.createWriteStream(destFile);
|
|
167
|
+
res.pipe(out);
|
|
168
|
+
out.on("finish", () => out.close(() => cb(null)));
|
|
169
|
+
out.on("error", (e) => cb(e));
|
|
170
|
+
})
|
|
171
|
+
.on("error", (e) => cb(e));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Extract the archive into vendor/ using the platform's native tool.
|
|
175
|
+
function extract(archiveFile, ext) {
|
|
176
|
+
fs.mkdirSync(VENDOR_DIR, { recursive: true });
|
|
177
|
+
let res;
|
|
178
|
+
if (ext === "zip") {
|
|
179
|
+
if (os.platform() === "win32") {
|
|
180
|
+
res = spawnSync(
|
|
181
|
+
"powershell",
|
|
182
|
+
[
|
|
183
|
+
"-NoProfile",
|
|
184
|
+
"-Command",
|
|
185
|
+
"Expand-Archive -Force -LiteralPath '" +
|
|
186
|
+
archiveFile +
|
|
187
|
+
"' -DestinationPath '" +
|
|
188
|
+
VENDOR_DIR +
|
|
189
|
+
"'",
|
|
190
|
+
],
|
|
191
|
+
{ stdio: "inherit" }
|
|
192
|
+
);
|
|
193
|
+
} else {
|
|
194
|
+
res = spawnSync("unzip", ["-o", archiveFile, "-d", VENDOR_DIR], {
|
|
195
|
+
stdio: "inherit",
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
res = spawnSync("tar", ["-xzf", archiveFile, "-C", VENDOR_DIR], {
|
|
200
|
+
stdio: "inherit",
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
if (res.error) {
|
|
204
|
+
fail("extraction tool failed to launch: " + res.error.message);
|
|
205
|
+
}
|
|
206
|
+
if (res.status !== 0) {
|
|
207
|
+
fail("extraction exited with status " + res.status);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Make all extracted binaries executable and assert the full set is present.
|
|
212
|
+
function finalizeAndVerify() {
|
|
213
|
+
const exeSuffix = os.platform() === "win32" ? ".exe" : "";
|
|
214
|
+
const missing = [];
|
|
215
|
+
for (const name of EXPECTED_BINS) {
|
|
216
|
+
const p = path.join(VENDOR_DIR, name + exeSuffix);
|
|
217
|
+
if (fs.existsSync(p)) {
|
|
218
|
+
try {
|
|
219
|
+
fs.chmodSync(p, 0o755);
|
|
220
|
+
} catch (e) {
|
|
221
|
+
// Best-effort on Windows where chmod is largely a no-op.
|
|
222
|
+
}
|
|
223
|
+
} else {
|
|
224
|
+
missing.push(name + exeSuffix);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (missing.length > 0) {
|
|
228
|
+
fail(
|
|
229
|
+
"the downloaded bundle is missing expected binaries: " +
|
|
230
|
+
missing.join(", ") +
|
|
231
|
+
". The release archive may be corrupt or incomplete."
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function main() {
|
|
237
|
+
if (process.env.OCTOS_SKIP_DOWNLOAD === "1") {
|
|
238
|
+
console.log(
|
|
239
|
+
"[@octos-org/octos] OCTOS_SKIP_DOWNLOAD=1 set; skipping bundle download."
|
|
240
|
+
);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const target = resolveTarget();
|
|
245
|
+
const url = bundleUrl(target);
|
|
246
|
+
console.log("[@octos-org/octos] downloading " + url);
|
|
247
|
+
|
|
248
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "octos-npm-"));
|
|
249
|
+
const archiveFile = path.join(tmpDir, "bundle." + target.ext);
|
|
250
|
+
|
|
251
|
+
download(url, archiveFile, 0, (err) => {
|
|
252
|
+
if (err) {
|
|
253
|
+
fail(err.message);
|
|
254
|
+
}
|
|
255
|
+
extract(archiveFile, target.ext);
|
|
256
|
+
finalizeAndVerify();
|
|
257
|
+
try {
|
|
258
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
259
|
+
} catch (e) {
|
|
260
|
+
// non-fatal cleanup failure
|
|
261
|
+
}
|
|
262
|
+
console.log(
|
|
263
|
+
"[@octos-org/octos] installed octos + " +
|
|
264
|
+
(EXPECTED_BINS.length - 1) +
|
|
265
|
+
" bundled skills into vendor/"
|
|
266
|
+
);
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@octos-org/octos",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Rust-native, API-first Agentic OS server (octos serve + bundled skills). Installs the prebuilt release bundle.",
|
|
5
|
+
"homepage": "https://github.com/octos-org/octos",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/octos-org/octos.git"
|
|
10
|
+
},
|
|
11
|
+
"bin": {
|
|
12
|
+
"octos": "bin/octos.js"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"postinstall": "node install.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"bin",
|
|
19
|
+
"install.js",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"os": [
|
|
23
|
+
"darwin",
|
|
24
|
+
"linux",
|
|
25
|
+
"win32"
|
|
26
|
+
],
|
|
27
|
+
"cpu": [
|
|
28
|
+
"arm64",
|
|
29
|
+
"x64"
|
|
30
|
+
],
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18"
|
|
33
|
+
}
|
|
34
|
+
}
|