@themoltnet/cli 1.26.0 → 1.28.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.
Files changed (3) hide show
  1. package/bin/moltnet.js +27 -5
  2. package/install.js +63 -116
  3. package/package.json +13 -5
package/bin/moltnet.js CHANGED
@@ -6,13 +6,35 @@ const fs = require('fs');
6
6
  const { execFileSync } = require('child_process');
7
7
 
8
8
  const binaryName = process.platform === 'win32' ? 'moltnet.exe' : 'moltnet';
9
- const binaryPath = path.join(__dirname, binaryName);
10
9
 
11
- if (!fs.existsSync(binaryPath)) {
10
+ function findBinary() {
11
+ const pkgName = `@themoltnet/cli-${process.platform}-${process.arch}`;
12
+ try {
13
+ const pkgDir = path.dirname(require.resolve(`${pkgName}/package.json`));
14
+ const pkgPath = path.join(pkgDir, 'bin', binaryName);
15
+ if (fs.existsSync(pkgPath)) {
16
+ return pkgPath;
17
+ }
18
+ } catch {
19
+ // Platform package not installed
20
+ }
21
+
22
+ const localPath = path.join(__dirname, binaryName);
23
+ if (fs.existsSync(localPath)) {
24
+ return localPath;
25
+ }
26
+
27
+ return null;
28
+ }
29
+
30
+ const binaryPath = findBinary();
31
+
32
+ if (!binaryPath) {
12
33
  console.error(
13
- `moltnet binary not found at ${binaryPath}\n` +
14
- 'Run "node install.js" in the package directory, or download manually from:\n' +
15
- ' https://github.com/getlarge/themoltnet/releases'
34
+ `moltnet binary not found for ${process.platform}-${process.arch}\n` +
35
+ `Install the platform package manually:\n` +
36
+ ` npm install @themoltnet/cli-${process.platform}-${process.arch}\n` +
37
+ `Or reinstall @themoltnet/cli to trigger the postinstall fallback.`
16
38
  );
17
39
  process.exit(1);
18
40
  }
package/install.js CHANGED
@@ -4,44 +4,34 @@
4
4
  const https = require('https');
5
5
  const fs = require('fs');
6
6
  const path = require('path');
7
- const crypto = require('crypto');
8
7
  const zlib = require('zlib');
9
8
  const { execFileSync } = require('child_process');
10
9
 
11
10
  const VERSION = require('./package.json').version;
12
- const REPO = 'getlarge/themoltnet';
13
- const TAG = `cli-v${VERSION}`;
14
- const BASE_URL = `https://github.com/${REPO}/releases/download/${TAG}`;
15
-
16
- const PLATFORM_MAP = {
17
- darwin: 'darwin',
18
- linux: 'linux',
19
- win32: 'windows',
20
- };
21
-
22
- const ARCH_MAP = {
23
- x64: 'amd64',
24
- arm64: 'arm64',
25
- };
26
11
 
27
12
  function getBinaryName() {
28
13
  return process.platform === 'win32' ? 'moltnet.exe' : 'moltnet';
29
14
  }
30
15
 
31
- function getBinaryPath() {
32
- return path.join(__dirname, 'bin', getBinaryName());
16
+ function getPlatformPackageName() {
17
+ return `@themoltnet/cli-${process.platform}-${process.arch}`;
33
18
  }
34
19
 
35
- function getArchiveName() {
36
- const os = PLATFORM_MAP[process.platform];
37
- const arch = ARCH_MAP[process.arch];
38
- if (!os || !arch) {
39
- throw new Error(
40
- `Unsupported platform: ${process.platform}-${process.arch}`
41
- );
20
+ // Case 1 (happy path): the platform package was installed via
21
+ // optionalDependencies. bin/moltnet.js resolves the binary in place at
22
+ // runtime, so install.js has nothing to do.
23
+ function tryPlatformPackage() {
24
+ const pkgName = getPlatformPackageName();
25
+ try {
26
+ const pkgDir = path.dirname(require.resolve(`${pkgName}/package.json`));
27
+ const binaryPath = path.join(pkgDir, 'bin', getBinaryName());
28
+ if (fs.existsSync(binaryPath)) {
29
+ return binaryPath;
30
+ }
31
+ } catch {
32
+ // Platform package not installed (e.g. --no-optional, yarn v1 optional bug)
42
33
  }
43
- const ext = process.platform === 'win32' ? 'zip' : 'tar.gz';
44
- return `moltnet_${VERSION}_${os}_${arch}.${ext}`;
34
+ return null;
45
35
  }
46
36
 
47
37
  function fetch(url, maxRedirects = 5) {
@@ -51,13 +41,15 @@ function fetch(url, maxRedirects = 5) {
51
41
  }
52
42
  https
53
43
  .get(url, { headers: { 'User-Agent': 'themoltnet-cli' } }, (res) => {
54
- if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
44
+ if (
45
+ res.statusCode >= 300 &&
46
+ res.statusCode < 400 &&
47
+ res.headers.location
48
+ ) {
55
49
  return resolve(fetch(res.headers.location, maxRedirects - 1));
56
50
  }
57
51
  if (res.statusCode !== 200) {
58
- return reject(
59
- new Error(`HTTP ${res.statusCode} fetching ${url}`)
60
- );
52
+ return reject(new Error(`HTTP ${res.statusCode} fetching ${url}`));
61
53
  }
62
54
  const chunks = [];
63
55
  res.on('data', (chunk) => chunks.push(chunk));
@@ -68,106 +60,61 @@ function fetch(url, maxRedirects = 5) {
68
60
  });
69
61
  }
70
62
 
71
- async function verifyChecksum(archiveBuffer, archiveName) {
72
- const checksumsUrl = `${BASE_URL}/checksums.txt`;
73
- const checksumsBuffer = await fetch(checksumsUrl);
74
- const checksums = checksumsBuffer.toString('utf8');
63
+ // Case 2 (fallback): fetch the platform package tarball directly from the npm
64
+ // registry and extract the binary into local bin/. The registry is reachable
65
+ // in most sandboxed environments where github.com is not.
66
+ async function downloadFromNpm() {
67
+ const pkgName = getPlatformPackageName();
68
+ const bareName = pkgName.split('/')[1];
69
+ const tarballUrl = `https://registry.npmjs.org/${pkgName}/-/${bareName}-${VERSION}.tgz`;
75
70
 
76
- const line = checksums.split('\n').find((l) => l.includes(archiveName));
77
- if (!line) {
78
- throw new Error(
79
- `Checksum not found for ${archiveName} in checksums.txt`
80
- );
81
- }
71
+ console.log(`Downloading moltnet binary from ${tarballUrl}`);
72
+ const tarball = await fetch(tarballUrl);
73
+ const gunzipped = zlib.gunzipSync(tarball);
82
74
 
83
- const expectedHash = line.split(/\s+/)[0];
84
- const actualHash = crypto
85
- .createHash('sha256')
86
- .update(archiveBuffer)
87
- .digest('hex');
88
-
89
- if (actualHash !== expectedHash) {
90
- throw new Error(
91
- `Checksum mismatch for ${archiveName}:\n expected: ${expectedHash}\n actual: ${actualHash}`
92
- );
93
- }
94
- }
95
-
96
- function extractTarGz(buffer, destDir) {
97
- const tmpDir = path.join(__dirname, '.tmp');
98
- const tmpFile = path.join(tmpDir, 'archive.tar.gz');
75
+ const tmpDir = path.join(__dirname, '.install-tmp');
76
+ fs.rmSync(tmpDir, { recursive: true, force: true });
99
77
  fs.mkdirSync(tmpDir, { recursive: true });
100
- fs.writeFileSync(tmpFile, buffer);
101
- try {
102
- execFileSync('tar', ['xzf', tmpFile, '-C', destDir], {
103
- stdio: 'pipe',
104
- });
105
- } finally {
106
- fs.rmSync(tmpDir, { recursive: true, force: true });
107
- }
108
- }
78
+ const tmpTar = path.join(tmpDir, 'archive.tar');
79
+ fs.writeFileSync(tmpTar, gunzipped);
109
80
 
110
- function extractZip(buffer, destDir) {
111
- const tmpDir = path.join(__dirname, '.tmp');
112
- const tmpFile = path.join(tmpDir, 'archive.zip');
113
- fs.mkdirSync(tmpDir, { recursive: true });
114
- fs.writeFileSync(tmpFile, buffer);
115
81
  try {
116
- execFileSync(
117
- 'powershell',
118
- [
119
- '-NoProfile',
120
- '-Command',
121
- `Expand-Archive -Path '${tmpFile}' -DestinationPath '${destDir}' -Force`,
122
- ],
123
- { stdio: 'pipe' }
124
- );
82
+ execFileSync('tar', ['xf', tmpTar, '-C', tmpDir], { stdio: 'pipe' });
83
+
84
+ const extractedBinary = path.join(tmpDir, 'package', 'bin', getBinaryName());
85
+ if (!fs.existsSync(extractedBinary)) {
86
+ throw new Error(`Binary not found in tarball: ${extractedBinary}`);
87
+ }
88
+
89
+ const targetBinDir = path.join(__dirname, 'bin');
90
+ fs.mkdirSync(targetBinDir, { recursive: true });
91
+ const targetPath = path.join(targetBinDir, getBinaryName());
92
+ fs.copyFileSync(extractedBinary, targetPath);
93
+ if (process.platform !== 'win32') {
94
+ fs.chmodSync(targetPath, 0o755);
95
+ }
96
+ return targetPath;
125
97
  } finally {
126
98
  fs.rmSync(tmpDir, { recursive: true, force: true });
127
99
  }
128
100
  }
129
101
 
130
102
  async function main() {
131
- const binaryPath = getBinaryPath();
132
-
133
- if (fs.existsSync(binaryPath)) {
134
- console.log(`moltnet binary already exists at ${binaryPath}, skipping download.`);
103
+ if (tryPlatformPackage()) {
135
104
  return;
136
105
  }
137
106
 
138
- const archiveName = getArchiveName();
139
- const archiveUrl = `${BASE_URL}/${archiveName}`;
140
-
141
- console.log(`Downloading moltnet ${VERSION} for ${process.platform}-${process.arch}...`);
142
- console.log(` ${archiveUrl}`);
143
-
144
- const archiveBuffer = await fetch(archiveUrl);
145
-
146
- console.log('Verifying checksum...');
147
- await verifyChecksum(archiveBuffer, archiveName);
148
-
149
- const binDir = path.join(__dirname, 'bin');
150
- fs.mkdirSync(binDir, { recursive: true });
151
-
152
- console.log('Extracting...');
153
- if (process.platform === 'win32') {
154
- extractZip(archiveBuffer, binDir);
155
- } else {
156
- extractTarGz(archiveBuffer, binDir);
157
- }
158
-
159
- if (process.platform !== 'win32') {
160
- fs.chmodSync(binaryPath, 0o755);
107
+ try {
108
+ const binaryPath = await downloadFromNpm();
109
+ console.log(`Installed moltnet ${VERSION} to ${binaryPath}`);
110
+ } catch (err) {
111
+ console.warn(`Warning: Failed to install moltnet binary: ${err.message}`);
112
+ console.warn(
113
+ `You can install the platform package manually:\n` +
114
+ ` npm install ${getPlatformPackageName()}@${VERSION}`
115
+ );
116
+ // Exit 0 so postinstall doesn't break install for the whole project
161
117
  }
162
-
163
- console.log(`Installed moltnet ${VERSION} to ${binaryPath}`);
164
118
  }
165
119
 
166
- main().catch((err) => {
167
- console.warn(`Warning: Failed to install moltnet binary: ${err.message}`);
168
- console.warn(
169
- `\nYou can download it manually from:\n ${BASE_URL}/`
170
- );
171
- // Exit 0 so postinstall doesn't break `pnpm install` for the whole monorepo
172
- process.exit(0);
173
- });
120
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@themoltnet/cli",
3
- "version": "1.26.0",
3
+ "version": "1.28.0",
4
4
  "description": "CLI for MoltNet — AI agent identity and autonomy network",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -12,14 +12,22 @@
12
12
  "bin": {
13
13
  "moltnet": "bin/moltnet.js"
14
14
  },
15
- "scripts": {
16
- "postinstall": "node install.js"
17
- },
18
15
  "files": [
19
16
  "bin/moltnet.js",
20
17
  "install.js"
21
18
  ],
22
19
  "engines": {
23
20
  "node": ">=18"
21
+ },
22
+ "optionalDependencies": {
23
+ "@themoltnet/cli-darwin-arm64": "1.28.0",
24
+ "@themoltnet/cli-linux-arm64": "1.28.0",
25
+ "@themoltnet/cli-darwin-x64": "1.28.0",
26
+ "@themoltnet/cli-win32-arm64": "1.28.0",
27
+ "@themoltnet/cli-linux-x64": "1.28.0",
28
+ "@themoltnet/cli-win32-x64": "1.28.0"
29
+ },
30
+ "scripts": {
31
+ "postinstall": "node install.js"
24
32
  }
25
- }
33
+ }