@blackrose28/hapi 0.18.18-sharedhub → 0.18.91-dev

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/bin/hapi.cjs CHANGED
@@ -123,6 +123,15 @@ function reportMissingPlatformPackage(platformName = process.platform, archName
123
123
  log(` ${RELEASE_URL}`);
124
124
  }
125
125
 
126
+ // Tell the binary which wrapper version launched it. The compiled binary
127
+ // embeds the version it was built from; the wrapper package is the actual
128
+ // installed artifact, so its version is the one `hapi update` should
129
+ // compare against. Passed explicitly (rather than sniffed from paths) so
130
+ // the binary stays deterministic regardless of install layout.
131
+ function buildChildEnv(installedVersion) {
132
+ return { ...process.env, HAPI_INSTALLED_VERSION: installedVersion };
133
+ }
134
+
126
135
  function main() {
127
136
  if (!isSupportedPlatform()) {
128
137
  reportUnsupportedPlatform();
@@ -138,7 +147,7 @@ function main() {
138
147
  const args = process.argv.slice(2);
139
148
 
140
149
  try {
141
- execFileSync(binPath, args, { stdio: 'inherit' });
150
+ execFileSync(binPath, args, { stdio: 'inherit', env: buildChildEnv(pkg.version) });
142
151
  } catch (error) {
143
152
  const { status, signal } = reportExecutionFailure(error, binPath, args);
144
153
 
@@ -163,6 +172,7 @@ if (require.main === module) {
163
172
  }
164
173
 
165
174
  module.exports = {
175
+ buildChildEnv,
166
176
  formatCommand,
167
177
  getPlatformKey,
168
178
  getBinaryPath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blackrose28/hapi",
3
- "version": "0.18.18-sharedhub",
3
+ "version": "0.18.91-dev",
4
4
  "description": "App for agentic coding - access coding agent anywhere",
5
5
  "author": "daudaudinang",
6
6
  "license": "AGPL-3.0-only",
@@ -9,21 +9,24 @@
9
9
  "bugs": "https://github.com/daudaudinang/hapi/issues",
10
10
  "repository": {
11
11
  "type": "git",
12
- "url": "git+https://github.com/daudaudinang/hapi.git",
13
- "directory": "cli"
12
+ "url": "git+https://github.com/blackrose28/hapi-publisher.git"
14
13
  },
15
14
  "bin": {
16
15
  "hapi": "bin/hapi.cjs"
17
16
  },
18
17
  "files": [
19
18
  "bin/hapi.cjs",
20
- "NOTICE"
19
+ "NOTICE",
20
+ "scripts/install-platform.cjs"
21
21
  ],
22
+ "scripts": {
23
+ "postinstall": "node scripts/install-platform.cjs"
24
+ },
22
25
  "optionalDependencies": {
23
- "@blackrose28/hapi-darwin-arm64": "0.18.18-sharedhub",
24
- "@blackrose28/hapi-darwin-x64": "0.18.18-sharedhub",
25
- "@blackrose28/hapi-linux-arm64": "0.18.18-sharedhub",
26
- "@blackrose28/hapi-linux-x64": "0.18.18-sharedhub",
27
- "@blackrose28/hapi-win32-x64": "0.18.18-sharedhub"
26
+ "@blackrose28/hapi-darwin-arm64": "0.18.91-dev",
27
+ "@blackrose28/hapi-darwin-x64": "0.18.91-dev",
28
+ "@blackrose28/hapi-linux-arm64": "0.18.91-dev",
29
+ "@blackrose28/hapi-linux-x64": "0.18.91-dev",
30
+ "@blackrose28/hapi-win32-x64": "0.18.91-dev"
28
31
  }
29
32
  }
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // Postinstall hook for the @blackrose28/hapi wrapper package.
5
+ //
6
+ // The GitLab npm registry does not serve `optionalDependencies` in the
7
+ // packument it hands to `npm install`, so installing `@blackrose28/hapi` from it
8
+ // leaves the platform binary behind and the `hapi` launcher fails with
9
+ // "Missing platform package". This hook fetches the binary for the current
10
+ // platform whenever npm itself did not place it — so `npm install -g
11
+ // @blackrose28/hapi` stays a single command on any registry.
12
+ //
13
+ // When the registry does serve the platform packages (public npm), the binary
14
+ // is already present and this hook is a no-op.
15
+
16
+ const { execSync } = require('node:child_process');
17
+ const path = require('node:path');
18
+ const fs = require('node:fs');
19
+
20
+ const pkgPath = path.join(__dirname, '..', 'package.json');
21
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
22
+
23
+ const [scope, baseName] = pkg.name.startsWith('@')
24
+ ? pkg.name.split('/')
25
+ : ['', pkg.name];
26
+
27
+ const platformKey = `${process.platform}-${process.arch}`;
28
+ const platformPkg = scope
29
+ ? `${scope}/${baseName}-${platformKey}`
30
+ : `${baseName}-${platformKey}`;
31
+ const version = pkg.optionalDependencies && pkg.optionalDependencies[platformPkg];
32
+
33
+ // Current platform has no binary package — nothing to do (harmless).
34
+ if (!version) {
35
+ process.exit(0);
36
+ }
37
+
38
+ // npm already placed a matching binary (e.g. public npm registry). Nothing to do.
39
+ // Compare versions so a stale binary from a previous release is re-fetched
40
+ // rather than silently left behind after a wrapper-only upgrade.
41
+ try {
42
+ const installed = require(`${platformPkg}/package.json`);
43
+ if (installed.version === version) {
44
+ process.exit(0);
45
+ }
46
+ console.log(`[hapi] Platform binary ${platformPkg}@${installed.version} is outdated (need ${version}); re-fetching ...`);
47
+ } catch {
48
+ // Not installed — fall through and fetch it.
49
+ }
50
+
51
+ const registry = process.env.npm_config_registry || 'https://registry.npmjs.org';
52
+ console.log(`[hapi] Installing platform binary ${platformPkg}@${version} from ${registry} ...`);
53
+ const tmpDir = fs.mkdtempSync(path.join(require('node:os').tmpdir(), 'hapi-platform-'));
54
+ try {
55
+ fs.writeFileSync(
56
+ path.join(tmpDir, 'package.json'),
57
+ JSON.stringify({ name: 'hapi-platform-scratch', private: true })
58
+ );
59
+ // The outer npm run (this lifecycle hook) sets npm_config_global/prefix in
60
+ // the env; without clearing them the nested install would re-target the
61
+ // outer global prefix and collide with the wrapper's own files (EEXIST).
62
+ const childEnv = { ...process.env };
63
+ for (const key of Object.keys(childEnv)) {
64
+ if (key.startsWith('npm_config_')) {
65
+ delete childEnv[key];
66
+ }
67
+ }
68
+ // Install into a scratch dir with an isolated package.json and pinned prefix
69
+ // so npm does not traverse up parent directories (e.g. /tmp/package.json)
70
+ // and fetches only this platform package, not every optionalDependency.
71
+ execSync(
72
+ `npm install --prefix "${tmpDir}" ${platformPkg}@${version} --no-save --no-package-lock --no-audit --no-fund --registry="${registry}"`,
73
+ { stdio: 'inherit', cwd: tmpDir, env: childEnv }
74
+ );
75
+ const dest = path.join(__dirname, '..', 'node_modules', ...platformPkg.split('/'));
76
+ fs.rmSync(dest, { recursive: true, force: true });
77
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
78
+ fs.cpSync(path.join(tmpDir, 'node_modules', ...platformPkg.split('/')), dest, { recursive: true });
79
+ } catch (error) {
80
+ console.error(
81
+ `[hapi] Failed to auto-install the ${platformPkg}@${version} platform binary.\n` +
82
+ ` Install it manually:\n npm install -g ${platformPkg}@${version} --registry="${registry}"\n` +
83
+ ' then re-run `hapi`.'
84
+ );
85
+ process.exit(1);
86
+ } finally {
87
+ fs.rmSync(tmpDir, { recursive: true, force: true });
88
+ }