@webnori/agent-one 0.5.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 +54 -0
- package/bin/agent-one.js +41 -0
- package/package.json +48 -0
- package/scripts/install.js +180 -0
- package/scripts/uninstall.js +18 -0
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# @webnori/agent-one
|
|
2
|
+
|
|
3
|
+
A standalone CLI agent: ask a question, it reads your workspace through a small
|
|
4
|
+
set of tools and answers. Windows, macOS and Linux.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npm install -g @webnori/agent-one
|
|
8
|
+
|
|
9
|
+
agent-one run "hello" --provider echo # offline smoke test, no API key
|
|
10
|
+
agent-one run "what does this project do?"
|
|
11
|
+
agent-one chat
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## What this package is
|
|
15
|
+
|
|
16
|
+
A thin wrapper. It ships **no binary**: `postinstall` downloads the native
|
|
17
|
+
`agent-one` build for your OS/arch from the matching GitHub Release, verifies
|
|
18
|
+
its SHA256 against `checksums.txt`, and unpacks it next to the launcher. The npm
|
|
19
|
+
version and the release tag are published together, so they cannot drift.
|
|
20
|
+
|
|
21
|
+
Supported: `win-x64`, `linux-x64`, `osx-arm64` (Node ≥ 18). Intel Macs (`osx-x64`) have no prebuilt binary — build from source.
|
|
22
|
+
|
|
23
|
+
## Configuration
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
agent-one config set provider openai
|
|
27
|
+
agent-one config set model gpt-4o-mini
|
|
28
|
+
export OPENAI_API_KEY=sk-...
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Any OpenAI-compatible endpoint works — Ollama, LM Studio, vLLM, llama.cpp:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
agent-one config set baseUrl http://localhost:11434/v1
|
|
35
|
+
agent-one config set model qwen2.5-coder:7b
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Settings live in `~/.agent-one/config.json`. The API key is never written
|
|
39
|
+
there — `apiKeyEnv` names the environment variable to read it from.
|
|
40
|
+
|
|
41
|
+
## Environment variables
|
|
42
|
+
|
|
43
|
+
| Variable | Effect |
|
|
44
|
+
|---|---|
|
|
45
|
+
| `AGENT_ONE_SKIP_DOWNLOAD=1` | Skip the postinstall download (offline / vendored installs) |
|
|
46
|
+
| `AGENT_ONE_VERSION` | Download a specific release instead of the package version |
|
|
47
|
+
| `AGENT_ONE_REPO` | Download from a fork instead of `psmon/AgentZeroLite` |
|
|
48
|
+
| `AGENT_ONE_HOME` | Relocate `~/.agent-one/` |
|
|
49
|
+
|
|
50
|
+
Uninstalling removes only the downloaded binary; `~/.agent-one/` is your data
|
|
51
|
+
and is left where it is.
|
|
52
|
+
|
|
53
|
+
Full documentation:
|
|
54
|
+
<https://github.com/psmon/AgentZeroLite/tree/main/Project/AgentOne>
|
package/bin/agent-one.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
//
|
|
3
|
+
// Thin launcher — forwards argv to the native agent-one binary that
|
|
4
|
+
// scripts/install.js placed in ../vendor/agent-one/.
|
|
5
|
+
//
|
|
6
|
+
// It stays thin on purpose: every flag, every exit code and every byte of
|
|
7
|
+
// output belongs to the binary, so `agent-one` behaves identically whether it
|
|
8
|
+
// was installed from npm, from a release ZIP, or built from source.
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const { spawnSync } = require('child_process');
|
|
15
|
+
|
|
16
|
+
const PKG = '@webnori/agent-one';
|
|
17
|
+
const exeName = process.platform === 'win32' ? 'agent-one.exe' : 'agent-one';
|
|
18
|
+
const vendorBin = path.resolve(__dirname, '..', 'vendor', 'agent-one', exeName);
|
|
19
|
+
|
|
20
|
+
if (!fs.existsSync(vendorBin)) {
|
|
21
|
+
console.error(`${PKG}: binary not found at ${vendorBin}`);
|
|
22
|
+
console.error(`${PKG}: did the postinstall step run? Try reinstalling:`);
|
|
23
|
+
console.error(`${PKG}: npm install -g ${PKG} --force`);
|
|
24
|
+
console.error(`${PKG}: or install it manually from`);
|
|
25
|
+
console.error(`${PKG}: https://github.com/psmon/AgentZeroLite/releases`);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const result = spawnSync(vendorBin, process.argv.slice(2), {
|
|
30
|
+
stdio: 'inherit',
|
|
31
|
+
windowsHide: false
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (result.error) {
|
|
35
|
+
console.error(`${PKG}: failed to spawn binary: ${result.error.message}`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Preserve the child's exit code; a signal death becomes 128+n like a shell would report.
|
|
40
|
+
if (result.signal) process.exit(1);
|
|
41
|
+
process.exit(result.status ?? 0);
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@webnori/agent-one",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "A standalone CLI agent: ask a question, it reads your workspace and answers. (npm wrapper around the prebuilt agent-one binary.)",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"agent",
|
|
7
|
+
"cli",
|
|
8
|
+
"llm",
|
|
9
|
+
"openai-compatible",
|
|
10
|
+
"ollama",
|
|
11
|
+
"tool-use"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/psmon/AgentZeroLite/tree/main/Project/AgentOne",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/psmon/AgentZeroLite/issues"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/psmon/AgentZeroLite.git",
|
|
20
|
+
"directory": "Project/AgentOne/packaging/npm/agent-one"
|
|
21
|
+
},
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"author": "psmon",
|
|
24
|
+
"bin": {
|
|
25
|
+
"agent-one": "bin/agent-one.js"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"bin/",
|
|
29
|
+
"scripts/",
|
|
30
|
+
"README.md"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"postinstall": "node scripts/install.js",
|
|
34
|
+
"preuninstall": "node scripts/uninstall.js"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18"
|
|
38
|
+
},
|
|
39
|
+
"os": [
|
|
40
|
+
"linux",
|
|
41
|
+
"darwin",
|
|
42
|
+
"win32"
|
|
43
|
+
],
|
|
44
|
+
"cpu": [
|
|
45
|
+
"x64",
|
|
46
|
+
"arm64"
|
|
47
|
+
]
|
|
48
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
//
|
|
3
|
+
// postinstall: download the agent-one binary for this OS/arch from GitHub
|
|
4
|
+
// Releases, verify its SHA256 against checksums.txt, extract into
|
|
5
|
+
// ../vendor/agent-one/.
|
|
6
|
+
//
|
|
7
|
+
// User data in ~/.agent-one/ (config, sessions) is never touched — install and
|
|
8
|
+
// uninstall only ever manage the vendored binary.
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const os = require('os');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const crypto = require('crypto');
|
|
16
|
+
const https = require('https');
|
|
17
|
+
const { execFileSync } = require('child_process');
|
|
18
|
+
|
|
19
|
+
const PKG = '@webnori/agent-one';
|
|
20
|
+
const REPO = process.env.AGENT_ONE_REPO || 'psmon/AgentZeroLite';
|
|
21
|
+
const TAG_PREFIX = 'agent-one-v';
|
|
22
|
+
|
|
23
|
+
function log(msg) { process.stdout.write(`${PKG}: ${msg}\n`); }
|
|
24
|
+
function warn(msg) { process.stderr.write(`${PKG}: ${msg}\n`); }
|
|
25
|
+
function die(msg) { warn(msg); process.exit(1); }
|
|
26
|
+
|
|
27
|
+
// 1. Opt-out, for offline CI and mirrored caches that vendor the binary themselves.
|
|
28
|
+
if (process.env.AGENT_ONE_SKIP_DOWNLOAD === '1') {
|
|
29
|
+
log('AGENT_ONE_SKIP_DOWNLOAD=1 — skipping binary download.');
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 2. platform/arch -> .NET RID
|
|
34
|
+
const rid = (() => {
|
|
35
|
+
const arch = ({ x64: 'x64', arm64: 'arm64' })[process.arch];
|
|
36
|
+
if (!arch) die(`unsupported CPU arch: ${process.arch}`);
|
|
37
|
+
if (process.platform === 'linux') return `linux-${arch}`;
|
|
38
|
+
if (process.platform === 'darwin') return `osx-${arch}`;
|
|
39
|
+
if (process.platform === 'win32') return `win-${arch}`;
|
|
40
|
+
return die(`unsupported platform: ${process.platform}`);
|
|
41
|
+
})();
|
|
42
|
+
|
|
43
|
+
// Intel Macs are not built (the macOS x64 runners were retired); say so rather than 404.
|
|
44
|
+
if (rid === 'osx-x64') {
|
|
45
|
+
die('no prebuilt binary for Intel Macs (osx-x64). Build from source: ' +
|
|
46
|
+
'dotnet publish Project/AgentOne/AgentOne.csproj -c Release -r osx-x64 ' +
|
|
47
|
+
'(https://github.com/psmon/AgentZeroLite/tree/main/Project/AgentOne)');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const ext = process.platform === 'win32' ? 'zip' : 'tar.gz';
|
|
51
|
+
const asset = `agent-one-${rid}.${ext}`;
|
|
52
|
+
|
|
53
|
+
// 3. The npm version IS the release tag — they are published together.
|
|
54
|
+
const pkg = require(path.resolve(__dirname, '..', 'package.json'));
|
|
55
|
+
const version = process.env.AGENT_ONE_VERSION || pkg.version;
|
|
56
|
+
if (!version || version === '0.0.0') {
|
|
57
|
+
die('package.json version is unset (0.0.0). Publish with a real version, or set AGENT_ONE_VERSION.');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const tag = version.startsWith(TAG_PREFIX) ? version : TAG_PREFIX + version.replace(/^v/, '');
|
|
61
|
+
const base = `https://github.com/${REPO}/releases/download/${tag}`;
|
|
62
|
+
const assetUrl = `${base}/${asset}`;
|
|
63
|
+
const sumsUrl = `${base}/checksums.txt`;
|
|
64
|
+
|
|
65
|
+
function get(url, redirectsLeft = 5) {
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
if (redirectsLeft < 0) return reject(new Error('too many redirects'));
|
|
68
|
+
const opts = { headers: { 'User-Agent': 'agent-one-npm-installer' } };
|
|
69
|
+
https.get(url, opts, (res) => {
|
|
70
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
71
|
+
res.resume();
|
|
72
|
+
return resolve(get(res.headers.location, redirectsLeft - 1));
|
|
73
|
+
}
|
|
74
|
+
if (res.statusCode !== 200) {
|
|
75
|
+
res.resume();
|
|
76
|
+
return reject(new Error(`HTTP ${res.statusCode} for ${url}`));
|
|
77
|
+
}
|
|
78
|
+
resolve(res);
|
|
79
|
+
}).on('error', reject);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function download(url, destPath) {
|
|
84
|
+
const res = await get(url);
|
|
85
|
+
await new Promise((resolve, reject) => {
|
|
86
|
+
const out = fs.createWriteStream(destPath);
|
|
87
|
+
res.pipe(out);
|
|
88
|
+
out.on('finish', resolve);
|
|
89
|
+
out.on('error', reject);
|
|
90
|
+
res.on('error', reject);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function fetchText(url) {
|
|
95
|
+
const res = await get(url);
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
let buf = '';
|
|
98
|
+
res.on('data', (c) => { buf += c.toString('utf8'); });
|
|
99
|
+
res.on('end', () => resolve(buf));
|
|
100
|
+
res.on('error', reject);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function sha256(file) {
|
|
105
|
+
return crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function extract(archive, destDir) {
|
|
109
|
+
if (ext === 'zip') {
|
|
110
|
+
try {
|
|
111
|
+
execFileSync('powershell', [
|
|
112
|
+
'-NoProfile', '-NonInteractive', '-Command',
|
|
113
|
+
`Expand-Archive -LiteralPath '${archive}' -DestinationPath '${destDir}' -Force`
|
|
114
|
+
], { stdio: 'inherit' });
|
|
115
|
+
return;
|
|
116
|
+
} catch {
|
|
117
|
+
execFileSync('unzip', ['-o', archive, '-d', destDir], { stdio: 'inherit' });
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
execFileSync('tar', ['-xzf', archive, '-C', destDir], { stdio: 'inherit' });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function main() {
|
|
125
|
+
const root = path.resolve(__dirname, '..');
|
|
126
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-one-install-'));
|
|
127
|
+
const archive = path.join(tmp, asset);
|
|
128
|
+
|
|
129
|
+
log(`release ${tag}, platform ${rid}`);
|
|
130
|
+
log(`downloading ${assetUrl}`);
|
|
131
|
+
try {
|
|
132
|
+
await download(assetUrl, archive);
|
|
133
|
+
} catch (e) {
|
|
134
|
+
die(`download failed: ${e.message}\n manual install: ${assetUrl}`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// A checksum that cannot be fetched is a warning, but one that does not
|
|
138
|
+
// match is fatal — a wrong binary is worse than no binary.
|
|
139
|
+
let expected = null;
|
|
140
|
+
try {
|
|
141
|
+
const sums = await fetchText(sumsUrl);
|
|
142
|
+
for (const line of sums.split(/\r?\n/)) {
|
|
143
|
+
if (line.includes(asset)) { expected = line.trim().split(/\s+/)[0]; break; }
|
|
144
|
+
}
|
|
145
|
+
} catch (e) {
|
|
146
|
+
warn(`could not fetch checksums.txt (${e.message}) — continuing without verification`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (expected) {
|
|
150
|
+
const actual = sha256(archive);
|
|
151
|
+
if (actual.toLowerCase() !== expected.toLowerCase()) {
|
|
152
|
+
die(`checksum mismatch\n expected: ${expected}\n actual: ${actual}`);
|
|
153
|
+
}
|
|
154
|
+
log(`sha256 verified: ${actual}`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const vendor = path.join(root, 'vendor');
|
|
158
|
+
fs.rmSync(vendor, { recursive: true, force: true });
|
|
159
|
+
fs.mkdirSync(vendor, { recursive: true });
|
|
160
|
+
|
|
161
|
+
log(`extracting into ${vendor}`);
|
|
162
|
+
try {
|
|
163
|
+
extract(archive, vendor);
|
|
164
|
+
} catch (e) {
|
|
165
|
+
die(`extraction failed: ${e.message}`);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const exeName = process.platform === 'win32' ? 'agent-one.exe' : 'agent-one';
|
|
169
|
+
const finalBin = path.join(vendor, 'agent-one', exeName);
|
|
170
|
+
if (!fs.existsSync(finalBin)) {
|
|
171
|
+
die(`expected ${finalBin} after extraction, but it is not there`);
|
|
172
|
+
}
|
|
173
|
+
if (process.platform !== 'win32') fs.chmodSync(finalBin, 0o755);
|
|
174
|
+
|
|
175
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
176
|
+
log(`installed ${finalBin}`);
|
|
177
|
+
log('try: agent-one run "hello" --provider echo');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
main().catch((e) => die(e.stack || e.message));
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
//
|
|
3
|
+
// preuninstall: remove only the vendored binary this package downloaded.
|
|
4
|
+
// ~/.agent-one/ (config, sessions) is the user's data and is left alone —
|
|
5
|
+
// reinstalling should find the same settings where they were.
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
|
|
12
|
+
const vendor = path.resolve(__dirname, '..', 'vendor');
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
fs.rmSync(vendor, { recursive: true, force: true });
|
|
16
|
+
} catch (e) {
|
|
17
|
+
process.stderr.write(`@webnori/agent-one: could not remove ${vendor}: ${e.message}\n`);
|
|
18
|
+
}
|