@goodfoot/wiki 0.5.63 → 0.5.66

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/wiki.exe ADDED
@@ -0,0 +1,6 @@
1
+ @goodfoot/wiki placeholder. scripts/postinstall.js replaces this file
2
+ with the native binary for your platform. The name ends in .exe and the
3
+ first line intentionally has NO "#!" shebang so npm/yarn/pnpm cmd-shim
4
+ generates a direct-exec wrapper that runs on Windows; Unix ignores the
5
+ .exe suffix and execs by mode bit. If you are seeing this text, the
6
+ postinstall step did not run.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@goodfoot/wiki",
3
- "version": "0.5.63",
4
- "bin": "bin/wiki",
3
+ "version": "0.5.66",
4
+ "bin": "bin/wiki.exe",
5
5
  "scripts": {
6
6
  "postinstall": "node scripts/postinstall.js",
7
7
  "build": "env PATH=\"$HOME/.cargo/bin:$PATH\" CARGO_BUILD_JOBS=1 CARGO_TARGET_DIR=target/build cargo build --release",
@@ -12,15 +12,15 @@
12
12
  "typecheck": "env PATH=\"$HOME/.cargo/bin:$PATH\" CARGO_BUILD_JOBS=1 CARGO_TARGET_DIR=target/typecheck cargo check --quiet"
13
13
  },
14
14
  "files": [
15
- "bin/",
15
+ "bin/wiki.exe",
16
16
  "scripts/postinstall.js"
17
17
  ],
18
18
  "optionalDependencies": {
19
- "@goodfoot/wiki-darwin-arm64": "0.5.63",
20
- "@goodfoot/wiki-darwin-x64": "0.5.63",
21
- "@goodfoot/wiki-linux-arm64": "0.5.63",
22
- "@goodfoot/wiki-linux-x64": "0.5.63",
23
- "@goodfoot/wiki-win32-x64": "0.5.63"
19
+ "@goodfoot/wiki-darwin-arm64": "0.5.66",
20
+ "@goodfoot/wiki-darwin-x64": "0.5.66",
21
+ "@goodfoot/wiki-linux-arm64": "0.5.66",
22
+ "@goodfoot/wiki-linux-x64": "0.5.66",
23
+ "@goodfoot/wiki-win32-x64": "0.5.66"
24
24
  },
