@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 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
+ });