dejima 0.8.1 → 0.8.8

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 CHANGED
@@ -8,10 +8,11 @@ npm install -g dejima
8
8
  dejima --version
9
9
  ```
10
10
 
11
- On install, this package downloads the prebuilt `dejima` binary matching its
12
- version from the [GitHub Release](https://github.com/aoos/dejima/releases),
13
- checksum-verifies it, and puts a `dejima` command on your PATH. No Go toolchain
14
- required.
11
+ The prebuilt `dejima` binary for your platform ships inside a per-platform
12
+ package (`@dejima/cli-<platform>-<arch>`) that npm installs automatically as an
13
+ optional dependency only the one matching your OS/CPU. There's **no install
14
+ script** (so it works under npm 11's default script-blocking), and no Go
15
+ toolchain required; the `dejima` command lands on your PATH.
15
16
 
16
17
  ## What this installs (and what it doesn't)
17
18
 
@@ -46,13 +47,13 @@ See <https://dejima.tech/> for the full picture.
46
47
 
47
48
  ## Environment knobs
48
49
 
49
- - `DEJIMA_SKIP_DOWNLOAD=1` — skip the postinstall download (offline / sandboxed
50
- CI). Provide your own binary at runtime with `DEJIMA_BINARY=/path/to/dejima`.
51
- - `DEJIMA_BINARY=/path/to/dejima` — run a specific binary instead of the
52
- downloaded one.
50
+ - `DEJIMA_BINARY=/path/to/dejima` — run a specific binary instead of the bundled
51
+ platform one (offline installs, `npm i --no-optional`, or a binary you built).
53
52
 
54
53
  ## Notes
55
54
 
56
- - Requires Node 16+ and a `tar` on PATH (bundled on macOS, Linux, and Windows 10+).
57
- - macOS binaries are currently unsigned; the installer strips the Gatekeeper
58
- quarantine attribute on download. Notarization is on the roadmap.
55
+ - Requires Node 16+.
56
+ - macOS binaries are currently unsigned. When downloaded via npm, Gatekeeper may
57
+ quarantine them; if macOS blocks the binary, clear it with
58
+ `xattr -d com.apple.quarantine "$(npm root -g)/dejima/node_modules/@dejima/cli-darwin-arm64/bin/dejima"`
59
+ (adjust the arch). Notarization is on the roadmap.
package/bin/dejima.js CHANGED
@@ -1,20 +1,49 @@
1
1
  #!/usr/bin/env node
2
- // Thin shim: exec the dejima binary that install.js placed in ../binary/,
3
- // forwarding argv, stdio, and the exit code. Lets `npm install -g dejima`
4
- // expose a real `dejima` command on PATH.
2
+ // Launcher for the `dejima` CLI. The real binary ships INSIDE a per-platform
3
+ // package (@dejima/cli-<platform>-<arch>) declared as an optionalDependency, so
4
+ // npm installs only the one matching this host (os/cpu fields) and skips the
5
+ // rest. There is NO postinstall download — that was blocked by npm 11's default
6
+ // script-blocking and left the CLI non-functional. This shim resolves the
7
+ // platform package and execs its binary, forwarding argv, stdio, and exit code.
8
+ //
9
+ // DEJIMA_BINARY overrides the resolved path (offline installs / CI / a binary
10
+ // you provide yourself, e.g. when installed with --no-optional).
5
11
  'use strict';
6
12
 
7
13
  const fs = require('fs');
8
14
  const path = require('path');
9
15
  const { spawnSync } = require('child_process');
10
16
 
17
+ // node's process.platform is already darwin|linux|win32; process.arch is
18
+ // x64|arm64 — the exact suffixes our platform packages use.
19
+ const pkgName = `@dejima/cli-${process.platform}-${process.arch}`;
11
20
  const exe = process.platform === 'win32' ? 'dejima.exe' : 'dejima';
12
- const binary = process.env.DEJIMA_BINARY || path.join(__dirname, '..', 'binary', exe);
13
21
 
14
- if (!fs.existsSync(binary)) {
15
- console.error(`dejima: binary not found at ${binary}`);
16
- console.error('The postinstall download may have failed. Reinstall the package, or');
17
- console.error('set DEJIMA_BINARY to the path of a dejima binary you provide yourself.');
22
+ function resolveBinary() {
23
+ if (process.env.DEJIMA_BINARY) {
24
+ return process.env.DEJIMA_BINARY;
25
+ }
26
+ // Resolve the package's own package.json (always present + resolvable) and
27
+ // join the binary path, rather than require.resolve-ing the extensionless
28
+ // binary directly — more robust across node versions and bundlers. esbuild,
29
+ // swc and turbo resolve their platform binaries the same way.
30
+ try {
31
+ const pkgJson = require.resolve(`${pkgName}/package.json`);
32
+ return path.join(path.dirname(pkgJson), 'bin', exe);
33
+ } catch (_) {
34
+ return null;
35
+ }
36
+ }
37
+
38
+ const binary = resolveBinary();
39
+ if (!binary || !fs.existsSync(binary)) {
40
+ console.error(`dejima: no prebuilt binary for ${process.platform}-${process.arch}.`);
41
+ console.error(`Expected the optional dependency ${pkgName} to be installed.`);
42
+ console.error('This usually means the platform is unsupported, or the package was');
43
+ console.error('installed with --no-optional / --omit=optional. Alternatives:');
44
+ console.error(' • curl -fsSL https://dejima.tech/install-client.sh | bash');
45
+ console.error(' • brew install aoos/dejima/dejima');
46
+ console.error(' • set DEJIMA_BINARY to the path of a dejima binary you provide.');
18
47
  process.exit(1);
19
48
  }
20
49
 
package/package.json CHANGED
@@ -1,19 +1,23 @@
1
1
  {
2
2
  "name": "dejima",
3
- "version": "0.8.1",
3
+ "version": "0.8.8",
4
4
  "description": "CLI for Dejima — run a fleet of isolated AI coding agents on hardware you own.",
5
5
  "license": "Apache-2.0",
6
6
  "bin": {
7
7
  "dejima": "bin/dejima.js"
8
8
  },
9
- "scripts": {
10
- "postinstall": "node ./install.js"
11
- },
12
9
  "files": [
13
10
  "bin/dejima.js",
14
- "install.js",
15
11
  "README.md"
16
12
  ],
13
+ "optionalDependencies": {
14
+ "@dejima/cli-darwin-arm64": "0.8.8",
15
+ "@dejima/cli-darwin-x64": "0.8.8",
16
+ "@dejima/cli-linux-arm64": "0.8.8",
17
+ "@dejima/cli-linux-x64": "0.8.8",
18
+ "@dejima/cli-win32-arm64": "0.8.8",
19
+ "@dejima/cli-win32-x64": "0.8.8"
20
+ },
17
21
  "engines": {
18
22
  "node": ">=16"
19
23
  },
package/install.js DELETED
@@ -1,169 +0,0 @@
1
- #!/usr/bin/env node
2
- // Postinstall hook for the `dejima` npm package.
3
- //
4
- // Downloads the dejima CLI binary that matches this package's version from the
5
- // GitHub Release, verifies its SHA256 against the release's SHA256SUMS, and
6
- // unpacks it into ./binary/. The bin shim (bin/dejima.js) execs it.
7
- //
8
- // This package ships only the CLI *client* — the cross-platform binary you
9
- // drive a Dejima host with. The daemon (dejimad) and the island image are
10
- // Unix-host-only; install those with `curl -fsSL https://dejima.tech/install.sh
11
- // | bash` or Homebrew. See README.md.
12
- //
13
- // Knobs:
14
- // DEJIMA_SKIP_DOWNLOAD=1 skip the download (e.g. offline CI); provide your
15
- // own binary via DEJIMA_BINARY at runtime instead.
16
- 'use strict';
17
-
18
- const fs = require('fs');
19
- const path = require('path');
20
- const https = require('https');
21
- const crypto = require('crypto');
22
- const { execFileSync } = require('child_process');
23
-
24
- const REPO = 'aoos/dejima';
25
- const pkg = require('./package.json');
26
- const version = String(pkg.version).replace(/^v/, '');
27
- const tag = `v${version}`;
28
-
29
- if (process.env.DEJIMA_SKIP_DOWNLOAD === '1') {
30
- console.log('dejima: DEJIMA_SKIP_DOWNLOAD=1 set — skipping binary download.');
31
- process.exit(0);
32
- }
33
-
34
- function mapPlatform() {
35
- switch (process.platform) {
36
- case 'darwin': return 'darwin';
37
- case 'linux': return 'linux';
38
- case 'win32': return 'windows';
39
- default: throw new Error(`unsupported platform: ${process.platform}`);
40
- }
41
- }
42
- function mapArch() {
43
- switch (process.arch) {
44
- case 'x64': return 'amd64';
45
- case 'arm64': return 'arm64';
46
- default: throw new Error(`unsupported arch: ${process.arch}`);
47
- }
48
- }
49
-
50
- const plat = mapPlatform();
51
- const arch = mapArch();
52
- const ext = plat === 'windows' ? 'zip' : 'tar.gz';
53
- const asset = `dejima_${tag}_${plat}_${arch}.${ext}`;
54
- const base = `https://github.com/${REPO}/releases/download/${tag}`;
55
-
56
- // GET that follows redirects (GitHub release assets 302 to a CDN) and buffers
57
- // the body. Caps redirects so a misconfigured mirror can't loop forever.
58
- function get(url, redirects = 0) {
59
- return new Promise((resolve, reject) => {
60
- if (redirects > 10) return reject(new Error('too many redirects'));
61
- https
62
- .get(url, { headers: { 'User-Agent': 'dejima-npm-installer' } }, (res) => {
63
- const { statusCode, headers } = res;
64
- if (statusCode >= 300 && statusCode < 400 && headers.location) {
65
- res.resume();
66
- resolve(get(headers.location, redirects + 1));
67
- return;
68
- }
69
- if (statusCode !== 200) {
70
- res.resume();
71
- reject(new Error(`GET ${url} -> HTTP ${statusCode}`));
72
- return;
73
- }
74
- const chunks = [];
75
- res.on('data', (c) => chunks.push(c));
76
- res.on('end', () => resolve(Buffer.concat(chunks)));
77
- })
78
- .on('error', reject);
79
- });
80
- }
81
-
82
- async function verifyChecksum(tarball) {
83
- let sums;
84
- try {
85
- sums = (await get(`${base}/SHA256SUMS`)).toString('utf8');
86
- } catch (e) {
87
- console.warn(`dejima: could not fetch SHA256SUMS (${e.message}) — skipping checksum.`);
88
- return;
89
- }
90
- const row = sums
91
- .split('\n')
92
- .map((l) => l.trim().split(/\s+/))
93
- .find((p) => p[1] === asset);
94
- if (!row) {
95
- console.warn(`dejima: ${asset} not listed in SHA256SUMS — skipping checksum.`);
96
- return;
97
- }
98
- const got = crypto.createHash('sha256').update(tarball).digest('hex');
99
- if (got !== row[0]) {
100
- throw new Error(`checksum mismatch for ${asset}\n want ${row[0]}\n got ${got}`);
101
- }
102
- console.log('dejima: checksum OK');
103
- }
104
-
105
- async function main() {
106
- const binDir = path.join(__dirname, 'binary');
107
- fs.mkdirSync(binDir, { recursive: true });
108
-
109
- console.log(`dejima: downloading ${asset} …`);
110
- let tarball;
111
- try {
112
- tarball = await get(`${base}/${asset}`);
113
- } catch (e) {
114
- // A 404 here almost always means there's no published Release for this exact
115
- // version/platform yet (or the tag isn't out). Say so plainly instead of
116
- // surfacing a raw "HTTP 404" the way a generic failure would.
117
- if (/HTTP 404/.test(e.message)) {
118
- throw new Error(
119
- `no prebuilt binary for this version/platform yet — ${asset} isn't in ` +
120
- `release ${tag}.\n See https://github.com/${REPO}/releases for what's published.`
121
- );
122
- }
123
- throw e;
124
- }
125
- await verifyChecksum(tarball);
126
-
127
- // Unpack with the system tar. bsdtar (Windows 10+ `tar.exe`) reads .zip too;
128
- // gnutar/bsdtar read .tar.gz on Unix. Archives carry dejima (+ dejimad on
129
- // Unix, which we leave unused) and LICENSE/README.
130
- const archivePath = path.join(binDir, asset);
131
- fs.writeFileSync(archivePath, tarball);
132
- const flags = ext === 'tar.gz' ? ['-xzf'] : ['-xf'];
133
- execFileSync('tar', [...flags, archivePath, '-C', binDir], { stdio: 'inherit' });
134
- fs.unlinkSync(archivePath);
135
-
136
- const exe = plat === 'windows' ? 'dejima.exe' : 'dejima';
137
- const exePath = path.join(binDir, exe);
138
- if (!fs.existsSync(exePath)) {
139
- throw new Error(`expected ${exe} in ${asset}, but it was not found after extraction`);
140
- }
141
- if (plat !== 'windows') fs.chmodSync(exePath, 0o755);
142
-
143
- // Drop the extras the archive carries (dejimad, LICENSE, README) — this
144
- // package is the CLI client only, so keep just the one binary.
145
- for (const f of fs.readdirSync(binDir)) {
146
- if (f !== exe) fs.rmSync(path.join(binDir, f), { force: true });
147
- }
148
-
149
- // Strip the macOS quarantine xattr — binaries are unsigned until notarization
150
- // lands, so Gatekeeper would otherwise block the downloaded executable.
151
- if (plat === 'darwin') {
152
- try {
153
- execFileSync('xattr', ['-d', 'com.apple.quarantine', exePath], { stdio: 'ignore' });
154
- } catch (_) {
155
- /* attribute may be absent; ignore */
156
- }
157
- }
158
-
159
- console.log(`dejima ${version} installed → ${exePath}`);
160
- }
161
-
162
- main().catch((err) => {
163
- console.error(`\ndejima: install failed: ${err.message}\n`);
164
- console.error('Alternatives:');
165
- console.error(' • curl -fsSL https://dejima.tech/install-client.sh | bash');
166
- console.error(' • brew install aoos/dejima/dejima');
167
- console.error(' • set DEJIMA_SKIP_DOWNLOAD=1 and point DEJIMA_BINARY at a dejima binary.');
168
- process.exit(1);
169
- });