@inflexa-ai/inflexa 0.1.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 +13 -0
- package/bin/inflexa.js +48 -0
- package/package.json +34 -0
- package/postinstall.js +82 -0
package/README.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Inflexa
|
|
2
|
+
|
|
3
|
+
Local-first AI agent for reproducible biological data analysis.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install -g @inflexa-ai/inflexa
|
|
7
|
+
inflexa
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
This package delivers a self-contained native binary through a
|
|
11
|
+
platform-specific optional dependency; Node.js only hosts the thin
|
|
12
|
+
launcher. Docs, source, and other install channels (Homebrew, install
|
|
13
|
+
scripts): https://github.com/inflexa-ai/inflexa
|
package/bin/inflexa.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
// The @inflexa-ai/inflexa `bin`: resolves and executes the platform-native
|
|
4
|
+
// binary delivered by one of the @inflexa-ai/inflexa-<platform>-<arch>
|
|
5
|
+
// optionalDependencies, falling back to the copy postinstall.js downloaded
|
|
6
|
+
// when optional dependencies were skipped. The `bin` stays a Node script —
|
|
7
|
+
// pointing it at the raw executable breaks the shims npm/pnpm/bun generate
|
|
8
|
+
// on Windows.
|
|
9
|
+
const { spawnSync } = require("node:child_process");
|
|
10
|
+
const fs = require("node:fs");
|
|
11
|
+
const path = require("node:path");
|
|
12
|
+
|
|
13
|
+
function resolveBinary() {
|
|
14
|
+
if (process.env.INFLEXA_BIN_PATH) return process.env.INFLEXA_BIN_PATH;
|
|
15
|
+
const binName = process.platform === "win32" ? "inflexa.exe" : "inflexa";
|
|
16
|
+
// TODO(extend): pick a -musl platform package on musl libc once those
|
|
17
|
+
// binaries ship (inflexa-ai/inflexa#107).
|
|
18
|
+
const pkg = `@inflexa-ai/inflexa-${process.platform}-${process.arch}`;
|
|
19
|
+
try {
|
|
20
|
+
const pkgJson = require.resolve(`${pkg}/package.json`);
|
|
21
|
+
return path.join(path.dirname(pkgJson), "bin", binName);
|
|
22
|
+
} catch {
|
|
23
|
+
const fallback = path.join(__dirname, "..", "bin-fallback", binName);
|
|
24
|
+
if (fs.existsSync(fallback)) return fallback;
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const bin = resolveBinary();
|
|
30
|
+
if (!bin) {
|
|
31
|
+
console.error(
|
|
32
|
+
[
|
|
33
|
+
`inflexa: no binary available for ${process.platform}-${process.arch}.`,
|
|
34
|
+
"The platform package (an optionalDependency) was not installed, and the",
|
|
35
|
+
"postinstall fallback did not deliver a binary either. Reinstall without",
|
|
36
|
+
"--no-optional/--omit=optional/--ignore-scripts, or install the platform",
|
|
37
|
+
`package directly: npm install @inflexa-ai/inflexa-${process.platform}-${process.arch}`,
|
|
38
|
+
].join("\n"),
|
|
39
|
+
);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const result = spawnSync(bin, process.argv.slice(2), { stdio: "inherit" });
|
|
44
|
+
if (result.error) {
|
|
45
|
+
console.error(`inflexa: failed to start ${bin}: ${result.error.message}`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
process.exit(typeof result.status === "number" ? result.status : 0);
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@inflexa-ai/inflexa",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Local-first AI agent for reproducible biological data analysis",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"homepage": "https://github.com/inflexa-ai/inflexa",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/inflexa-ai/inflexa.git"
|
|
10
|
+
},
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public",
|
|
13
|
+
"registry": "https://registry.npmjs.org"
|
|
14
|
+
},
|
|
15
|
+
"bin": {
|
|
16
|
+
"inflexa": "bin/inflexa.js"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"bin",
|
|
20
|
+
"postinstall.js"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"postinstall": "node postinstall.js"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18"
|
|
27
|
+
},
|
|
28
|
+
"optionalDependencies": {
|
|
29
|
+
"@inflexa-ai/inflexa-darwin-arm64": "0.1.0",
|
|
30
|
+
"@inflexa-ai/inflexa-darwin-x64": "0.1.0",
|
|
31
|
+
"@inflexa-ai/inflexa-linux-x64": "0.1.0",
|
|
32
|
+
"@inflexa-ai/inflexa-win32-x64": "0.1.0"
|
|
33
|
+
}
|
|
34
|
+
}
|
package/postinstall.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Fallback binary delivery for installs that skipped optionalDependencies
|
|
3
|
+
// (--no-optional/--omit=optional, or a node_modules/lockfile carried across
|
|
4
|
+
// operating systems): downloads this exact version's binary from the GitHub
|
|
5
|
+
// release and verifies it against the release's SHA256SUMS — the file the
|
|
6
|
+
// release workflow generated and attested — before placing it in
|
|
7
|
+
// bin-fallback/ for the launcher.
|
|
8
|
+
//
|
|
9
|
+
// Failures warn and exit 0 instead of failing the whole `npm install`: a
|
|
10
|
+
// missing binary is only fatal when inflexa is actually invoked (the
|
|
11
|
+
// launcher prints recovery steps), while a hard postinstall failure would
|
|
12
|
+
// block installing any dependency tree that merely includes inflexa —
|
|
13
|
+
// e.g. on a platform we don't build for at all.
|
|
14
|
+
const { createHash } = require("node:crypto");
|
|
15
|
+
const fs = require("node:fs");
|
|
16
|
+
const path = require("node:path");
|
|
17
|
+
|
|
18
|
+
const REPO = "inflexa-ai/inflexa";
|
|
19
|
+
|
|
20
|
+
// npm platform key -> release asset name (npm says win32 where the release
|
|
21
|
+
// assets say windows).
|
|
22
|
+
const ASSETS = {
|
|
23
|
+
"darwin-arm64": "inflexa-darwin-arm64",
|
|
24
|
+
"darwin-x64": "inflexa-darwin-x64",
|
|
25
|
+
"linux-x64": "inflexa-linux-x64",
|
|
26
|
+
"win32-x64": "inflexa-windows-x64.exe",
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
async function main() {
|
|
30
|
+
const key = `${process.platform}-${process.arch}`;
|
|
31
|
+
const binName = process.platform === "win32" ? "inflexa.exe" : "inflexa";
|
|
32
|
+
|
|
33
|
+
// Fast path: the platform optionalDependency delivered the binary, nothing
|
|
34
|
+
// to download.
|
|
35
|
+
try {
|
|
36
|
+
require.resolve(`@inflexa-ai/inflexa-${key}/package.json`);
|
|
37
|
+
return;
|
|
38
|
+
} catch {
|
|
39
|
+
// fall through to the download
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const asset = ASSETS[key];
|
|
43
|
+
if (!asset) {
|
|
44
|
+
console.warn(`inflexa: no prebuilt binary exists for ${key}; the inflexa command will not run on this platform.`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const version = require(path.join(__dirname, "package.json")).version;
|
|
49
|
+
const base = `https://github.com/${REPO}/releases/download/v${version}`;
|
|
50
|
+
|
|
51
|
+
const binRes = await fetch(`${base}/${asset}`);
|
|
52
|
+
if (!binRes.ok) throw new Error(`download failed (HTTP ${binRes.status}): ${base}/${asset}`);
|
|
53
|
+
const bin = Buffer.from(await binRes.arrayBuffer());
|
|
54
|
+
|
|
55
|
+
const sumsRes = await fetch(`${base}/SHA256SUMS`);
|
|
56
|
+
if (!sumsRes.ok) throw new Error(`download failed (HTTP ${sumsRes.status}): ${base}/SHA256SUMS`);
|
|
57
|
+
const sums = await sumsRes.text();
|
|
58
|
+
let expected = null;
|
|
59
|
+
for (const line of sums.split("\n")) {
|
|
60
|
+
const [hash, name] = line.trim().split(/\s+/);
|
|
61
|
+
if (name === asset) {
|
|
62
|
+
expected = hash;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (!expected) throw new Error(`${asset} is not listed in the release's SHA256SUMS`);
|
|
67
|
+
const actual = createHash("sha256").update(bin).digest("hex");
|
|
68
|
+
if (actual !== expected) throw new Error(`checksum mismatch for ${asset} — expected ${expected}, got ${actual}`);
|
|
69
|
+
|
|
70
|
+
// Stage-then-rename so the launcher never sees a half-written binary.
|
|
71
|
+
const dir = path.join(__dirname, "bin-fallback");
|
|
72
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
73
|
+
const staged = path.join(dir, `.${binName}.tmp`);
|
|
74
|
+
fs.writeFileSync(staged, bin, { mode: 0o755 });
|
|
75
|
+
fs.renameSync(staged, path.join(dir, binName));
|
|
76
|
+
console.log(`inflexa: optionalDependencies were skipped — downloaded and verified ${asset} instead`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
main().catch(function (err) {
|
|
80
|
+
console.warn(`inflexa: postinstall fallback failed: ${err.message}`);
|
|
81
|
+
console.warn("inflexa: the inflexa command will not run until its binary is available — reinstall without --no-optional, or see https://github.com/inflexa-ai/inflexa");
|
|
82
|
+
});
|