25
25
  "repository": {
26
26
  "type": "git",
@@ -2,6 +2,7 @@
2
2
 
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
+ const { spawnSync } = require('child_process');
5
6
 
6
7
  const PLATFORM_MAP = {
7
8
  linux: 'linux',
@@ -14,15 +15,74 @@ const ARCH_MAP = {
14
15
  arm64: 'arm64'
15
16
  };
16
17
 
18
+ function fail(message, error) {
19
+ console.error(message);
20
+ if (error) {
21
+ console.error(error.message);
22
+ }
23
+ process.exit(1);
24
+ }
25
+
26
+ function buildFromSource(destBinary, binaryName) {
27
+ const cargoToml = path.join(__dirname, '..', 'Cargo.toml');
28
+ if (!fs.existsSync(cargoToml)) {
29
+ fail(`@goodfoot/wiki: Binary not found at ${destBinary} and no Cargo.toml available to build from source.`);
30
+ }
31
+
32
+ console.log(`@goodfoot/wiki: Prebuilt binary missing; building from source via cargo...`);
33
+
34
+ const targetDir = path.join(__dirname, '..', 'target-cache', 'build');
35
+ const result = spawnSync('cargo', ['build', '--release', '--manifest-path', cargoToml], {
36
+ stdio: 'inherit',
37
+ env: { ...process.env, CARGO_BUILD_JOBS: '1', CARGO_TARGET_DIR: targetDir }
38
+ });
39
+
40
+ if (result.error || result.status !== 0) {
41
+ fail(
42
+ `@goodfoot/wiki: Failed to build binary from source. Install Rust/cargo or publish the platform package.`,
43
+ result.error
44
+ );
45
+ }
46
+
47
+ const builtBinary = path.join(targetDir, 'release', binaryName);
48
+ if (!fs.existsSync(builtBinary)) {
49
+ fail(`@goodfoot/wiki: cargo build succeeded but binary not found at ${builtBinary}.`);
50
+ }
51
+
52
+ fs.mkdirSync(path.dirname(destBinary), { recursive: true });
53
+ fs.copyFileSync(builtBinary, destBinary);
54
+ fs.chmodSync(destBinary, 0o755);
55
+ }
56
+
57
+ function isInsideSourceTree() {
58
+ // Walk up from this script looking for a `.git` entry. If found, this is
59
+ // the @goodfoot/wiki source repo (developer doing `yarn install`), not a
60
+ // consumer install under node_modules. Mutating the tracked `bin/wiki`
61
+ // shim in that case dirties the working tree and — if committed — ships a
62
+ // dangling symlink (or a leaked absolute build path) in the published
63
+ // tarball.
64
+ let dir = path.resolve(__dirname, '..');
65
+ for (let i = 0; i < 16; i++) {
66
+ if (fs.existsSync(path.join(dir, '.git'))) return true;
67
+ const parent = path.dirname(dir);
68
+ if (parent === dir) return false;
69
+ if (path.basename(parent) === 'node_modules') return false;
70
+ dir = parent;
71
+ }
72
+ return false;
73
+ }
74
+
17
75
  function main() {
76
+ if (isInsideSourceTree()) {
77
+ console.log('@goodfoot/wiki: postinstall skipped (running inside source tree).');
78
+ return;
79
+ }
80
+
18
81
  const platform = PLATFORM_MAP[process.platform];
19
82
  const arch = ARCH_MAP[process.arch];
20
83
 
21
84
  if (!platform || !arch) {
22
- console.log(
23
- `@goodfoot/wiki: No prebuilt binary available for ${process.platform}-${process.arch}. Build from source with "cargo build --release".`
24
- );
25
- process.exit(0);
85
+ fail(`@goodfoot/wiki: No prebuilt binary available for ${process.platform}-${process.arch}.`);
26
86
  }
27
87
 
28
88
  const packageName = `@goodfoot/wiki-${platform}-${arch}`;
@@ -31,31 +91,51 @@ function main() {
31
91
  let packageDir;
32
92
  try {
33
93
  packageDir = path.dirname(require.resolve(`${packageName}/package.json`));
34
- } catch {
35
- // Platform package not installed -- user may have built from source
36
- console.log(`@goodfoot/wiki: Optional package ${packageName} not found. Skipping binary setup.`);
37
- process.exit(0);
94
+ } catch (error) {
95
+ fail(`@goodfoot/wiki: Required platform package ${packageName} not found.`, error);
38
96
  }
39
97
 
40
98
  const sourceBinary = path.join(packageDir, 'bin', sourceBinaryName);
41
99
  if (!fs.existsSync(sourceBinary)) {
42
- console.log(`@goodfoot/wiki: Binary not found in ${packageName}. The package may not have been published yet.`);
43
- process.exit(0);
100
+ buildFromSource(sourceBinary, sourceBinaryName);
44
101
  }
45
102
 
46
- const binWiki = path.join(__dirname, '..', 'bin', 'wiki');
103
+ // Always write to bin/wiki.exe the package.json `bin` field points
104
+ // here on every platform. The `.exe` extension plus a no-shebang stub makes
105
+ // npm's cmd-shim (generated at install time, before this postinstall) emit
106
+ // a direct exec on Windows; Unix executes by mode bit + ELF/Mach-O header
107
+ // and ignores the `.exe` suffix entirely. No resident Node process — the
108
+ // `wiki` command execs the native binary directly. Same pattern as
109
+ // Bun's and Claude Code's npm packages.
110
+ const binWiki = path.join(__dirname, '..', 'bin', 'wiki.exe');
47
111
 
112
+ // Hardlink first (instant, zero extra disk for the binary; src and dest are
113
+ // both under node_modules so same-filesystem is the common case), then fall
114
+ // back to copy across devices / on link-permission errors.
48
115
  try {
49
- fs.unlinkSync(binWiki);
50
- } catch {
51
- // Ignore if it doesn't exist
116
+ fs.linkSync(sourceBinary, binWiki);
117
+ } catch (linkError) {
118
+ if (linkError.code === 'EEXIST') {
119
+ try {
120
+ fs.unlinkSync(binWiki);
121
+ fs.linkSync(sourceBinary, binWiki);
122
+ } catch {
123
+ fs.copyFileSync(sourceBinary, binWiki);
124
+ }
125
+ } else if (linkError.code === 'EXDEV' || linkError.code === 'EPERM') {
126
+ fs.copyFileSync(sourceBinary, binWiki);
127
+ } else {
128
+ try {
129
+ fs.copyFileSync(sourceBinary, binWiki);
130
+ } catch (copyError) {
131
+ fail(
132
+ `@goodfoot/wiki: Could not install binary from ${sourceBinary} to ${binWiki}.`,
133
+ new Error(`link failed: ${linkError.message}\ncopy failed: ${copyError.message}`)
134
+ );
135
+ }
136
+ }
52
137
  }
53
-
54
- // Try symlink first, fall back to copy
55
- try {
56
- fs.symlinkSync(sourceBinary, binWiki);
57
- } catch {
58
- fs.copyFileSync(sourceBinary, binWiki);
138
+ if (process.platform !== 'win32') {
59
139
  fs.chmodSync(binWiki, 0o755);
60
140
  }
61
141