aether-colony 1.0.17

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 ADDED
@@ -0,0 +1,59 @@
1
+ <div align="center">
2
+
3
+ <img src="https://raw.githubusercontent.com/calcosmic/Aether/main/assets/banner/banner.jpg" alt="Aether Banner" width="100%" />
4
+
5
+ <img src="https://raw.githubusercontent.com/calcosmic/Aether/main/assets/logo/logo.jpg" alt="Aether Logo" width="140" />
6
+
7
+ # Aether
8
+
9
+ **Artificial Ecology for Thought and Emergent Reasoning**
10
+
11
+ [![GitHub release](https://img.shields.io/github/v/release/calcosmic/Aether.svg?style=flat-square)](https://github.com/calcosmic/Aether/releases)
12
+ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-7B3FE4?style=flat-square)](https://github.com/calcosmic/Aether/blob/main/LICENSE)
13
+ [![GitHub stars](https://img.shields.io/github/stars/calcosmic/Aether.svg?style=flat-square)](https://github.com/calcosmic/Aether/stargazers)
14
+
15
+ ```bash
16
+ npx --yes aether-colony@latest
17
+ ```
18
+
19
+ </div>
20
+
21
+ `aether-colony` is the low-friction npm bootstrap for Aether. It is not a second runtime. It downloads the matching published Go `aether` binary for your platform, installs it into a stable local directory, and then hands off to the real CLI.
22
+
23
+ The npm package version intentionally matches the published Go release version.
24
+ There is one public Aether version, not one version for npm and another for the
25
+ runtime.
26
+
27
+ ## What happens on first run
28
+
29
+ 1. The wrapper resolves the matching Aether release for your platform.
30
+ 2. It downloads and verifies the release archive from GitHub Releases.
31
+ 3. It installs the binary locally.
32
+ 4. It runs `aether install` so the hub and companion files are populated.
33
+
34
+ ## Quick start
35
+
36
+ ```bash
37
+ npx --yes aether-colony@latest
38
+ ```
39
+
40
+ ## Hand off to the real CLI
41
+
42
+ ```bash
43
+ npx --yes aether-colony@latest -- status
44
+ npx --yes aether-colony@latest -- update --force --download-binary
45
+ npx --yes aether-colony@latest -- init "Build feature X"
46
+ ```
47
+
48
+ ## Important distinction
49
+
50
+ - `aether-colony` is the bootstrap and discovery path.
51
+ - The real runtime is the Go `aether` binary.
52
+ - After the first install, users should normally run `aether ...` directly.
53
+ - `aether-colony@1.0.17` is expected to bootstrap Aether `1.0.17`.
54
+
55
+ ## Source and docs
56
+
57
+ - GitHub: https://github.com/calcosmic/Aether
58
+ - Install guide: https://github.com/calcosmic/Aether#-install
59
+ - Release notes: https://github.com/calcosmic/Aether/releases
package/bin/aether.js ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { main } = require("../lib/bootstrap");
4
+
5
+ main(process.argv.slice(2)).catch((error) => {
6
+ const message = error && error.message ? error.message : String(error);
7
+ console.error(message);
8
+ process.exit(1);
9
+ });
@@ -0,0 +1,463 @@
1
+ "use strict";
2
+
3
+ const crypto = require("node:crypto");
4
+ const fs = require("node:fs");
5
+ const fsp = require("node:fs/promises");
6
+ const http = require("node:http");
7
+ const https = require("node:https");
8
+ const os = require("node:os");
9
+ const path = require("node:path");
10
+ const { spawnSync, execFileSync } = require("node:child_process");
11
+ const packageJson = require("../package.json");
12
+
13
+ const REPO_OWNER = "calcosmic";
14
+ const REPO_NAME = "Aether";
15
+ const DEFAULT_AETHER_VERSION = packageJson.version;
16
+ const PACKAGE_VERSION = packageJson.version;
17
+ const MAX_REDIRECTS = 5;
18
+ const BANNER = `
19
+ █████╗ ███████╗████████╗██╗ ██╗███████╗██████╗
20
+ ██╔══██╗██╔════╝╚══██╔══╝██║ ██║██╔════╝██╔══██╗
21
+ ███████║█████╗ ██║ ███████║█████╗ ██████╔╝
22
+ ██╔══██║██╔══╝ ██║ ██╔══██║██╔══╝ ██╔══██╗
23
+ ██║ ██║███████╗ ██║ ██║ ██║███████╗██║ ██║
24
+ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
25
+ `;
26
+
27
+ function printBootstrapHelp() {
28
+ console.log(BANNER.trimEnd());
29
+ console.log("");
30
+ console.log("Aether npm bootstrap");
31
+ console.log("");
32
+ console.log("Usage:");
33
+ console.log(" npx --yes aether-colony@latest");
34
+ console.log(" npx --yes aether-colony@latest -- <aether args>");
35
+ console.log("");
36
+ console.log("What it does:");
37
+ console.log(" 1. Downloads the matching Go release binary for your platform");
38
+ console.log(" 2. Installs it into a stable local directory");
39
+ console.log(" 3. Runs the real `aether` CLI");
40
+ console.log("");
41
+ console.log("Flags:");
42
+ console.log(" --bootstrap-help Show this help");
43
+ console.log(" --bootstrap-version Print the npm wrapper version");
44
+ console.log(" --aether-version <ver> Override the Go release version to install");
45
+ console.log(" --dest <path> Override the install directory for the Go binary");
46
+ console.log("");
47
+ console.log("Examples:");
48
+ console.log(" npx --yes aether-colony@latest");
49
+ console.log(" npx --yes aether-colony@latest -- status");
50
+ console.log(" npx --yes aether-colony@latest -- update --force --download-binary");
51
+ }
52
+
53
+ function normalizeArgs(argv) {
54
+ const args = [...argv];
55
+ const bootstrap = {
56
+ help: false,
57
+ wrapperVersion: false,
58
+ aetherVersion: DEFAULT_AETHER_VERSION,
59
+ dest: null,
60
+ passthrough: []
61
+ };
62
+
63
+ for (let i = 0; i < args.length; i += 1) {
64
+ const arg = args[i];
65
+ if (arg === "--") {
66
+ bootstrap.passthrough = args.slice(i + 1);
67
+ return bootstrap;
68
+ }
69
+ if (arg === "--bootstrap-help") {
70
+ bootstrap.help = true;
71
+ continue;
72
+ }
73
+ if (arg === "--bootstrap-version") {
74
+ bootstrap.wrapperVersion = true;
75
+ continue;
76
+ }
77
+ if (arg === "--aether-version") {
78
+ bootstrap.aetherVersion = normalizeVersion(args[i + 1]);
79
+ i += 1;
80
+ continue;
81
+ }
82
+ if (arg.startsWith("--aether-version=")) {
83
+ bootstrap.aetherVersion = normalizeVersion(arg.split("=", 2)[1]);
84
+ continue;
85
+ }
86
+ if (arg === "--dest") {
87
+ bootstrap.dest = args[i + 1];
88
+ i += 1;
89
+ continue;
90
+ }
91
+ if (arg.startsWith("--dest=")) {
92
+ bootstrap.dest = arg.split("=", 2)[1];
93
+ continue;
94
+ }
95
+ bootstrap.passthrough = args.slice(i);
96
+ return bootstrap;
97
+ }
98
+
99
+ return bootstrap;
100
+ }
101
+
102
+ function normalizeVersion(version) {
103
+ return String(version || "").trim().replace(/^v/, "");
104
+ }
105
+
106
+ function detectPlatform(nodePlatform = process.platform, nodeArch = process.arch) {
107
+ const osMap = {
108
+ darwin: "darwin",
109
+ linux: "linux",
110
+ win32: "windows"
111
+ };
112
+ const archMap = {
113
+ x64: "amd64",
114
+ arm64: "arm64"
115
+ };
116
+
117
+ const osName = osMap[nodePlatform];
118
+ const archName = archMap[nodeArch];
119
+ if (!osName || !archName) {
120
+ throw new Error(`Unsupported platform: ${nodePlatform}/${nodeArch}. Supported: darwin/linux/windows + x64/arm64.`);
121
+ }
122
+ return { os: osName, arch: archName };
123
+ }
124
+
125
+ function archiveFilename(version, platform) {
126
+ const ext = platform.os === "windows" ? ".zip" : ".tar.gz";
127
+ return `aether_v${version}_${platform.os}_${platform.arch}${ext}`;
128
+ }
129
+
130
+ function checksumsFilename(version) {
131
+ return `aether_v${version}_checksums.txt`;
132
+ }
133
+
134
+ function releaseBaseURL(version) {
135
+ return `https://github.com/${REPO_OWNER}/${REPO_NAME}/releases/download/v${version}`;
136
+ }
137
+
138
+ function archiveURL(version, platform) {
139
+ return `${releaseBaseURL(version)}/${archiveFilename(version, platform)}`;
140
+ }
141
+
142
+ function checksumsURL(version) {
143
+ return `${releaseBaseURL(version)}/${checksumsFilename(version)}`;
144
+ }
145
+
146
+ function binaryName(platform) {
147
+ return platform.os === "windows" ? "aether.exe" : "aether";
148
+ }
149
+
150
+ function defaultDestDir(homeDir = os.homedir(), nodePlatform = process.platform) {
151
+ if (process.env.AETHER_BINARY_DEST) {
152
+ return process.env.AETHER_BINARY_DEST;
153
+ }
154
+ if (nodePlatform === "win32") {
155
+ return path.join(homeDir, ".aether", "bin");
156
+ }
157
+ const localBin = path.join(homeDir, ".local", "bin");
158
+ if (fs.existsSync(localBin) && fs.statSync(localBin).isDirectory()) {
159
+ return localBin;
160
+ }
161
+ return path.join(homeDir, ".aether", "bin");
162
+ }
163
+
164
+ function installedBinaryPath(destDir, platform) {
165
+ return path.join(destDir, binaryName(platform));
166
+ }
167
+
168
+ function hubVersionFile(homeDir = os.homedir()) {
169
+ return path.join(homeDir, ".aether", "version.json");
170
+ }
171
+
172
+ function hasHubInstalled(homeDir = os.homedir()) {
173
+ return fs.existsSync(hubVersionFile(homeDir));
174
+ }
175
+
176
+ function isBinaryOnPath(binaryPath) {
177
+ const pathEntries = String(process.env.PATH || "").split(path.delimiter);
178
+ return pathEntries.some((entry) => path.resolve(entry || ".") === path.resolve(path.dirname(binaryPath)));
179
+ }
180
+
181
+ function parseChecksum(content, filename) {
182
+ const lines = String(content).split(/\r?\n/);
183
+ for (const line of lines) {
184
+ const parts = line.split(/\s{2,}/);
185
+ if (parts.length >= 2 && parts[1] === filename) {
186
+ return parts[0].trim();
187
+ }
188
+ }
189
+ throw new Error(`Checksum not found for ${filename}`);
190
+ }
191
+
192
+ function parseVersionOutput(stdout) {
193
+ const trimmed = String(stdout || "").trim();
194
+ if (!trimmed) {
195
+ return "";
196
+ }
197
+ try {
198
+ const parsed = JSON.parse(trimmed);
199
+ if (parsed && parsed.ok === true) {
200
+ return normalizeVersion(parsed.result);
201
+ }
202
+ } catch (_) {
203
+ // fall through
204
+ }
205
+ return normalizeVersion(trimmed);
206
+ }
207
+
208
+ function getInstalledVersion(binaryPath) {
209
+ if (!fs.existsSync(binaryPath)) {
210
+ return "";
211
+ }
212
+ const result = spawnSync(binaryPath, ["version"], {
213
+ encoding: "utf8",
214
+ env: {
215
+ ...process.env,
216
+ AETHER_OUTPUT_MODE: "json"
217
+ }
218
+ });
219
+ if (result.status !== 0) {
220
+ return "";
221
+ }
222
+ return parseVersionOutput(result.stdout);
223
+ }
224
+
225
+ function needsInstall(binaryPath, targetVersion) {
226
+ const installedVersion = getInstalledVersion(binaryPath);
227
+ return installedVersion !== normalizeVersion(targetVersion);
228
+ }
229
+
230
+ function requestWithRedirects(url, redirectsLeft = MAX_REDIRECTS) {
231
+ return new Promise((resolve, reject) => {
232
+ const transport = url.startsWith("https:") ? https : http;
233
+ const req = transport.get(
234
+ url,
235
+ {
236
+ headers: {
237
+ "User-Agent": `${packageJson.name}/${PACKAGE_VERSION}`
238
+ }
239
+ },
240
+ (res) => {
241
+ const status = res.statusCode || 0;
242
+ if ([301, 302, 303, 307, 308].includes(status) && res.headers.location) {
243
+ if (redirectsLeft <= 0) {
244
+ reject(new Error(`Too many redirects while fetching ${url}`));
245
+ res.resume();
246
+ return;
247
+ }
248
+ const nextURL = new URL(res.headers.location, url).toString();
249
+ res.resume();
250
+ resolve(requestWithRedirects(nextURL, redirectsLeft - 1));
251
+ return;
252
+ }
253
+ if (status < 200 || status >= 300) {
254
+ reject(new Error(`HTTP ${status} for ${url}`));
255
+ res.resume();
256
+ return;
257
+ }
258
+ resolve(res);
259
+ }
260
+ );
261
+ req.on("error", reject);
262
+ });
263
+ }
264
+
265
+ async function downloadText(url) {
266
+ const response = await requestWithRedirects(url);
267
+ const chunks = [];
268
+ for await (const chunk of response) {
269
+ chunks.push(chunk);
270
+ }
271
+ return Buffer.concat(chunks).toString("utf8");
272
+ }
273
+
274
+ async function downloadFile(url, destination) {
275
+ const response = await requestWithRedirects(url);
276
+ await fsp.mkdir(path.dirname(destination), { recursive: true });
277
+ const out = fs.createWriteStream(destination);
278
+ await new Promise((resolve, reject) => {
279
+ response.pipe(out);
280
+ response.on("error", reject);
281
+ out.on("error", reject);
282
+ out.on("finish", resolve);
283
+ });
284
+ await fsp.chmod(destination, 0o644);
285
+ }
286
+
287
+ async function sha256File(filePath) {
288
+ const hash = crypto.createHash("sha256");
289
+ const stream = fs.createReadStream(filePath);
290
+ return new Promise((resolve, reject) => {
291
+ stream.on("data", (chunk) => hash.update(chunk));
292
+ stream.on("error", reject);
293
+ stream.on("end", () => resolve(hash.digest("hex")));
294
+ });
295
+ }
296
+
297
+ function extractArchive(archivePath, extractDir, platform) {
298
+ fs.mkdirSync(extractDir, { recursive: true });
299
+ if (platform.os === "windows") {
300
+ execFileSync(
301
+ "powershell.exe",
302
+ [
303
+ "-NoLogo",
304
+ "-NoProfile",
305
+ "-NonInteractive",
306
+ "-Command",
307
+ `Expand-Archive -LiteralPath '${archivePath.replace(/'/g, "''")}' -DestinationPath '${extractDir.replace(/'/g, "''")}' -Force`
308
+ ],
309
+ { stdio: "ignore" }
310
+ );
311
+ return;
312
+ }
313
+
314
+ execFileSync("tar", ["-xzf", archivePath, "-C", extractDir], {
315
+ stdio: "ignore"
316
+ });
317
+ }
318
+
319
+ function findBinaryRecursively(baseDir, binaryFile) {
320
+ const entries = fs.readdirSync(baseDir, { withFileTypes: true });
321
+ for (const entry of entries) {
322
+ const fullPath = path.join(baseDir, entry.name);
323
+ if (entry.isFile() && entry.name === binaryFile) {
324
+ return fullPath;
325
+ }
326
+ if (entry.isDirectory()) {
327
+ const nested = findBinaryRecursively(fullPath, binaryFile);
328
+ if (nested) {
329
+ return nested;
330
+ }
331
+ }
332
+ }
333
+ return "";
334
+ }
335
+
336
+ async function installReleaseBinary(version, destDir) {
337
+ const platform = detectPlatform();
338
+ const archiveFile = archiveFilename(version, platform);
339
+ const tmpRoot = await fsp.mkdtemp(path.join(os.tmpdir(), "aether-npm-"));
340
+ const archivePath = path.join(tmpRoot, archiveFile);
341
+ const extractDir = path.join(tmpRoot, "extract");
342
+ const destPath = installedBinaryPath(destDir, platform);
343
+
344
+ try {
345
+ const checksums = await downloadText(checksumsURL(version));
346
+ const expected = parseChecksum(checksums, archiveFile);
347
+ await downloadFile(archiveURL(version, platform), archivePath);
348
+ const actual = await sha256File(archivePath);
349
+ if (actual !== expected) {
350
+ throw new Error(`Checksum mismatch for ${archiveFile}`);
351
+ }
352
+
353
+ extractArchive(archivePath, extractDir, platform);
354
+ const extractedBinary = findBinaryRecursively(extractDir, binaryName(platform));
355
+ if (!extractedBinary) {
356
+ throw new Error(`Binary ${binaryName(platform)} not found in extracted archive`);
357
+ }
358
+
359
+ await fsp.mkdir(destDir, { recursive: true });
360
+ const tmpDest = `${destPath}.tmp-${process.pid}`;
361
+ await fsp.copyFile(extractedBinary, tmpDest);
362
+ if (platform.os !== "windows") {
363
+ await fsp.chmod(tmpDest, 0o755);
364
+ }
365
+ await fsp.rm(destPath, { force: true });
366
+ await fsp.rename(tmpDest, destPath);
367
+ return destPath;
368
+ } finally {
369
+ await fsp.rm(tmpRoot, { recursive: true, force: true });
370
+ }
371
+ }
372
+
373
+ function runAether(binaryPath, args) {
374
+ const result = spawnSync(binaryPath, args, {
375
+ stdio: "inherit",
376
+ env: process.env
377
+ });
378
+ if (typeof result.status === "number") {
379
+ process.exit(result.status);
380
+ }
381
+ if (result.error) {
382
+ throw result.error;
383
+ }
384
+ process.exit(1);
385
+ }
386
+
387
+ async function main(argv) {
388
+ const options = normalizeArgs(argv);
389
+ if (options.help) {
390
+ printBootstrapHelp();
391
+ return;
392
+ }
393
+ if (options.wrapperVersion) {
394
+ console.log(PACKAGE_VERSION);
395
+ return;
396
+ }
397
+
398
+ const aetherVersion = normalizeVersion(options.aetherVersion);
399
+ if (!aetherVersion) {
400
+ throw new Error("Missing Aether release version for bootstrap");
401
+ }
402
+
403
+ const platform = detectPlatform();
404
+ const destDir = path.resolve(options.dest || defaultDestDir());
405
+ const binaryPath = installedBinaryPath(destDir, platform);
406
+ const firstInstall = !fs.existsSync(binaryPath);
407
+ const hubMissing = !hasHubInstalled();
408
+
409
+ console.log(BANNER.trimEnd());
410
+ console.log("");
411
+ console.log(`Bootstrapping Aether ${aetherVersion} via npm package ${packageJson.name}@${PACKAGE_VERSION}`);
412
+ console.log(`Install directory: ${destDir}`);
413
+
414
+ if (needsInstall(binaryPath, aetherVersion)) {
415
+ console.log(`Downloading Go release binary for ${platform.os}/${platform.arch}...`);
416
+ await installReleaseBinary(aetherVersion, destDir);
417
+ console.log(`Installed ${binaryPath}`);
418
+ } else {
419
+ console.log(`Found Aether ${aetherVersion} already installed at ${binaryPath}`);
420
+ }
421
+
422
+ if (!isBinaryOnPath(binaryPath)) {
423
+ console.log("");
424
+ console.log("PATH note:");
425
+ console.log(` Add ${destDir} to your PATH if you want to run \`aether\` directly outside npm.`);
426
+ }
427
+
428
+ const passthrough = options.passthrough.length > 0 ? options.passthrough : ["install"];
429
+ if ((firstInstall || hubMissing) && passthrough[0] !== "install") {
430
+ console.log("");
431
+ console.log("Initial setup detected. Initializing companion files before handing off to the requested command.");
432
+ const installResult = spawnSync(binaryPath, ["install"], {
433
+ stdio: "inherit",
434
+ env: process.env
435
+ });
436
+ if (installResult.status !== 0) {
437
+ process.exit(typeof installResult.status === "number" ? installResult.status : 1);
438
+ }
439
+ }
440
+
441
+ console.log("");
442
+ console.log(`Handing off to: ${path.basename(binaryPath)} ${passthrough.join(" ")}`);
443
+ runAether(binaryPath, passthrough);
444
+ }
445
+
446
+ module.exports = {
447
+ MAX_REDIRECTS,
448
+ archiveFilename,
449
+ archiveURL,
450
+ binaryName,
451
+ checksumsFilename,
452
+ checksumsURL,
453
+ defaultDestDir,
454
+ detectPlatform,
455
+ installedBinaryPath,
456
+ main,
457
+ normalizeArgs,
458
+ normalizeVersion,
459
+ parseChecksum,
460
+ parseVersionOutput,
461
+ hasHubInstalled,
462
+ releaseBaseURL
463
+ };
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "aether-colony",
3
+ "version": "1.0.17",
4
+ "description": "Bootstrap installer for the Aether ant colony CLI",
5
+ "license": "Apache-2.0",
6
+ "homepage": "https://github.com/calcosmic/Aether#readme",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/calcosmic/Aether.git",
10
+ "directory": "npm"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/calcosmic/Aether/issues"
14
+ },
15
+ "publishConfig": {
16
+ "access": "public",
17
+ "tag": "latest"
18
+ },
19
+ "keywords": [
20
+ "aether",
21
+ "aether-colony",
22
+ "ai",
23
+ "agents",
24
+ "multi-agent",
25
+ "ant-colony",
26
+ "claude-code",
27
+ "opencode",
28
+ "codex"
29
+ ],
30
+ "engines": {
31
+ "node": ">=18"
32
+ },
33
+ "bin": {
34
+ "aether": "./bin/aether.js"
35
+ },
36
+ "files": [
37
+ "bin",
38
+ "lib",
39
+ "README.md"
40
+ ],
41
+ "scripts": {
42
+ "test": "node --test test/*.test.js"
43
+ }
44
+ }