nanoai-cli 1.0.7 → 1.0.9
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 +84 -25
- package/package.json +2 -1
- package/scripts/download.js +6 -3
- package/scripts/platform.js +5 -2
- package/scripts/update.js +244 -0
- package/bin/nanoai.js +0 -62
package/README.md
CHANGED
|
@@ -1,54 +1,113 @@
|
|
|
1
|
-
#
|
|
1
|
+
# nanoai-cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`nanoai-cli` installs the NanoAgent CLI as the `nanoai` command.
|
|
4
4
|
|
|
5
|
-
This package is a thin installer:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
NanoAgent is a local AI coding agent for terminal workflows, ACP-compatible editors, and automation. This npm package is a thin installer: it downloads the matching self-contained NanoAgent release for your platform, verifies it against the published `SHA256SUMS`, and launches it without requiring a .NET toolchain.
|
|
6
|
+
|
|
7
|
+
## Why use this package
|
|
8
|
+
|
|
9
|
+
- Install NanoAgent with `npm`, `pnpm`, or `bun`.
|
|
10
|
+
- Download the correct native binary for the current platform automatically.
|
|
11
|
+
- Verify release archives before extraction with published SHA-256 checksums.
|
|
12
|
+
- Recover automatically on first run if `postinstall` was skipped or the binary is missing.
|
|
9
13
|
|
|
10
14
|
## Install
|
|
11
15
|
|
|
12
16
|
```bash
|
|
13
|
-
npm install -g
|
|
17
|
+
npm install -g nanoai-cli
|
|
14
18
|
# or
|
|
15
|
-
|
|
19
|
+
pnpm add -g nanoai-cli
|
|
16
20
|
# or
|
|
17
|
-
|
|
21
|
+
bun add -g nanoai-cli
|
|
18
22
|
```
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
Start NanoAgent:
|
|
21
25
|
|
|
22
26
|
```bash
|
|
23
27
|
nanoai
|
|
24
28
|
```
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
If you want a quick non-interactive smoke test after install:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
nanoai --version
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## How installation works
|
|
37
|
+
|
|
38
|
+
On install, the package tries to:
|
|
39
|
+
|
|
40
|
+
1. Resolve the correct release asset for the current OS and CPU architecture.
|
|
41
|
+
2. Download the matching `NanoAgent.CLI-<rid>.zip` archive from GitHub Releases.
|
|
42
|
+
3. Download `SHA256SUMS` from the same release.
|
|
43
|
+
4. Verify the archive checksum before extraction.
|
|
44
|
+
5. Extract the NanoAgent binary into the package's `vendor/` directory.
|
|
45
|
+
|
|
46
|
+
If the download is skipped or fails during `postinstall`, installation still succeeds. The launcher downloads the binary automatically the first time you run `nanoai`.
|
|
47
|
+
|
|
48
|
+
## bun note
|
|
49
|
+
|
|
50
|
+
`bun add` skips `postinstall` scripts by default, so the binary is usually downloaded on first launch instead of during installation.
|
|
51
|
+
|
|
52
|
+
To fetch it eagerly after installing with bun, run:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
bunx nanoai-cli --version
|
|
56
|
+
```
|
|
29
57
|
|
|
30
58
|
## Supported platforms
|
|
31
59
|
|
|
32
|
-
| OS
|
|
33
|
-
|
|
|
34
|
-
| Windows | x64
|
|
35
|
-
| macOS
|
|
36
|
-
| Linux
|
|
60
|
+
| OS | Architectures |
|
|
61
|
+
| --- | --- |
|
|
62
|
+
| Windows | x64 |
|
|
63
|
+
| macOS | x64, arm64 |
|
|
64
|
+
| Linux | x64, arm64 |
|
|
65
|
+
|
|
66
|
+
## Updates
|
|
67
|
+
|
|
68
|
+
By default, the package downloads the release tag that matches the npm package version, using `v<package-version>`.
|
|
69
|
+
|
|
70
|
+
At runtime, the launcher can also check GitHub for a newer NanoAgent release. When running interactively, it prompts before replacing the installed binary with the latest release and then continues launch.
|
|
71
|
+
|
|
72
|
+
Skip the runtime update prompt with either:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
nanoai --no-update-check
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
or:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
NANOAGENT_SKIP_UPDATE_CHECK=1 nanoai
|
|
82
|
+
```
|
|
37
83
|
|
|
38
84
|
## Environment variables
|
|
39
85
|
|
|
40
|
-
| Variable
|
|
41
|
-
|
|
|
42
|
-
| `NANOAGENT_SKIP_DOWNLOAD` | Set to `1` to skip the
|
|
43
|
-
| `
|
|
44
|
-
| `
|
|
86
|
+
| Variable | Purpose |
|
|
87
|
+
| --- | --- |
|
|
88
|
+
| `NANOAGENT_SKIP_DOWNLOAD` | Set to `1` to skip the install-time download. The binary will still be fetched on first run. |
|
|
89
|
+
| `NANOAGENT_SKIP_UPDATE_CHECK` | Set to `1` to disable the runtime check for newer GitHub releases. |
|
|
90
|
+
| `NANOAGENT_CLI_TAG` | Override the release tag to download, such as `v1.2.3`. |
|
|
91
|
+
| `NANOAGENT_CLI_VERSION` | Override the version used to derive the default release tag. |
|
|
92
|
+
| `NANOAGENT_CLI_BASE_URL` | Override the release asset base URL for mirrors, testing, or private distribution. |
|
|
93
|
+
|
|
94
|
+
## Manual reinstall
|
|
45
95
|
|
|
46
|
-
|
|
96
|
+
If you need to force a fresh binary download for a local install, run:
|
|
47
97
|
|
|
48
98
|
```bash
|
|
49
|
-
node node_modules/
|
|
99
|
+
node ./node_modules/nanoai-cli/scripts/download.js
|
|
50
100
|
```
|
|
51
101
|
|
|
102
|
+
If the package was installed globally, reinstalling the package is usually the simplest way to refresh the bundled launcher files.
|
|
103
|
+
|
|
104
|
+
## Learn more
|
|
105
|
+
|
|
106
|
+
- Product overview: [NanoAgent README](https://github.com/rizwan3d/NanoAgent#readme)
|
|
107
|
+
- Full documentation: [docs/documentation.md](https://github.com/rizwan3d/NanoAgent/blob/master/docs/documentation.md)
|
|
108
|
+
- Releases: [GitHub Releases](https://github.com/rizwan3d/NanoAgent/releases)
|
|
109
|
+
- Issues: [GitHub Issues](https://github.com/rizwan3d/NanoAgent/issues)
|
|
110
|
+
|
|
52
111
|
## License
|
|
53
112
|
|
|
54
113
|
Apache-2.0
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nanoai-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "Terminal UI, ACP server, and automation-friendly CLI for NanoAgent.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nanoagent",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"arm64"
|
|
48
48
|
],
|
|
49
49
|
"dependencies": {
|
|
50
|
+
"@inquirer/select": "^4.4.0",
|
|
50
51
|
"adm-zip": "^0.5.16"
|
|
51
52
|
}
|
|
52
53
|
}
|
package/scripts/download.js
CHANGED
|
@@ -77,7 +77,7 @@ function extractExecutable(zipBuffer, destinationPath) {
|
|
|
77
77
|
|
|
78
78
|
// Ensures the platform binary is present in vendor/. Returns the absolute path.
|
|
79
79
|
async function ensureBinary(options = {}) {
|
|
80
|
-
const { force = false, log = () => {} } = options;
|
|
80
|
+
const { force = false, log = () => {}, tag } = options;
|
|
81
81
|
|
|
82
82
|
const binaryPath = platform.installedBinaryPath();
|
|
83
83
|
if (!force && fs.existsSync(binaryPath)) {
|
|
@@ -86,11 +86,14 @@ async function ensureBinary(options = {}) {
|
|
|
86
86
|
|
|
87
87
|
const rid = platform.resolveRid();
|
|
88
88
|
const asset = platform.assetName(rid);
|
|
89
|
-
const
|
|
89
|
+
const resolvedTag = tag && tag.trim()
|
|
90
|
+
? tag.trim()
|
|
91
|
+
: platform.resolveTag();
|
|
92
|
+
const base = platform.baseDownloadUrl(resolvedTag);
|
|
90
93
|
const assetUrl = `${base}/${asset}`;
|
|
91
94
|
const checksumsUrl = `${base}/${platform.CHECKSUMS_NAME}`;
|
|
92
95
|
|
|
93
|
-
log(`Downloading ${asset} (${
|
|
96
|
+
log(`Downloading ${asset} (${resolvedTag})...`);
|
|
94
97
|
const archiveBuffer = await fetchBuffer(assetUrl);
|
|
95
98
|
|
|
96
99
|
log(`Verifying ${platform.CHECKSUMS_NAME}...`);
|
package/scripts/platform.js
CHANGED
|
@@ -62,12 +62,15 @@ function resolveTag() {
|
|
|
62
62
|
return `v${resolveVersion()}`;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
function baseDownloadUrl() {
|
|
65
|
+
function baseDownloadUrl(tagOverride) {
|
|
66
66
|
const override = process.env.NANOAGENT_CLI_BASE_URL;
|
|
67
67
|
if (override && override.trim()) {
|
|
68
68
|
return override.trim().replace(/\/+$/, "");
|
|
69
69
|
}
|
|
70
|
-
|
|
70
|
+
const tag = tagOverride && tagOverride.trim()
|
|
71
|
+
? tagOverride.trim()
|
|
72
|
+
: resolveTag();
|
|
73
|
+
return `https://github.com/${OWNER}/${REPO}/releases/download/${tag}`;
|
|
71
74
|
}
|
|
72
75
|
|
|
73
76
|
function assetName(rid) {
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const { spawnSync } = require("child_process");
|
|
5
|
+
|
|
6
|
+
const platform = require("./platform");
|
|
7
|
+
const { ensureBinary } = require("./download");
|
|
8
|
+
|
|
9
|
+
const LatestReleaseApiUrl = `https://api.github.com/repos/${platform.OWNER}/${platform.REPO}/releases/latest`;
|
|
10
|
+
const VersionPattern = /\b(?:NanoAgent\s+CLI\s+)?v?(\d+(?:\.\d+){1,3}(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?)\b/i;
|
|
11
|
+
|
|
12
|
+
function normalizeVersionText(value) {
|
|
13
|
+
if (!value || !value.trim()) {
|
|
14
|
+
return "0.0.0";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let normalized = value.trim();
|
|
18
|
+
const metadataIndex = normalized.indexOf("+");
|
|
19
|
+
if (metadataIndex >= 0) {
|
|
20
|
+
normalized = normalized.slice(0, metadataIndex);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (normalized.startsWith("v") || normalized.startsWith("V")) {
|
|
24
|
+
normalized = normalized.slice(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return normalized;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function parseComparableVersion(value) {
|
|
31
|
+
const normalized = normalizeVersionText(value);
|
|
32
|
+
const prereleaseIndex = normalized.indexOf("-");
|
|
33
|
+
const releasePart = prereleaseIndex >= 0
|
|
34
|
+
? normalized.slice(0, prereleaseIndex)
|
|
35
|
+
: normalized;
|
|
36
|
+
const segments = releasePart
|
|
37
|
+
.split(".")
|
|
38
|
+
.map((segment) => Number.parseInt(segment, 10));
|
|
39
|
+
|
|
40
|
+
if (segments.length === 0 || segments.some((segment) => !Number.isFinite(segment))) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
while (segments.length < 4) {
|
|
45
|
+
segments.push(0);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
normalized,
|
|
50
|
+
segments,
|
|
51
|
+
hasPrerelease: prereleaseIndex >= 0,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function compareVersions(left, right) {
|
|
56
|
+
const parsedLeft = parseComparableVersion(left);
|
|
57
|
+
const parsedRight = parseComparableVersion(right);
|
|
58
|
+
|
|
59
|
+
if (!parsedLeft || !parsedRight) {
|
|
60
|
+
const normalizedLeft = normalizeVersionText(left);
|
|
61
|
+
const normalizedRight = normalizeVersionText(right);
|
|
62
|
+
return normalizedLeft.localeCompare(normalizedRight, undefined, { numeric: true, sensitivity: "base" });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
for (let index = 0; index < Math.max(parsedLeft.segments.length, parsedRight.segments.length); index += 1) {
|
|
66
|
+
const leftSegment = parsedLeft.segments[index] ?? 0;
|
|
67
|
+
const rightSegment = parsedRight.segments[index] ?? 0;
|
|
68
|
+
if (leftSegment !== rightSegment) {
|
|
69
|
+
return leftSegment - rightSegment;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (parsedLeft.hasPrerelease !== parsedRight.hasPrerelease) {
|
|
74
|
+
return parsedLeft.hasPrerelease ? -1 : 1;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return parsedLeft.normalized.localeCompare(
|
|
78
|
+
parsedRight.normalized,
|
|
79
|
+
undefined,
|
|
80
|
+
{ numeric: true, sensitivity: "base" }
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function fetchLatestRelease(options = {}) {
|
|
85
|
+
const { timeoutMs = 4000 } = options;
|
|
86
|
+
if (typeof fetch !== "function") {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const response = await fetch(LatestReleaseApiUrl, {
|
|
91
|
+
headers: {
|
|
92
|
+
"Accept": "application/vnd.github+json",
|
|
93
|
+
"User-Agent": `${platform.APP_NAME}-npm-launcher`,
|
|
94
|
+
},
|
|
95
|
+
redirect: "follow",
|
|
96
|
+
signal: typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function"
|
|
97
|
+
? AbortSignal.timeout(timeoutMs)
|
|
98
|
+
: undefined,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
if (!response.ok) {
|
|
102
|
+
throw new Error(`GitHub returned HTTP ${response.status} ${response.statusText}.`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const payload = await response.json();
|
|
106
|
+
const tag = typeof payload?.tag_name === "string" ? payload.tag_name.trim() : "";
|
|
107
|
+
if (!tag) {
|
|
108
|
+
throw new Error("GitHub did not return a release tag.");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const releaseUrl = typeof payload?.html_url === "string" && payload.html_url.trim()
|
|
112
|
+
? payload.html_url.trim()
|
|
113
|
+
: `https://github.com/${platform.OWNER}/${platform.REPO}/releases/latest`;
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
tag,
|
|
117
|
+
version: normalizeVersionText(tag),
|
|
118
|
+
releaseUrl,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function readInstalledBinaryVersion(binaryPath) {
|
|
123
|
+
if (!binaryPath || !fs.existsSync(binaryPath)) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
const result = spawnSync(binaryPath, ["--version"], {
|
|
129
|
+
encoding: "utf8",
|
|
130
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
131
|
+
timeout: 10000,
|
|
132
|
+
windowsHide: true,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
const combined = `${result.stdout || ""}\n${result.stderr || ""}`;
|
|
136
|
+
const match = combined.match(VersionPattern);
|
|
137
|
+
return match?.[1] ? normalizeVersionText(match[1]) : null;
|
|
138
|
+
} catch {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function shouldSkipRuntimeUpdateCheck() {
|
|
144
|
+
if (process.env.NANOAGENT_SKIP_UPDATE_CHECK === "1") {
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (process.env.NANOAGENT_CLI_TAG || process.env.NANOAGENT_CLI_BASE_URL || process.env.NANOAGENT_CLI_VERSION) {
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return process.argv.slice(2).some((arg) => arg === "--no-update-check");
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function canPromptForUpdate() {
|
|
156
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function promptForUpdate(currentVersion, latestVersion) {
|
|
160
|
+
const { default: select } = await import("@inquirer/select");
|
|
161
|
+
|
|
162
|
+
return await select({
|
|
163
|
+
message: `NanoAgent ${latestVersion} is available. Update before launch?`,
|
|
164
|
+
choices: [
|
|
165
|
+
{
|
|
166
|
+
name: `Yes, update from ${currentVersion} to ${latestVersion}`,
|
|
167
|
+
value: true,
|
|
168
|
+
description: "Downloads the latest NanoAgent CLI binary, then starts nanoai.",
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: `No, continue with ${currentVersion}`,
|
|
172
|
+
value: false,
|
|
173
|
+
description: "Skip this update check and launch the currently installed binary.",
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
default: false,
|
|
177
|
+
loop: false,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async function maybeUpdateBinary(binaryPath, options = {}) {
|
|
182
|
+
const { log = () => {} } = options;
|
|
183
|
+
|
|
184
|
+
if (shouldSkipRuntimeUpdateCheck()) {
|
|
185
|
+
return binaryPath;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
let latestRelease;
|
|
189
|
+
try {
|
|
190
|
+
latestRelease = await fetchLatestRelease();
|
|
191
|
+
} catch {
|
|
192
|
+
return binaryPath;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (!latestRelease) {
|
|
196
|
+
return binaryPath;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const currentVersion = readInstalledBinaryVersion(binaryPath) || normalizeVersionText(platform.resolveVersion());
|
|
200
|
+
if (compareVersions(latestRelease.version, currentVersion) <= 0) {
|
|
201
|
+
return binaryPath;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (!canPromptForUpdate()) {
|
|
205
|
+
return binaryPath;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
let shouldUpdate;
|
|
209
|
+
try {
|
|
210
|
+
shouldUpdate = await promptForUpdate(currentVersion, latestRelease.version);
|
|
211
|
+
} catch {
|
|
212
|
+
return binaryPath;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (!shouldUpdate) {
|
|
216
|
+
return binaryPath;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
log(`Updating NanoAgent CLI to ${latestRelease.tag}...`);
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
return await ensureBinary({
|
|
223
|
+
force: true,
|
|
224
|
+
tag: latestRelease.tag,
|
|
225
|
+
log,
|
|
226
|
+
});
|
|
227
|
+
} catch (error) {
|
|
228
|
+
const message = error && error.message
|
|
229
|
+
? error.message
|
|
230
|
+
: String(error);
|
|
231
|
+
log(`Update failed: ${message}`);
|
|
232
|
+
log("Starting the currently installed NanoAgent CLI instead.");
|
|
233
|
+
return binaryPath;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
module.exports = {
|
|
238
|
+
compareVersions,
|
|
239
|
+
fetchLatestRelease,
|
|
240
|
+
maybeUpdateBinary,
|
|
241
|
+
normalizeVersionText,
|
|
242
|
+
readInstalledBinaryVersion,
|
|
243
|
+
shouldSkipRuntimeUpdateCheck,
|
|
244
|
+
};
|
package/bin/nanoai.js
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
|
|
4
|
-
// Launcher for the NanoAgent CLI. Spawns the vendored native binary, passing
|
|
5
|
-
// through all arguments, stdio, and the exit code. If the binary is missing
|
|
6
|
-
// (e.g. postinstall was skipped by bun, or a prior download failed), it is
|
|
7
|
-
// downloaded on demand before the first launch.
|
|
8
|
-
|
|
9
|
-
const fs = require("fs");
|
|
10
|
-
const { spawn } = require("child_process");
|
|
11
|
-
|
|
12
|
-
const platform = require("../scripts/platform");
|
|
13
|
-
|
|
14
|
-
function launch(binaryPath) {
|
|
15
|
-
const child = spawn(binaryPath, process.argv.slice(2), { stdio: "inherit" });
|
|
16
|
-
|
|
17
|
-
child.on("error", (err) => {
|
|
18
|
-
console.error(`[nanoagent] Failed to start NanoAgent CLI: ${err.message}`);
|
|
19
|
-
process.exit(1);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
child.on("exit", (code, signal) => {
|
|
23
|
-
if (signal) {
|
|
24
|
-
// Re-raise the terminating signal so shells see the real cause.
|
|
25
|
-
process.kill(process.pid, signal);
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
process.exit(code === null ? 1 : code);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
// Forward termination signals to the child so Ctrl+C behaves normally.
|
|
32
|
-
for (const sig of ["SIGINT", "SIGTERM", "SIGHUP"]) {
|
|
33
|
-
process.on(sig, () => {
|
|
34
|
-
if (!child.killed) {
|
|
35
|
-
try {
|
|
36
|
-
child.kill(sig);
|
|
37
|
-
} catch {
|
|
38
|
-
/* child already gone */
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async function main() {
|
|
46
|
-
const binaryPath = platform.installedBinaryPath();
|
|
47
|
-
|
|
48
|
-
if (!fs.existsSync(binaryPath)) {
|
|
49
|
-
const { ensureBinary } = require("../scripts/download");
|
|
50
|
-
try {
|
|
51
|
-
await ensureBinary({ log: (m) => console.error(`[nanoagent] ${m}`) });
|
|
52
|
-
} catch (err) {
|
|
53
|
-
console.error(`[nanoagent] Unable to download the NanoAgent CLI binary: ${err.message}`);
|
|
54
|
-
console.error("[nanoagent] Check your network connection and try running `nanoai` again.");
|
|
55
|
-
process.exit(1);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
launch(binaryPath);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
main();
|