agentworth 0.1.1 → 0.1.4
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 +6 -10
- package/lib/resolver.js +234 -33
- package/package.json +10 -2
package/README.md
CHANGED
|
@@ -89,16 +89,12 @@ The launcher searches for the native binary in the following priority order:
|
|
|
89
89
|
|
|
90
90
|
You can also install the native AgentWorth binary directly:
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
curl -fsSL https://agentworth.dev/install.sh | sh
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
# Via Cargo
|
|
100
|
-
cargo install agentworth-cli
|
|
101
|
-
```
|
|
92
|
+
| Method | Command | Description |
|
|
93
|
+
| :--- | :--- | :--- |
|
|
94
|
+
| **Standalone Script** | `curl -fsSL https://agentworth.dev/install.sh | sh` | Installs the pre-built native binary directly to `~/.local/bin`. |
|
|
95
|
+
| **Homebrew** | `brew install unfoundbox-crew/tap/agentworth` | Installs via official Homebrew tap. |
|
|
96
|
+
| **Cargo (Native)** | `cargo install agentworth-cli` | Compiles and installs `agentworth` & `agwt` to `~/.cargo/bin`. |
|
|
97
|
+
| **NPX (Instant)** | `npx agentworth` | Zero-install runner that detects or downloads the native binary. |
|
|
102
98
|
|
|
103
99
|
---
|
|
104
100
|
|
package/lib/resolver.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import os from 'node:os';
|
|
4
|
-
import
|
|
4
|
+
import https from 'node:https';
|
|
5
|
+
import zlib from 'node:zlib';
|
|
6
|
+
import { spawnSync, execFileSync } from 'node:child_process';
|
|
5
7
|
import { fileURLToPath } from 'node:url';
|
|
6
8
|
|
|
7
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -18,6 +20,54 @@ export function getPlatformKey(platform = process.platform, arch = process.arch)
|
|
|
18
20
|
return `${platform}-${arch}`;
|
|
19
21
|
}
|
|
20
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Maps Node platform and arch to Rust release target triple.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} [platform=process.platform]
|
|
27
|
+
* @param {string} [arch=process.arch]
|
|
28
|
+
* @returns {string | null}
|
|
29
|
+
*/
|
|
30
|
+
export function getTargetTriple(platform = process.platform, arch = process.arch) {
|
|
31
|
+
if (platform === 'darwin' && arch === 'arm64') return 'aarch64-apple-darwin';
|
|
32
|
+
if (platform === 'darwin' && arch === 'x64') return 'x86_64-apple-darwin';
|
|
33
|
+
if (platform === 'linux' && arch === 'x64') return 'x86_64-unknown-linux-gnu';
|
|
34
|
+
if (platform === 'linux' && arch === 'arm64') return 'aarch64-unknown-linux-gnu';
|
|
35
|
+
if (platform === 'win32' && arch === 'x64') return 'x86_64-pc-windows-msvc';
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Reads the package version from package.json.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} [baseDir=__dirname]
|
|
43
|
+
* @returns {string}
|
|
44
|
+
*/
|
|
45
|
+
export function getPackageVersion(baseDir = __dirname) {
|
|
46
|
+
try {
|
|
47
|
+
const pkgPath = path.resolve(baseDir, '..', 'package.json');
|
|
48
|
+
if (fs.existsSync(pkgPath)) {
|
|
49
|
+
const data = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
50
|
+
return data.version || '0.1.3';
|
|
51
|
+
}
|
|
52
|
+
} catch {
|
|
53
|
+
// fallback
|
|
54
|
+
}
|
|
55
|
+
return '0.1.3';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Returns the local cache directory for AgentWorth binaries (~/.agentworth/bin/v{version}/).
|
|
60
|
+
*
|
|
61
|
+
* @param {string} [version]
|
|
62
|
+
* @param {string} [homeDir]
|
|
63
|
+
* @returns {string}
|
|
64
|
+
*/
|
|
65
|
+
export function getCacheDir(version, homeDir) {
|
|
66
|
+
const v = version || getPackageVersion();
|
|
67
|
+
const home = homeDir || os.homedir();
|
|
68
|
+
return path.join(home, '.agentworth', 'bin', `v${v}`);
|
|
69
|
+
}
|
|
70
|
+
|
|
21
71
|
/**
|
|
22
72
|
* Returns the expected native binary name for the target platform.
|
|
23
73
|
*
|
|
@@ -95,6 +145,117 @@ export function findCargoTargetBinary(startDir, binName = getBinaryName()) {
|
|
|
95
145
|
return null;
|
|
96
146
|
}
|
|
97
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Downloads a file following HTTP redirects.
|
|
150
|
+
*
|
|
151
|
+
* @param {string} url
|
|
152
|
+
* @param {string} destPath
|
|
153
|
+
* @param {number} [redirects=5]
|
|
154
|
+
* @returns {Promise<void>}
|
|
155
|
+
*/
|
|
156
|
+
export function downloadFile(url, destPath, redirects = 5) {
|
|
157
|
+
return new Promise((resolve, reject) => {
|
|
158
|
+
if (redirects < 0) {
|
|
159
|
+
return reject(new Error('Too many redirects while downloading binary.'));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const request = https.get(url, { headers: { 'User-Agent': 'agentworth-npm-resolver' } }, (res) => {
|
|
163
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
164
|
+
return downloadFile(res.headers.location, destPath, redirects - 1).then(resolve, reject);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (res.statusCode !== 200) {
|
|
168
|
+
return reject(new Error(`Failed to download binary: HTTP ${res.statusCode} from ${url}`));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const fileStream = fs.createWriteStream(destPath);
|
|
172
|
+
res.pipe(fileStream);
|
|
173
|
+
|
|
174
|
+
fileStream.on('finish', () => {
|
|
175
|
+
fileStream.close(resolve);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
fileStream.on('error', (err) => {
|
|
179
|
+
fs.unlink(destPath, () => reject(err));
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
request.on('error', (err) => {
|
|
184
|
+
reject(err);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Downloads and extracts the precompiled native binary from GitHub Releases into the user's local cache.
|
|
191
|
+
*
|
|
192
|
+
* @param {Object} [options={}]
|
|
193
|
+
* @param {string} [options.platform=process.platform]
|
|
194
|
+
* @param {string} [options.arch=process.arch]
|
|
195
|
+
* @param {string} [options.version]
|
|
196
|
+
* @param {string} [options.homeDir]
|
|
197
|
+
* @param {boolean} [options.silent=false]
|
|
198
|
+
* @returns {Promise<string>} Path to extracted binary
|
|
199
|
+
*/
|
|
200
|
+
export async function downloadAndExtractBinary(options = {}) {
|
|
201
|
+
const platform = options.platform || process.platform;
|
|
202
|
+
const arch = options.arch || process.arch;
|
|
203
|
+
const version = options.version || getPackageVersion();
|
|
204
|
+
const targetTriple = getTargetTriple(platform, arch);
|
|
205
|
+
const binName = getBinaryName(platform);
|
|
206
|
+
|
|
207
|
+
if (!targetTriple) {
|
|
208
|
+
throw new Error(`Unsupported platform/architecture: ${platform}-${arch}`);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const cacheDir = getCacheDir(version, options.homeDir);
|
|
212
|
+
const cachedBinary = path.join(cacheDir, binName);
|
|
213
|
+
|
|
214
|
+
if (isExecutable(cachedBinary)) {
|
|
215
|
+
return cachedBinary;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
219
|
+
|
|
220
|
+
const archiveName = `agentworth-v${version}-${targetTriple}.tar.gz`;
|
|
221
|
+
const url = `https://github.com/unfoundbox-crew/agentworth/releases/download/v${version}/${archiveName}`;
|
|
222
|
+
|
|
223
|
+
if (!options.silent) {
|
|
224
|
+
console.error(`\x1b[36m⚡ AgentWorth native binary not found locally. Downloading v${version} for ${platform}-${arch}...\x1b[0m`);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const archivePath = path.join(cacheDir, archiveName);
|
|
228
|
+
|
|
229
|
+
await downloadFile(url, archivePath);
|
|
230
|
+
|
|
231
|
+
// Extract archive
|
|
232
|
+
try {
|
|
233
|
+
execFileSync('tar', ['-xzf', archivePath, '-C', cacheDir]);
|
|
234
|
+
} catch (err) {
|
|
235
|
+
throw new Error(`Failed to extract ${archiveName}: ${err.message}`);
|
|
236
|
+
} finally {
|
|
237
|
+
try {
|
|
238
|
+
if (fs.existsSync(archivePath)) {
|
|
239
|
+
fs.unlinkSync(archivePath);
|
|
240
|
+
}
|
|
241
|
+
} catch {}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (process.platform !== 'win32') {
|
|
245
|
+
fs.chmodSync(cachedBinary, 0o755);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (!isExecutable(cachedBinary)) {
|
|
249
|
+
throw new Error(`Downloaded binary is not executable: ${cachedBinary}`);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (!options.silent) {
|
|
253
|
+
console.error(`\x1b[32m✔ Successfully installed AgentWorth native binary to ${cachedBinary}\x1b[0m\n`);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return cachedBinary;
|
|
257
|
+
}
|
|
258
|
+
|
|
98
259
|
/**
|
|
99
260
|
* Searches for the agentworth binary in the system PATH.
|
|
100
261
|
*
|
|
@@ -130,11 +291,12 @@ export function findPathBinary(binName = getBinaryName(), pathEnv = process.env.
|
|
|
130
291
|
* Search priority:
|
|
131
292
|
* 1. AGENTWORTH_BIN environment variable
|
|
132
293
|
* 2. Platform-specific optional package / vendor directory
|
|
133
|
-
* 3.
|
|
134
|
-
* 4. Cargo target in
|
|
135
|
-
* 5.
|
|
136
|
-
* 6.
|
|
137
|
-
* 7.
|
|
294
|
+
* 3. System PATH
|
|
295
|
+
* 4. Cargo target in cwd directory hierarchy (release or debug)
|
|
296
|
+
* 5. Cargo target in package directory hierarchy
|
|
297
|
+
* 6. CARGO_TARGET_DIR if set
|
|
298
|
+
* 7. User ~/.cargo/bin/
|
|
299
|
+
* 8. User local cache ~/.agentworth/bin/v{version}/
|
|
138
300
|
*
|
|
139
301
|
* @param {Object} [options={}]
|
|
140
302
|
* @param {string} [options.cwd=process.cwd()]
|
|
@@ -142,6 +304,7 @@ export function findPathBinary(binName = getBinaryName(), pathEnv = process.env.
|
|
|
142
304
|
* @param {string} [options.arch=process.arch]
|
|
143
305
|
* @param {NodeJS.ProcessEnv} [options.env=process.env]
|
|
144
306
|
* @param {string} [options.baseDir=__dirname]
|
|
307
|
+
* @param {string} [options.homeDir]
|
|
145
308
|
* @returns {{ found: boolean, path?: string, source?: string, error?: string }}
|
|
146
309
|
*/
|
|
147
310
|
export function resolveBinary(options = {}) {
|
|
@@ -150,6 +313,7 @@ export function resolveBinary(options = {}) {
|
|
|
150
313
|
const arch = options.arch || process.arch;
|
|
151
314
|
const env = options.env || process.env;
|
|
152
315
|
const baseDir = options.baseDir || __dirname;
|
|
316
|
+
const homeDir = options.homeDir || (env.HOME ? env.HOME : os.homedir());
|
|
153
317
|
const binName = getBinaryName(platform);
|
|
154
318
|
const platformKey = getPlatformKey(platform, arch);
|
|
155
319
|
|
|
@@ -172,7 +336,20 @@ export function resolveBinary(options = {}) {
|
|
|
172
336
|
};
|
|
173
337
|
}
|
|
174
338
|
|
|
175
|
-
// 3.
|
|
339
|
+
// 3. System PATH (highest user priority for installed binaries)
|
|
340
|
+
const currentBin = path.resolve(baseDir, '..', 'bin', 'agentworth.js');
|
|
341
|
+
if (env.PATH !== undefined) {
|
|
342
|
+
const pathBin = findPathBinary(binName, env.PATH, currentBin);
|
|
343
|
+
if (pathBin) {
|
|
344
|
+
return {
|
|
345
|
+
found: true,
|
|
346
|
+
path: pathBin,
|
|
347
|
+
source: 'path',
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// 4. Local Cargo target from working directory
|
|
176
353
|
const cwdCargoBin = findCargoTargetBinary(cwd, binName);
|
|
177
354
|
if (cwdCargoBin) {
|
|
178
355
|
return {
|
|
@@ -182,7 +359,7 @@ export function resolveBinary(options = {}) {
|
|
|
182
359
|
};
|
|
183
360
|
}
|
|
184
361
|
|
|
185
|
-
//
|
|
362
|
+
// 5. Local Cargo target from package directory hierarchy
|
|
186
363
|
const pkgCargoBin = findCargoTargetBinary(baseDir, binName);
|
|
187
364
|
if (pkgCargoBin) {
|
|
188
365
|
return {
|
|
@@ -192,7 +369,7 @@ export function resolveBinary(options = {}) {
|
|
|
192
369
|
};
|
|
193
370
|
}
|
|
194
371
|
|
|
195
|
-
//
|
|
372
|
+
// 6. CARGO_TARGET_DIR environment variable if specified
|
|
196
373
|
if (env.CARGO_TARGET_DIR) {
|
|
197
374
|
const targetDirRelease = path.join(env.CARGO_TARGET_DIR, 'release', binName);
|
|
198
375
|
if (isExecutable(targetDirRelease)) {
|
|
@@ -212,25 +389,27 @@ export function resolveBinary(options = {}) {
|
|
|
212
389
|
}
|
|
213
390
|
}
|
|
214
391
|
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
392
|
+
// 7. User ~/.cargo/bin directory
|
|
393
|
+
if (homeDir) {
|
|
394
|
+
const cargoHomeBin = path.join(homeDir, '.cargo', 'bin', binName);
|
|
395
|
+
if (isExecutable(cargoHomeBin)) {
|
|
396
|
+
return {
|
|
397
|
+
found: true,
|
|
398
|
+
path: cargoHomeBin,
|
|
399
|
+
source: 'cargo-home-bin',
|
|
400
|
+
};
|
|
401
|
+
}
|
|
224
402
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
403
|
+
// 8. User local cache (~/.agentworth/bin/v{version}/)
|
|
404
|
+
const cacheDir = getCacheDir(getPackageVersion(baseDir), homeDir);
|
|
405
|
+
const cachedBin = path.join(cacheDir, binName);
|
|
406
|
+
if (isExecutable(cachedBin)) {
|
|
407
|
+
return {
|
|
408
|
+
found: true,
|
|
409
|
+
path: cachedBin,
|
|
410
|
+
source: 'cache',
|
|
411
|
+
};
|
|
412
|
+
}
|
|
234
413
|
}
|
|
235
414
|
|
|
236
415
|
return {
|
|
@@ -257,11 +436,8 @@ export function formatMissingBinaryMessage(platformKey = getPlatformKey()) {
|
|
|
257
436
|
' \x1b[36m• Install via Cargo:\x1b[0m',
|
|
258
437
|
' cargo install --path apps/cli',
|
|
259
438
|
'',
|
|
260
|
-
' \x1b[36m•
|
|
261
|
-
|
|
262
|
-
'',
|
|
263
|
-
' \x1b[36m• Install via Shell script:\x1b[0m',
|
|
264
|
-
' curl -fsSL https://agentworth.dev/install.sh | sh',
|
|
439
|
+
' \x1b[36m• Download the release for your platform:\x1b[0m',
|
|
440
|
+
` https://github.com/unfoundbox-crew/agentworth/releases/latest`,
|
|
265
441
|
'',
|
|
266
442
|
' \x1b[36m• Set custom binary path:\x1b[0m',
|
|
267
443
|
' export AGENTWORTH_BIN=/path/to/agentworth',
|
|
@@ -278,7 +454,32 @@ export function formatMissingBinaryMessage(platformKey = getPlatformKey()) {
|
|
|
278
454
|
*/
|
|
279
455
|
export function run(argv = process.argv.slice(2), options = {}) {
|
|
280
456
|
const resolvedArgs = resolveArguments(argv);
|
|
281
|
-
|
|
457
|
+
let binaryResult = resolveBinary(options);
|
|
458
|
+
|
|
459
|
+
// If binary not found on clean machine, attempt on-demand download from GitHub Release
|
|
460
|
+
if ((!binaryResult.found || !binaryResult.path) && options.autoDownload !== false) {
|
|
461
|
+
try {
|
|
462
|
+
const resolverModuleUrl = new URL('./resolver.js', import.meta.url).href;
|
|
463
|
+
const syncDownloadScript = `
|
|
464
|
+
import { downloadAndExtractBinary } from '${resolverModuleUrl}';
|
|
465
|
+
await downloadAndExtractBinary({
|
|
466
|
+
platform: ${JSON.stringify(options.platform || process.platform)},
|
|
467
|
+
arch: ${JSON.stringify(options.arch || process.arch)},
|
|
468
|
+
homeDir: ${JSON.stringify(options.homeDir || (options.env && options.env.HOME) || '')}
|
|
469
|
+
});
|
|
470
|
+
`;
|
|
471
|
+
const dlResult = spawnSync(process.execPath, ['--input-type=module', '-e', syncDownloadScript], {
|
|
472
|
+
stdio: 'inherit',
|
|
473
|
+
env: options.env || process.env,
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
if (dlResult.status === 0) {
|
|
477
|
+
binaryResult = resolveBinary(options);
|
|
478
|
+
}
|
|
479
|
+
} catch {
|
|
480
|
+
// Fall through to error message below
|
|
481
|
+
}
|
|
482
|
+
}
|
|
282
483
|
|
|
283
484
|
if (!binaryResult.found || !binaryResult.path) {
|
|
284
485
|
const message = formatMissingBinaryMessage(getPlatformKey(options.platform, options.arch));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentworth",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Discover, normalize, and understand AI-agent histories locally.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/resolver.js",
|
|
@@ -23,8 +23,16 @@
|
|
|
23
23
|
"analytics",
|
|
24
24
|
"developer-tools"
|
|
25
25
|
],
|
|
26
|
-
"author": "Unfoundbox",
|
|
26
|
+
"author": "Unfoundbox Crew",
|
|
27
27
|
"license": "Apache-2.0",
|
|
28
|
+
"homepage": "https://agentworth.dev",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/unfoundbox-crew/agentworth.git"
|
|
32
|
+
},
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/unfoundbox-crew/agentworth/issues"
|
|
35
|
+
},
|
|
28
36
|
"engines": {
|
|
29
37
|
"node": ">=18.0.0"
|
|
30
38
|
},
|