infynon 0.2.5 → 0.2.7
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 +56 -8
- package/package.json +53 -34
- package/postinstall.js +373 -18
- package/preuninstall.js +3 -48
- package/run.js +244 -24
package/README.md
CHANGED
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
# infynon
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/infynon)
|
|
4
|
+
[](https://www.npmjs.com/package/infynon)
|
|
5
|
+
[](https://github.com/d4rkNinja/infynon-cli/releases)
|
|
6
|
+
[](https://github.com/d4rkNinja/infynon-cli/blob/main/docs/agent-control-plane.md)
|
|
7
|
+
[](https://github.com/d4rkNinja/infynon-cli/blob/main/docs/commands.md)
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
INFYNON is a terminal control plane for agentic engineering: multi-agent workspace/task orchestration, package intelligence, API flow testing, and repository memory in one native CLI.
|
|
10
|
+
|
|
11
|
+
This npm package is the official wrapper for the INFYNON native binary. npm installs the matching optional platform package when available; otherwise the wrapper downloads and verifies the matching GitHub Release binary on first launch. The public distribution repo includes installers, npm/go wrappers, docs, and release assets; the core Rust implementation is not included.
|
|
6
12
|
|
|
7
13
|
## Why Install INFYNON
|
|
8
14
|
|
|
9
|
-
INFYNON is built for teams that need one terminal tool for
|
|
15
|
+
INFYNON is built for teams that need one terminal tool for five connected workflows:
|
|
10
16
|
|
|
11
17
|
| Workflow | Command Area | Purpose |
|
|
12
18
|
|---|---|---|
|
|
19
|
+
| Agent control plane | `infynon workspace`, `infynon task`, `infynon coding` | Coordinate Codex, Claude Code, Gemini CLI, and child agent sessions through durable workspace and task records. |
|
|
13
20
|
| Package intelligence | `infynon pkg` | Scan dependencies, inspect risk, audit package changes, and support safer install workflows. |
|
|
14
21
|
| API flow testing | `infynon weave` | Run multi-step API flows with context passed between requests. |
|
|
15
22
|
| Repository memory | `infynon trace` | Preserve structured handoff notes, branch context, package ownership, and repo memory. |
|
|
16
|
-
| Agent task contracts |
|
|
23
|
+
| Agent task contracts | GCCD briefs | Turn vague AI work requests into Goal, Context, Constraints, and Done When. |
|
|
17
24
|
|
|
18
25
|
## Install
|
|
19
26
|
|
|
@@ -21,7 +28,7 @@ INFYNON is built for teams that need one terminal tool for four connected workfl
|
|
|
21
28
|
npm install -g infynon
|
|
22
29
|
```
|
|
23
30
|
|
|
24
|
-
|
|
31
|
+
npm installs the wrapper and, when available, the matching optional native package for the current platform. If the optional package is unavailable, first launch downloads and verifies the matching GitHub Release binary.
|
|
25
32
|
|
|
26
33
|
## Supported Platforms
|
|
27
34
|
|
|
@@ -33,17 +40,55 @@ The installer downloads the binary for the current platform and makes `infynon`
|
|
|
33
40
|
|
|
34
41
|
Unsupported platforms can still install the npm wrapper, but the wrapper will not be able to download a native binary until a matching release asset exists.
|
|
35
42
|
|
|
43
|
+
## Provenance and Platform Packages
|
|
44
|
+
|
|
45
|
+
INFYNON npm packages are configured for npm provenance from the release pipeline. Provenance links the published package to the GitHub Actions workflow that produced it.
|
|
46
|
+
|
|
47
|
+
The package can use optional native binary packages:
|
|
48
|
+
|
|
49
|
+
- `@infynon/cli-win32-x64`
|
|
50
|
+
- `@infynon/cli-linux-x64`
|
|
51
|
+
- `@infynon/cli-linux-arm64`
|
|
52
|
+
- `@infynon/cli-darwin-x64`
|
|
53
|
+
- `@infynon/cli-darwin-arm64`
|
|
54
|
+
|
|
36
55
|
## Quick Start
|
|
37
56
|
|
|
38
57
|
```bash
|
|
39
58
|
infynon --help
|
|
59
|
+
infynon workspace agent-root-show
|
|
40
60
|
infynon pkg scan
|
|
41
61
|
infynon pkg audit
|
|
42
62
|
infynon weave flow run checkout
|
|
43
63
|
infynon trace tui
|
|
44
|
-
infynon task create task_001 --mutate --workspace
|
|
64
|
+
infynon task create task_001 --mutate --workspace app --agent codex --prompt "Ship the settings API patch"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Agent Control Plane
|
|
68
|
+
|
|
69
|
+
Use INFYNON when one lead session needs to coordinate child coding agents.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
infynon workspace agent-root-set --mutate --path D:/Codeverse/infynon-agent
|
|
73
|
+
infynon workspace create app --mutate --folder-name web --path D:/Codeverse/app --default
|
|
74
|
+
|
|
75
|
+
infynon task create task_ui_review \
|
|
76
|
+
--mutate \
|
|
77
|
+
--workspace app \
|
|
78
|
+
--folder-name web \
|
|
79
|
+
--agent claude \
|
|
80
|
+
--prompt "Review the settings UI change. Do not edit backend files. Done when findings are recorded."
|
|
81
|
+
|
|
82
|
+
infynon coding tui
|
|
45
83
|
```
|
|
46
84
|
|
|
85
|
+
Good fit:
|
|
86
|
+
|
|
87
|
+
- parent and child agent work
|
|
88
|
+
- Codex, Claude Code, and Gemini CLI sessions launched from the right workspace
|
|
89
|
+
- task retries where context and completion criteria must stay intact
|
|
90
|
+
- reviewable handoffs between agents and humans
|
|
91
|
+
|
|
47
92
|
## Package Intelligence
|
|
48
93
|
|
|
49
94
|
Use `infynon pkg` to inspect dependency risk and package state.
|
|
@@ -113,7 +158,6 @@ infynon task create task_001 \
|
|
|
113
158
|
|
|
114
159
|
Good fit:
|
|
115
160
|
|
|
116
|
-
- parent and child agent work
|
|
117
161
|
- scoped implementation tasks
|
|
118
162
|
- reviewable handoffs
|
|
119
163
|
- retries where completion criteria must stay intact
|
|
@@ -155,10 +199,14 @@ https://github.com/d4rkNinja/infynon-cli/releases
|
|
|
155
199
|
## Documentation
|
|
156
200
|
|
|
157
201
|
- Public docs: https://github.com/d4rkNinja/infynon-cli/tree/main/docs
|
|
202
|
+
- Agent control plane: https://github.com/d4rkNinja/infynon-cli/blob/main/docs/agent-control-plane.md
|
|
203
|
+
- AI agent workflow: https://github.com/d4rkNinja/infynon-cli/blob/main/docs/ai-agent-workflow.md
|
|
158
204
|
- GCCD task contracts: https://github.com/d4rkNinja/infynon-cli/blob/main/docs/gccd.md
|
|
205
|
+
- npm install: https://github.com/d4rkNinja/infynon-cli/blob/main/docs/npm-install.md
|
|
206
|
+
- Windows troubleshooting: https://github.com/d4rkNinja/infynon-cli/blob/main/docs/windows-troubleshooting.md
|
|
159
207
|
- Releases: https://github.com/d4rkNinja/infynon-cli/releases
|
|
160
208
|
- Issues: https://github.com/d4rkNinja/infynon-cli/issues
|
|
161
209
|
|
|
162
210
|
## Source Availability
|
|
163
211
|
|
|
164
|
-
This npm package distributes the INFYNON binary and installer wrapper only. The Rust
|
|
212
|
+
This npm package distributes the INFYNON binary and installer wrapper only. The core Rust implementation is not bundled in this package.
|
package/package.json
CHANGED
|
@@ -1,36 +1,55 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
2
|
+
"name": "infynon",
|
|
3
|
+
"version": "0.2.7",
|
|
4
|
+
"description": "Security-first CLI for AI-assisted development: safe package installs, dependency scanning, API flow testing, and agent task orchestration.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"infynon": "run.js",
|
|
7
|
+
"infynon-pkg": "run-pkg.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE",
|
|
12
|
+
"run.js",
|
|
13
|
+
"run-pkg.js",
|
|
14
|
+
"postinstall.js",
|
|
15
|
+
"preuninstall.js"
|
|
16
|
+
],
|
|
17
|
+
"optionalDependencies": {
|
|
18
|
+
"@infynon/cli-win32-x64": "0.2.7",
|
|
19
|
+
"@infynon/cli-linux-x64": "0.2.7",
|
|
20
|
+
"@infynon/cli-linux-arm64": "0.2.7",
|
|
21
|
+
"@infynon/cli-darwin-x64": "0.2.7",
|
|
22
|
+
"@infynon/cli-darwin-arm64": "0.2.7"
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=18"
|
|
26
|
+
},
|
|
27
|
+
"packageManager": "npm@11.8.0",
|
|
28
|
+
"author": "d4rkNinja",
|
|
29
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/d4rkNinja/infynon-cli.git",
|
|
33
|
+
"directory": "npm"
|
|
34
|
+
},
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/d4rkNinja/infynon-cli/issues"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://cli.infynon.com",
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public",
|
|
41
|
+
"provenance": true
|
|
42
|
+
},
|
|
43
|
+
"keywords": [
|
|
44
|
+
"cli",
|
|
45
|
+
"security",
|
|
46
|
+
"supply-chain",
|
|
47
|
+
"dependency-scanning",
|
|
48
|
+
"ai-agents",
|
|
49
|
+
"claude-code",
|
|
50
|
+
"codex",
|
|
51
|
+
"gemini-cli",
|
|
52
|
+
"api-testing",
|
|
53
|
+
"devtools"
|
|
54
|
+
]
|
|
36
55
|
}
|
package/postinstall.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
|
+
const crypto = require("crypto");
|
|
4
5
|
const https = require("https");
|
|
5
6
|
const fs = require("fs");
|
|
6
7
|
const path = require("path");
|
|
@@ -10,27 +11,75 @@ const REPO = "d4rkNinja/infynon-cli";
|
|
|
10
11
|
const VERSION = require("./package.json").version;
|
|
11
12
|
const BIN_DIR = path.join(__dirname, "bin");
|
|
12
13
|
const BIN_PATH = path.join(BIN_DIR, process.platform === "win32" ? "infynon.exe" : "infynon");
|
|
14
|
+
const TEMP_BIN_PATH = BIN_PATH + ".download-" + process.pid;
|
|
15
|
+
const TEMP_CHECKSUMS_PATH = BIN_PATH + ".checksums-" + process.pid + ".txt";
|
|
16
|
+
const TEMP_MANIFEST_PATH = BIN_PATH + ".manifest-" + process.pid + ".json";
|
|
13
17
|
|
|
14
18
|
function getTarget() {
|
|
15
|
-
if (process.platform === "win32" && process.arch === "x64")
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
if (process.platform === "win32" && process.arch === "x64") {
|
|
20
|
+
return {
|
|
21
|
+
target: "x86_64-pc-windows-msvc",
|
|
22
|
+
ext: ".exe",
|
|
23
|
+
packageName: "@infynon/cli-win32-x64",
|
|
24
|
+
binaryName: "infynon.exe",
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (process.platform === "linux" && process.arch === "x64") {
|
|
28
|
+
return {
|
|
29
|
+
target: "x86_64-unknown-linux-musl",
|
|
30
|
+
ext: "",
|
|
31
|
+
packageName: "@infynon/cli-linux-x64",
|
|
32
|
+
binaryName: "infynon",
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
if (process.platform === "linux" && process.arch === "arm64") {
|
|
36
|
+
return {
|
|
37
|
+
target: "aarch64-unknown-linux-musl",
|
|
38
|
+
ext: "",
|
|
39
|
+
packageName: "@infynon/cli-linux-arm64",
|
|
40
|
+
binaryName: "infynon",
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (process.platform === "darwin" && process.arch === "x64") {
|
|
44
|
+
return {
|
|
45
|
+
target: "x86_64-apple-darwin",
|
|
46
|
+
ext: "",
|
|
47
|
+
packageName: "@infynon/cli-darwin-x64",
|
|
48
|
+
binaryName: "infynon",
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (process.platform === "darwin" && process.arch === "arm64") {
|
|
52
|
+
return {
|
|
53
|
+
target: "aarch64-apple-darwin",
|
|
54
|
+
ext: "",
|
|
55
|
+
packageName: "@infynon/cli-darwin-arm64",
|
|
56
|
+
binaryName: "infynon",
|
|
57
|
+
};
|
|
58
|
+
}
|
|
20
59
|
return null;
|
|
21
60
|
}
|
|
22
61
|
|
|
23
62
|
function downloadFile(url, dest, redirects) {
|
|
24
63
|
redirects = redirects === undefined ? 0 : redirects;
|
|
25
64
|
if (redirects > 5) {
|
|
26
|
-
|
|
65
|
+
return Promise.reject(new Error("Too many redirects while downloading binary"));
|
|
27
66
|
}
|
|
28
67
|
|
|
29
68
|
return new Promise(function (resolve, reject) {
|
|
30
69
|
https
|
|
31
70
|
.get(url, { headers: { "User-Agent": "infynon-npm-installer" } }, function (res) {
|
|
32
|
-
if (res.statusCode
|
|
33
|
-
|
|
71
|
+
if (res.statusCode >= 300 && res.statusCode < 400) {
|
|
72
|
+
res.resume();
|
|
73
|
+
if (!res.headers.location) {
|
|
74
|
+
return reject(new Error("Redirect response did not include a Location header"));
|
|
75
|
+
}
|
|
76
|
+
let nextUrl;
|
|
77
|
+
try {
|
|
78
|
+
nextUrl = new URL(res.headers.location, url).toString();
|
|
79
|
+
} catch (err) {
|
|
80
|
+
return reject(err);
|
|
81
|
+
}
|
|
82
|
+
return downloadFile(nextUrl, dest, redirects + 1)
|
|
34
83
|
.then(resolve)
|
|
35
84
|
.catch(reject);
|
|
36
85
|
}
|
|
@@ -48,6 +97,12 @@ function downloadFile(url, dest, redirects) {
|
|
|
48
97
|
file.on("finish", function () {
|
|
49
98
|
file.close(resolve);
|
|
50
99
|
});
|
|
100
|
+
res.on("error", function (err) {
|
|
101
|
+
file.close(function () {
|
|
102
|
+
fs.unlink(dest, function () {});
|
|
103
|
+
reject(err);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
51
106
|
res.pipe(file);
|
|
52
107
|
})
|
|
53
108
|
.on("error", function (err) {
|
|
@@ -57,21 +112,280 @@ function downloadFile(url, dest, redirects) {
|
|
|
57
112
|
});
|
|
58
113
|
}
|
|
59
114
|
|
|
60
|
-
function
|
|
61
|
-
|
|
115
|
+
function removeQuietly(filePath) {
|
|
116
|
+
try {
|
|
117
|
+
fs.rmSync(filePath, { force: true });
|
|
118
|
+
} catch (_) {}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function isFile(filePath) {
|
|
122
|
+
try {
|
|
123
|
+
return fs.statSync(filePath).isFile();
|
|
124
|
+
} catch (_) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function checksumForAsset(checksumsText, assetName) {
|
|
130
|
+
const lines = checksumsText.split(/\r?\n/);
|
|
131
|
+
for (const line of lines) {
|
|
132
|
+
const match = line.match(/^([a-fA-F0-9]{64})\s+[* ]?(.+)$/);
|
|
133
|
+
if (!match) continue;
|
|
134
|
+
if (path.basename(match[2].trim()) === assetName) {
|
|
135
|
+
return match[1].toLowerCase();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
throw new Error("checksums.txt does not include " + assetName);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function sha256File(filePath) {
|
|
142
|
+
return crypto.createHash("sha256").update(fs.readFileSync(filePath)).digest("hex");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function verifyChecksum(checksumsPath, filePath, assetName) {
|
|
146
|
+
const expected = checksumForAsset(fs.readFileSync(checksumsPath, "utf8"), assetName);
|
|
147
|
+
const actual = sha256File(filePath);
|
|
148
|
+
if (actual !== expected) {
|
|
149
|
+
throw new Error("SHA-256 mismatch for " + assetName);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function unavailable(message) {
|
|
154
|
+
const err = new Error(message);
|
|
155
|
+
err.fallbackAllowed = true;
|
|
156
|
+
return err;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function integrityFailure(message) {
|
|
160
|
+
const err = new Error(message);
|
|
161
|
+
err.integrityFailure = true;
|
|
162
|
+
return err;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function basenameMatches(value, assetName) {
|
|
166
|
+
return typeof value === "string" && path.basename(value) === assetName;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function entryName(entry) {
|
|
170
|
+
if (!entry || typeof entry !== "object") {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
return entry.name || entry.filename || entry.file || entry.path || entry.asset || entry.asset_name || null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function objectEntryForAsset(objectValue, assetName) {
|
|
177
|
+
if (!objectValue || typeof objectValue !== "object" || Array.isArray(objectValue)) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (Object.prototype.hasOwnProperty.call(objectValue, assetName)) {
|
|
182
|
+
const value = objectValue[assetName];
|
|
183
|
+
if (value && typeof value === "object") {
|
|
184
|
+
return Object.assign({ name: assetName }, value);
|
|
185
|
+
}
|
|
186
|
+
return { name: assetName, sha256: value };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
for (const key of Object.keys(objectValue)) {
|
|
190
|
+
const value = objectValue[key];
|
|
191
|
+
if (path.basename(key) === assetName) {
|
|
192
|
+
if (value && typeof value === "object") {
|
|
193
|
+
return Object.assign({ name: key }, value);
|
|
194
|
+
}
|
|
195
|
+
return { name: key, sha256: value };
|
|
196
|
+
}
|
|
197
|
+
if (value && typeof value === "object" && basenameMatches(entryName(value), assetName)) {
|
|
198
|
+
return value;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function findManifestEntry(manifest, assetName) {
|
|
206
|
+
if (basenameMatches(entryName(manifest), assetName)) {
|
|
207
|
+
return manifest;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const collections = [
|
|
211
|
+
manifest && manifest.assets,
|
|
212
|
+
manifest && manifest.files,
|
|
213
|
+
manifest && manifest.binaries,
|
|
214
|
+
manifest && manifest.artifacts,
|
|
215
|
+
manifest && manifest.release_assets,
|
|
216
|
+
];
|
|
217
|
+
|
|
218
|
+
for (const collection of collections) {
|
|
219
|
+
if (Array.isArray(collection)) {
|
|
220
|
+
for (const entry of collection) {
|
|
221
|
+
if (basenameMatches(entryName(entry), assetName)) {
|
|
222
|
+
return entry;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
} else {
|
|
226
|
+
const entry = objectEntryForAsset(collection, assetName);
|
|
227
|
+
if (entry) {
|
|
228
|
+
return entry;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return objectEntryForAsset(manifest, assetName);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function fieldValue(entry, names) {
|
|
237
|
+
for (const name of names) {
|
|
238
|
+
if (Object.prototype.hasOwnProperty.call(entry, name)) {
|
|
239
|
+
return entry[name];
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function normalizeSha256(value) {
|
|
246
|
+
if (typeof value !== "string") {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
const normalized = value.trim().toLowerCase().replace(/^sha256[:=\s]+/, "");
|
|
250
|
+
if (/^[a-f0-9]{64}$/.test(normalized)) {
|
|
251
|
+
return normalized;
|
|
252
|
+
}
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function normalizeSize(value) {
|
|
257
|
+
if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) {
|
|
258
|
+
return value;
|
|
259
|
+
}
|
|
260
|
+
if (typeof value === "string" && /^\d+$/.test(value.trim())) {
|
|
261
|
+
const parsed = Number(value.trim());
|
|
262
|
+
if (Number.isSafeInteger(parsed)) {
|
|
263
|
+
return parsed;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function manifestVerificationForAsset(manifestPath, assetName) {
|
|
270
|
+
let manifest;
|
|
271
|
+
try {
|
|
272
|
+
manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
273
|
+
} catch (err) {
|
|
274
|
+
throw unavailable("release-manifest.json is not valid JSON: " + err.message);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const entry = findManifestEntry(manifest, assetName);
|
|
278
|
+
if (!entry) {
|
|
279
|
+
throw unavailable("release-manifest.json does not include " + assetName);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const sha256 = normalizeSha256(
|
|
283
|
+
fieldValue(entry, ["sha256", "sha_256", "sha256sum", "checksum", "digest"])
|
|
284
|
+
);
|
|
285
|
+
if (!sha256) {
|
|
286
|
+
throw unavailable("release-manifest.json does not include a SHA-256 for " + assetName);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const size = normalizeSize(fieldValue(entry, ["size", "size_bytes", "bytes", "length"]));
|
|
290
|
+
if (size === null) {
|
|
291
|
+
throw unavailable("release-manifest.json does not include a size for " + assetName);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return { sha256: sha256, size: size };
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
async function fetchManifestVerification(manifestUrl, assetName) {
|
|
298
|
+
try {
|
|
299
|
+
removeQuietly(TEMP_MANIFEST_PATH);
|
|
300
|
+
await downloadFile(manifestUrl, TEMP_MANIFEST_PATH);
|
|
301
|
+
return manifestVerificationForAsset(TEMP_MANIFEST_PATH, assetName);
|
|
302
|
+
} catch (err) {
|
|
303
|
+
if (err && err.integrityFailure) {
|
|
304
|
+
throw err;
|
|
305
|
+
}
|
|
306
|
+
console.warn("[infynon] release-manifest.json verification unavailable: " + err.message);
|
|
307
|
+
console.warn("[infynon] Falling back to checksums.txt.");
|
|
308
|
+
return null;
|
|
309
|
+
} finally {
|
|
310
|
+
removeQuietly(TEMP_MANIFEST_PATH);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function verifyManifestAsset(expected, filePath, assetName) {
|
|
315
|
+
const actualSize = fs.statSync(filePath).size;
|
|
316
|
+
if (actualSize !== expected.size) {
|
|
317
|
+
throw integrityFailure("Size mismatch for " + assetName);
|
|
318
|
+
}
|
|
319
|
+
const actualSha256 = sha256File(filePath);
|
|
320
|
+
if (actualSha256 !== expected.sha256) {
|
|
321
|
+
throw integrityFailure("SHA-256 mismatch for " + assetName);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function verifyBinary(binaryPath, label) {
|
|
326
|
+
const result = spawnSync(binaryPath, ["--version"], {
|
|
62
327
|
encoding: "utf8",
|
|
63
328
|
windowsHide: true,
|
|
64
329
|
});
|
|
65
330
|
if (result.error) {
|
|
66
|
-
throw new Error("
|
|
331
|
+
throw new Error(label + " is not executable: " + result.error.message);
|
|
67
332
|
}
|
|
68
333
|
if (result.status !== 0) {
|
|
69
334
|
const detail = (result.stderr || result.stdout || "").trim();
|
|
70
335
|
throw new Error(
|
|
71
|
-
"
|
|
72
|
-
(detail ? ": " + detail : " with exit code " + result.status)
|
|
336
|
+
label + " failed verification" + (detail ? ": " + detail : " with exit code " + result.status)
|
|
73
337
|
);
|
|
74
338
|
}
|
|
339
|
+
const versionFields = String((result.stdout || "") + " " + (result.stderr || ""))
|
|
340
|
+
.trim()
|
|
341
|
+
.split(/\s+/)
|
|
342
|
+
.map(function (field) {
|
|
343
|
+
return field.replace(/^v/, "");
|
|
344
|
+
});
|
|
345
|
+
if (versionFields.indexOf(VERSION) === -1) {
|
|
346
|
+
throw new Error(label + " did not report version " + VERSION);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function resolvePlatformPackageBinary(info) {
|
|
351
|
+
let packageJsonPath;
|
|
352
|
+
try {
|
|
353
|
+
packageJsonPath = require.resolve(info.packageName + "/package.json", { paths: [__dirname] });
|
|
354
|
+
} catch (err) {
|
|
355
|
+
if (err && err.code !== "MODULE_NOT_FOUND") {
|
|
356
|
+
console.warn("[infynon] Could not inspect " + info.packageName + ": " + err.message);
|
|
357
|
+
}
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
let packageVersion = null;
|
|
362
|
+
try {
|
|
363
|
+
packageVersion = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")).version;
|
|
364
|
+
} catch (err) {
|
|
365
|
+
console.warn("[infynon] Could not read " + info.packageName + " metadata: " + err.message);
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (packageVersion !== VERSION) {
|
|
370
|
+
console.warn(
|
|
371
|
+
"[infynon] Ignoring " +
|
|
372
|
+
info.packageName +
|
|
373
|
+
" " +
|
|
374
|
+
packageVersion +
|
|
375
|
+
"; expected wrapper version " +
|
|
376
|
+
VERSION +
|
|
377
|
+
"."
|
|
378
|
+
);
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const binaryPath = path.join(path.dirname(packageJsonPath), "bin", info.binaryName);
|
|
383
|
+
if (!isFile(binaryPath)) {
|
|
384
|
+
console.warn("[infynon] Ignoring " + info.packageName + "; missing binary at " + binaryPath + ".");
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return { path: binaryPath, packageName: info.packageName };
|
|
75
389
|
}
|
|
76
390
|
|
|
77
391
|
async function main() {
|
|
@@ -79,15 +393,36 @@ async function main() {
|
|
|
79
393
|
|
|
80
394
|
if (!info) {
|
|
81
395
|
console.warn(
|
|
82
|
-
"[infynon] Unsupported platform: " +
|
|
83
|
-
|
|
396
|
+
"[infynon] Unsupported platform: " +
|
|
397
|
+
process.platform +
|
|
398
|
+
" " +
|
|
399
|
+
process.arch +
|
|
400
|
+
".\n" +
|
|
401
|
+
" Download a release manually: https://github.com/" +
|
|
402
|
+
REPO +
|
|
403
|
+
"/releases"
|
|
84
404
|
);
|
|
85
405
|
process.exit(0);
|
|
86
406
|
}
|
|
87
407
|
|
|
408
|
+
const platformBinary = resolvePlatformPackageBinary(info);
|
|
409
|
+
if (platformBinary) {
|
|
410
|
+
try {
|
|
411
|
+
verifyBinary(platformBinary.path, "Installed platform package " + platformBinary.packageName);
|
|
412
|
+
} catch (err) {
|
|
413
|
+
console.error("[infynon] Platform package verification failed: " + err.message);
|
|
414
|
+
console.error("[infynon] Reinstall after the package is corrected: npm install -g infynon");
|
|
415
|
+
process.exit(1);
|
|
416
|
+
}
|
|
417
|
+
console.log("[infynon] Using installed native package " + platformBinary.packageName + ".");
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
|
|
88
421
|
const tag = "v" + VERSION;
|
|
89
422
|
const assetName = "infynon-" + info.target + info.ext;
|
|
90
423
|
const url = "https://github.com/" + REPO + "/releases/download/" + tag + "/" + assetName;
|
|
424
|
+
const manifestUrl = "https://github.com/" + REPO + "/releases/download/" + tag + "/release-manifest.json";
|
|
425
|
+
const checksumsUrl = "https://github.com/" + REPO + "/releases/download/" + tag + "/checksums.txt";
|
|
91
426
|
|
|
92
427
|
if (!fs.existsSync(BIN_DIR)) {
|
|
93
428
|
fs.mkdirSync(BIN_DIR, { recursive: true });
|
|
@@ -96,11 +431,31 @@ async function main() {
|
|
|
96
431
|
console.log("[infynon] Downloading " + assetName + " from " + tag + " release...");
|
|
97
432
|
|
|
98
433
|
try {
|
|
99
|
-
|
|
434
|
+
removeQuietly(TEMP_BIN_PATH);
|
|
435
|
+
removeQuietly(TEMP_CHECKSUMS_PATH);
|
|
436
|
+
removeQuietly(TEMP_MANIFEST_PATH);
|
|
437
|
+
|
|
438
|
+
const manifestVerification = await fetchManifestVerification(manifestUrl, assetName);
|
|
439
|
+
await downloadFile(url, TEMP_BIN_PATH);
|
|
440
|
+
if (manifestVerification) {
|
|
441
|
+
verifyManifestAsset(manifestVerification, TEMP_BIN_PATH, assetName);
|
|
442
|
+
} else {
|
|
443
|
+
await downloadFile(checksumsUrl, TEMP_CHECKSUMS_PATH);
|
|
444
|
+
verifyChecksum(TEMP_CHECKSUMS_PATH, TEMP_BIN_PATH, assetName);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
removeQuietly(BIN_PATH);
|
|
448
|
+
fs.renameSync(TEMP_BIN_PATH, BIN_PATH);
|
|
100
449
|
} catch (err) {
|
|
450
|
+
removeQuietly(TEMP_BIN_PATH);
|
|
451
|
+
removeQuietly(TEMP_CHECKSUMS_PATH);
|
|
452
|
+
removeQuietly(TEMP_MANIFEST_PATH);
|
|
101
453
|
console.error("[infynon] Download failed: " + err.message);
|
|
102
454
|
console.error("[infynon] Manual install: https://github.com/" + REPO + "/releases/tag/" + tag);
|
|
103
455
|
process.exit(1);
|
|
456
|
+
} finally {
|
|
457
|
+
removeQuietly(TEMP_CHECKSUMS_PATH);
|
|
458
|
+
removeQuietly(TEMP_MANIFEST_PATH);
|
|
104
459
|
}
|
|
105
460
|
|
|
106
461
|
if (process.platform !== "win32") {
|
|
@@ -108,9 +463,9 @@ async function main() {
|
|
|
108
463
|
}
|
|
109
464
|
|
|
110
465
|
try {
|
|
111
|
-
verifyBinary();
|
|
466
|
+
verifyBinary(BIN_PATH, "Downloaded binary");
|
|
112
467
|
} catch (err) {
|
|
113
|
-
|
|
468
|
+
removeQuietly(BIN_PATH);
|
|
114
469
|
console.error("[infynon] Binary verification failed: " + err.message);
|
|
115
470
|
console.error("[infynon] Reinstall after the release asset is corrected: npm install -g infynon");
|
|
116
471
|
process.exit(1);
|
package/preuninstall.js
CHANGED
|
@@ -3,54 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const path = require("path");
|
|
6
|
-
const os = require("os");
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
const INFYNON_DIR = path.join(os.homedir(), ".infynon");
|
|
7
|
+
const BIN_DIR = path.join(__dirname, "bin");
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
{ p: path.join(INFYNON_DIR, "infynon.toml"), label: "firewall config" },
|
|
14
|
-
{ p: path.join(INFYNON_DIR, "eagle-eye.toml"), label: "eagle eye config" },
|
|
15
|
-
{ p: path.join(INFYNON_DIR, "access.jsonl"), label: "access log" },
|
|
16
|
-
{ p: path.join(INFYNON_DIR, "blocked.jsonl"), label: "blocked log" },
|
|
17
|
-
{ p: path.join(INFYNON_DIR, "sbom.json"), label: "SBOM" },
|
|
18
|
-
];
|
|
19
|
-
|
|
20
|
-
console.log("\n[infynon] Cleaning up...\n");
|
|
21
|
-
|
|
22
|
-
let removed = 0;
|
|
23
|
-
|
|
24
|
-
for (const { p, label } of MANAGED_PATHS) {
|
|
25
|
-
if (fs.existsSync(p)) {
|
|
26
|
-
try {
|
|
27
|
-
fs.rmSync(p, { force: true });
|
|
28
|
-
console.log(" removed " + label + " (" + p + ")");
|
|
29
|
-
removed++;
|
|
30
|
-
} catch (err) {
|
|
31
|
-
console.warn(" skipped " + label + " — " + err.message);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Remove ~/.infynon/ itself if it is now empty
|
|
37
|
-
if (fs.existsSync(INFYNON_DIR)) {
|
|
38
|
-
try {
|
|
39
|
-
const remaining = fs.readdirSync(INFYNON_DIR);
|
|
40
|
-
if (remaining.length === 0) {
|
|
41
|
-
fs.rmdirSync(INFYNON_DIR);
|
|
42
|
-
console.log(" removed ~/.infynon/ directory");
|
|
43
|
-
} else {
|
|
44
|
-
console.log(
|
|
45
|
-
" kept ~/.infynon/ — " + remaining.length +
|
|
46
|
-
" user file(s) remain: " + remaining.join(", ")
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
} catch (_) {}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (removed === 0) {
|
|
53
|
-
console.log(" nothing to clean up.\n");
|
|
54
|
-
} else {
|
|
55
|
-
console.log("\n[infynon] Clean uninstall complete.\n");
|
|
9
|
+
if (fs.existsSync(BIN_DIR)) {
|
|
10
|
+
fs.rmSync(BIN_DIR, { recursive: true, force: true });
|
|
56
11
|
}
|
package/run.js
CHANGED
|
@@ -1,45 +1,265 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
|
-
const path = require("path");
|
|
5
|
-
const { spawnSync } = require("child_process");
|
|
6
4
|
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const { spawn } = require("child_process");
|
|
7
7
|
|
|
8
|
-
const
|
|
9
|
-
|
|
8
|
+
const PACKAGE_DIR = __dirname;
|
|
9
|
+
const VERSION = require("./package.json").version;
|
|
10
|
+
const RELEASES_URL = "https://github.com/d4rkNinja/infynon-cli/releases";
|
|
11
|
+
const LOCAL_BIN_PATH = path.join(
|
|
12
|
+
PACKAGE_DIR,
|
|
10
13
|
"bin",
|
|
11
14
|
process.platform === "win32" ? "infynon.exe" : "infynon"
|
|
12
15
|
);
|
|
16
|
+
const POSTINSTALL_PATH = path.join(PACKAGE_DIR, "postinstall.js");
|
|
17
|
+
|
|
18
|
+
function getPlatformPackage() {
|
|
19
|
+
if (process.platform === "win32" && process.arch === "x64") {
|
|
20
|
+
return { packageName: "@infynon/cli-win32-x64", binaryName: "infynon.exe" };
|
|
21
|
+
}
|
|
22
|
+
if (process.platform === "linux" && process.arch === "x64") {
|
|
23
|
+
return { packageName: "@infynon/cli-linux-x64", binaryName: "infynon" };
|
|
24
|
+
}
|
|
25
|
+
if (process.platform === "linux" && process.arch === "arm64") {
|
|
26
|
+
return { packageName: "@infynon/cli-linux-arm64", binaryName: "infynon" };
|
|
27
|
+
}
|
|
28
|
+
if (process.platform === "darwin" && process.arch === "x64") {
|
|
29
|
+
return { packageName: "@infynon/cli-darwin-x64", binaryName: "infynon" };
|
|
30
|
+
}
|
|
31
|
+
if (process.platform === "darwin" && process.arch === "arm64") {
|
|
32
|
+
return { packageName: "@infynon/cli-darwin-arm64", binaryName: "infynon" };
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isFile(filePath) {
|
|
38
|
+
try {
|
|
39
|
+
return fs.statSync(filePath).isFile();
|
|
40
|
+
} catch (_) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function resolvePlatformBinary(notes) {
|
|
46
|
+
const info = getPlatformPackage();
|
|
47
|
+
if (!info) {
|
|
48
|
+
notes.push("No optional native package is published for " + process.platform + " " + process.arch + ".");
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let packageJsonPath;
|
|
53
|
+
try {
|
|
54
|
+
packageJsonPath = require.resolve(info.packageName + "/package.json", { paths: [PACKAGE_DIR] });
|
|
55
|
+
} catch (err) {
|
|
56
|
+
if (err && err.code !== "MODULE_NOT_FOUND") {
|
|
57
|
+
notes.push("Could not inspect " + info.packageName + ": " + err.message);
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const packageDir = path.dirname(packageJsonPath);
|
|
63
|
+
let packageVersion = null;
|
|
64
|
+
try {
|
|
65
|
+
packageVersion = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")).version;
|
|
66
|
+
} catch (err) {
|
|
67
|
+
notes.push("Could not read " + info.packageName + " metadata: " + err.message);
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (packageVersion !== VERSION) {
|
|
72
|
+
notes.push(
|
|
73
|
+
info.packageName + " is version " + packageVersion + ", but the wrapper is version " + VERSION + "."
|
|
74
|
+
);
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const binaryPath = path.join(packageDir, "bin", info.binaryName);
|
|
79
|
+
if (!isFile(binaryPath)) {
|
|
80
|
+
notes.push("Found " + info.packageName + ", but its binary is missing at " + binaryPath + ".");
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return { path: binaryPath, source: info.packageName };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function spawnInherited(command, args, options) {
|
|
88
|
+
return new Promise(function (resolve, reject) {
|
|
89
|
+
let child;
|
|
90
|
+
try {
|
|
91
|
+
child = spawn(
|
|
92
|
+
command,
|
|
93
|
+
args,
|
|
94
|
+
Object.assign(
|
|
95
|
+
{
|
|
96
|
+
stdio: "inherit",
|
|
97
|
+
windowsHide: false,
|
|
98
|
+
},
|
|
99
|
+
options || {}
|
|
100
|
+
)
|
|
101
|
+
);
|
|
102
|
+
} catch (err) {
|
|
103
|
+
reject(err);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
child.on("error", reject);
|
|
108
|
+
child.on("exit", function (code, signal) {
|
|
109
|
+
resolve({ code: code, signal: signal });
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
}
|
|
13
113
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
114
|
+
async function runPostinstallFallback() {
|
|
115
|
+
if (!isFile(POSTINSTALL_PATH)) {
|
|
116
|
+
throw new Error("postinstall.js is missing at " + POSTINSTALL_PATH);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.error("[infynon] Native binary is missing; running npm postinstall fallback once.");
|
|
120
|
+
const result = await spawnInherited(process.execPath, [POSTINSTALL_PATH], {
|
|
121
|
+
env: Object.assign({}, process.env, {
|
|
122
|
+
INFYNON_NPM_POSTINSTALL_FALLBACK: "1",
|
|
123
|
+
}),
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
if (result.signal) {
|
|
127
|
+
throw new Error("postinstall.js was terminated by signal " + result.signal);
|
|
128
|
+
}
|
|
129
|
+
if (result.code !== 0) {
|
|
130
|
+
throw new Error("postinstall.js failed with exit code " + result.code);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function resolveNativeBinary() {
|
|
135
|
+
const notes = [];
|
|
136
|
+
const platformBinary = resolvePlatformBinary(notes);
|
|
137
|
+
if (platformBinary) {
|
|
138
|
+
return platformBinary;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (isFile(LOCAL_BIN_PATH)) {
|
|
142
|
+
return { path: LOCAL_BIN_PATH, source: "npm/bin" };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
await runPostinstallFallback();
|
|
146
|
+
if (isFile(LOCAL_BIN_PATH)) {
|
|
147
|
+
return { path: LOCAL_BIN_PATH, source: "npm/bin:postinstall" };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const message = [
|
|
151
|
+
"Binary not found for " + process.platform + " " + process.arch + ".",
|
|
152
|
+
"Expected local fallback at: " + LOCAL_BIN_PATH,
|
|
153
|
+
];
|
|
154
|
+
if (notes.length > 0) {
|
|
155
|
+
message.push("Resolution notes:");
|
|
156
|
+
for (const note of notes) {
|
|
157
|
+
message.push(" - " + note);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
message.push("Try reinstalling: npm install -g infynon");
|
|
161
|
+
message.push("Or download a release manually: " + RELEASES_URL);
|
|
162
|
+
const err = new Error(message.join("\n"));
|
|
163
|
+
err.code = "BINARY_NOT_FOUND";
|
|
164
|
+
throw err;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function assertWindowsCommandLineFits(binaryPath, args) {
|
|
168
|
+
if (process.platform !== "win32") {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const estimatedLength = binaryPath.length + args.reduce(function (total, arg) {
|
|
172
|
+
return total + String(arg).length + 3;
|
|
173
|
+
}, 0);
|
|
174
|
+
if (estimatedLength <= 30000) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const err = new Error(
|
|
178
|
+
"command line is too long for Windows process creation; reduce arguments or use file-based package-manager input"
|
|
19
179
|
);
|
|
20
|
-
|
|
180
|
+
err.code = "COMMAND_TOO_LONG";
|
|
181
|
+
throw err;
|
|
21
182
|
}
|
|
22
183
|
|
|
23
|
-
function runBinary(args) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
184
|
+
async function runBinary(resolution, args) {
|
|
185
|
+
assertWindowsCommandLineFits(resolution.path, args);
|
|
186
|
+
return spawnInherited(resolution.path, args, {
|
|
187
|
+
env: Object.assign({}, process.env, {
|
|
188
|
+
INFYNON_NPM_WRAPPER: __filename,
|
|
189
|
+
INFYNON_NPM_PACKAGE_DIR: PACKAGE_DIR,
|
|
190
|
+
INFYNON_NPM_BINARY: resolution.path,
|
|
191
|
+
INFYNON_NPM_BINARY_SOURCE: resolution.source,
|
|
192
|
+
}),
|
|
27
193
|
});
|
|
28
194
|
}
|
|
29
195
|
|
|
30
|
-
|
|
196
|
+
function exitFromChild(result) {
|
|
197
|
+
if (result.signal) {
|
|
198
|
+
try {
|
|
199
|
+
process.kill(process.pid, result.signal);
|
|
200
|
+
} catch (_) {
|
|
201
|
+
const signalExitCodes = { SIGHUP: 129, SIGINT: 130, SIGTERM: 143 };
|
|
202
|
+
process.exit(signalExitCodes[result.signal] || 1);
|
|
203
|
+
}
|
|
204
|
+
setTimeout(function () {
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}, 1000);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
process.exit(result.code === null ? 1 : result.code);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function printLaunchError(err, resolution) {
|
|
214
|
+
const detected = [
|
|
215
|
+
"platform: " + process.platform + " " + process.arch,
|
|
216
|
+
"wrapper: " + __filename,
|
|
217
|
+
"package dir: " + PACKAGE_DIR,
|
|
218
|
+
"binary: " + (resolution ? resolution.path : "unresolved"),
|
|
219
|
+
"binary source: " + (resolution ? resolution.source : "unresolved"),
|
|
220
|
+
"node: " + process.version,
|
|
221
|
+
];
|
|
222
|
+
|
|
223
|
+
if (err && err.code === "BINARY_NOT_FOUND") {
|
|
224
|
+
console.error("[infynon] " + err.message);
|
|
225
|
+
console.error("[infynon] Detected:\n - " + detected.join("\n - "));
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
31
228
|
|
|
32
|
-
if (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
console.error("[infynon]
|
|
36
|
-
console.error("[infynon] Reinstall to download and verify a fresh release asset: npm install -g infynon");
|
|
229
|
+
if (resolution) {
|
|
230
|
+
console.error("[infynon] Failed to launch native binary: " + resolution.path);
|
|
231
|
+
} else {
|
|
232
|
+
console.error("[infynon] Failed to resolve native binary.");
|
|
37
233
|
}
|
|
38
|
-
|
|
234
|
+
console.error("[infynon] " + (err && err.message ? err.message : String(err)));
|
|
235
|
+
|
|
236
|
+
if (err && err.code === "COMMAND_TOO_LONG") {
|
|
237
|
+
console.error("[infynon] On Windows, pass large package-manager input through files instead of argv.");
|
|
238
|
+
} else if (err && err.code === "ENOENT") {
|
|
239
|
+
console.error("[infynon] The resolved binary path no longer exists. Try reinstalling: npm install -g infynon");
|
|
240
|
+
} else if (err && (err.code === "EACCES" || err.code === "EPERM")) {
|
|
241
|
+
console.error("[infynon] The resolved binary is not executable. Try reinstalling: npm install -g infynon");
|
|
242
|
+
} else if (process.platform === "win32") {
|
|
243
|
+
console.error("[infynon] If Windows blocked or quarantined the executable, reinstall to restore a verified copy.");
|
|
244
|
+
console.error("[infynon] Reinstall command: npm install -g infynon");
|
|
245
|
+
} else {
|
|
246
|
+
console.error("[infynon] Try reinstalling: npm install -g infynon");
|
|
247
|
+
}
|
|
248
|
+
console.error("[infynon] Detected:\n - " + detected.join("\n - "));
|
|
249
|
+
console.error("[infynon] Diagnostics: infynon doctor npm");
|
|
250
|
+
console.error("[infynon] Manual release downloads: " + RELEASES_URL);
|
|
39
251
|
}
|
|
40
252
|
|
|
41
|
-
|
|
42
|
-
|
|
253
|
+
async function main() {
|
|
254
|
+
let resolution = null;
|
|
255
|
+
try {
|
|
256
|
+
resolution = await resolveNativeBinary();
|
|
257
|
+
const result = await runBinary(resolution, process.argv.slice(2));
|
|
258
|
+
exitFromChild(result);
|
|
259
|
+
} catch (err) {
|
|
260
|
+
printLaunchError(err, resolution);
|
|
261
|
+
process.exit(1);
|
|
262
|
+
}
|
|
43
263
|
}
|
|
44
264
|
|
|
45
|
-
|
|
265
|
+
main();
|