lean-spec 0.2.18 → 0.2.19-dev.21166357960

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.
@@ -14,7 +14,7 @@ import { spawn } from 'child_process';
14
14
  import { createRequire } from 'module';
15
15
  import { fileURLToPath } from 'url';
16
16
  import { dirname, join } from 'path';
17
- import { accessSync } from 'fs';
17
+ import { accessSync, openSync, readSync, closeSync } from 'fs';
18
18
 
19
19
  const require = createRequire(import.meta.url);
20
20
  const __filename = fileURLToPath(import.meta.url);
@@ -27,10 +27,64 @@ const debug = (...args) => DEBUG && console.error('[lean-spec debug]', ...args);
27
27
  // Platform detection mapping
28
28
  const PLATFORM_MAP = {
29
29
  darwin: { x64: 'darwin-x64', arm64: 'darwin-arm64' },
30
- linux: { x64: 'linux-x64', arm64: 'linux-arm64' },
30
+ linux: { x64: 'linux-x64' },
31
31
  win32: { x64: 'windows-x64', arm64: 'windows-arm64' }
32
32
  };
33
33
 
34
+ const MACHO_MAGICS = new Set([
35
+ 0xfeedface,
36
+ 0xfeedfacf,
37
+ 0xcefaedfe,
38
+ 0xcffaedfe,
39
+ 0xcafebabe,
40
+ 0xbebafeca,
41
+ ]);
42
+
43
+ function readHeaderBytes(filePath) {
44
+ const fd = openSync(filePath, 'r');
45
+ try {
46
+ const buffer = Buffer.alloc(4);
47
+ const bytesRead = readSync(fd, buffer, 0, 4, 0);
48
+ return bytesRead === 4 ? buffer : null;
49
+ } finally {
50
+ closeSync(fd);
51
+ }
52
+ }
53
+
54
+ function isValidBinaryHeader(filePath, platform) {
55
+ try {
56
+ const header = readHeaderBytes(filePath);
57
+ if (!header) return false;
58
+
59
+ if (platform === 'linux') {
60
+ return header[0] === 0x7f && header[1] === 0x45 && header[2] === 0x4c && header[3] === 0x46;
61
+ }
62
+
63
+ if (platform === 'win32') {
64
+ return header[0] === 0x4d && header[1] === 0x5a;
65
+ }
66
+
67
+ if (platform === 'darwin') {
68
+ const magicBE = header.readUInt32BE(0);
69
+ const magicLE = header.readUInt32LE(0);
70
+ return MACHO_MAGICS.has(magicBE) || MACHO_MAGICS.has(magicLE);
71
+ }
72
+
73
+ return false;
74
+ } catch (error) {
75
+ debug('Failed to read binary header:', error.message);
76
+ return false;
77
+ }
78
+ }
79
+
80
+ function isExecutableBinary(filePath, platform) {
81
+ if (!isValidBinaryHeader(filePath, platform)) {
82
+ debug('Invalid binary header:', filePath);
83
+ return false;
84
+ }
85
+ return true;
86
+ }
87
+
34
88
  function getBinaryPath() {
35
89
  const platform = process.platform;
36
90
  const arch = process.arch;
@@ -53,8 +107,11 @@ function getBinaryPath() {
53
107
  // Try to resolve platform package
54
108
  try {
55
109
  const resolvedPath = require.resolve(`${packageName}/${binaryName}`);
56
- debug('Found platform package binary:', resolvedPath);
57
- return resolvedPath;
110
+ if (isExecutableBinary(resolvedPath, platform)) {
111
+ debug('Found platform package binary:', resolvedPath);
112
+ return resolvedPath;
113
+ }
114
+ debug('Platform package binary is invalid:', resolvedPath);
58
115
  } catch (e) {
59
116
  debug('Platform package not found:', packageName, '-', e.message);
60
117
  }
@@ -64,8 +121,11 @@ function getBinaryPath() {
64
121
  const localPath = join(__dirname, '..', 'binaries', platformKey, binaryName);
65
122
  debug('Trying local binary:', localPath);
66
123
  accessSync(localPath);
67
- debug('Found local binary:', localPath);
68
- return localPath;
124
+ if (isExecutableBinary(localPath, platform)) {
125
+ debug('Found local binary:', localPath);
126
+ return localPath;
127
+ }
128
+ debug('Local binary is invalid:', localPath);
69
129
  } catch (e) {
70
130
  debug('Local binary not found:', e.message);
71
131
  }
@@ -75,8 +135,11 @@ function getBinaryPath() {
75
135
  const rustTargetPath = join(__dirname, '..', '..', '..', 'rust', 'target', 'release', binaryName);
76
136
  debug('Trying rust target binary:', rustTargetPath);
77
137
  accessSync(rustTargetPath);
78
- debug('Found rust target binary:', rustTargetPath);
79
- return rustTargetPath;
138
+ if (isExecutableBinary(rustTargetPath, platform)) {
139
+ debug('Found rust target binary:', rustTargetPath);
140
+ return rustTargetPath;
141
+ }
142
+ debug('Rust target binary is invalid:', rustTargetPath);
80
143
  } catch (e) {
81
144
  debug('Rust target binary not found:', e.message);
82
145
  }
@@ -84,6 +147,12 @@ function getBinaryPath() {
84
147
  console.error(`Binary not found for ${platform}-${arch}`);
85
148
  console.error(`Expected package: ${packageName}`);
86
149
  console.error('');
150
+ console.error('Detected missing or corrupted binary.');
151
+ console.error('If you installed globally, reinstall to restore the binary:');
152
+ console.error(' npm uninstall -g lean-spec && npm install -g lean-spec');
153
+ console.error('');
154
+ console.error('If your npm config omits optional dependencies, enable them and reinstall.');
155
+ console.error('');
87
156
  console.error('To install:');
88
157
  console.error(' npm install -g lean-spec');
89
158
  console.error('');
Binary file
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leanspec/cli-darwin-arm64",
3
- "version": "0.2.18",
3
+ "version": "0.2.19-dev.21166357960",
4
4
  "description": "LeanSpec CLI binary for macOS ARM64",
5
5
  "os": [
6
6
  "darwin"
Binary file
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leanspec/cli-darwin-x64",
3
- "version": "0.2.18",
3
+ "version": "0.2.19-dev.21166357960",
4
4
  "description": "LeanSpec CLI binary for macOS x64",
5
5
  "os": [
6
6
  "darwin"
Binary file
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leanspec/cli-linux-x64",
3
- "version": "0.2.18",
3
+ "version": "0.2.19-dev.21166357960",
4
4
  "description": "LeanSpec CLI binary for Linux x64",
5
5
  "os": [
6
6
  "linux"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leanspec/cli-windows-x64",
3
- "version": "0.2.18",
3
+ "version": "0.2.19-dev.21166357960",
4
4
  "description": "LeanSpec CLI binary for Windows x64",
5
5
  "os": [
6
6
  "win32"
@@ -10,8 +10,12 @@
10
10
  ],
11
11
  "main": "lean-spec.exe",
12
12
  "files": [
13
- "lean-spec.exe"
13
+ "lean-spec.exe",
14
+ "postinstall.js"
14
15
  ],
16
+ "scripts": {
17
+ "postinstall": "node postinstall.js"
18
+ },
15
19
  "repository": {
16
20
  "type": "git",
17
21
  "url": "https://github.com/codervisor/lean-spec.git"
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Postinstall script - no-op on Windows (permissions not needed).
4
+ * This file exists for consistency across all platform packages.
5
+ */
6
+ console.log('✓ lean-spec.exe ready');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lean-spec",
3
- "version": "0.2.18",
3
+ "version": "0.2.19-dev.21166357960",
4
4
  "description": "Specification-driven development made simple",
5
5
  "type": "module",
6
6
  "bin": {
@@ -35,14 +35,13 @@
35
35
  "LICENSE",
36
36
  "CHANGELOG.md"
37
37
  ],
38
- "optionalDependencies": {
39
- "@leanspec/cli-darwin-arm64": "^0.2.18",
40
- "@leanspec/cli-darwin-x64": "^0.2.18",
41
- "@leanspec/cli-linux-arm64": "^0.2.18",
42
- "@leanspec/cli-linux-x64": "^0.2.18",
43
- "@leanspec/cli-windows-x64": "^0.2.18"
44
- },
45
38
  "engines": {
46
39
  "node": ">=20"
40
+ },
41
+ "optionalDependencies": {
42
+ "@leanspec/cli-darwin-x64": "^0.2.19-dev.21166357960",
43
+ "@leanspec/cli-darwin-arm64": "^0.2.19-dev.21166357960",
44
+ "@leanspec/cli-linux-x64": "^0.2.19-dev.21166357960",
45
+ "@leanspec/cli-windows-x64": "^0.2.19-dev.21166357960"
47
46
  }
48
47
  }
@@ -1,24 +0,0 @@
1
- {
2
- "name": "@leanspec/cli-linux-arm64",
3
- "version": "0.2.18",
4
- "description": "LeanSpec CLI binary for Linux ARM64",
5
- "os": [
6
- "linux"
7
- ],
8
- "cpu": [
9
- "arm64"
10
- ],
11
- "main": "lean-spec",
12
- "files": [
13
- "lean-spec",
14
- "postinstall.js"
15
- ],
16
- "scripts": {
17
- "postinstall": "node postinstall.js"
18
- },
19
- "repository": {
20
- "type": "git",
21
- "url": "https://github.com/codervisor/lean-spec.git"
22
- },
23
- "license": "MIT"
24
- }
@@ -1,17 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Postinstall script to set execute permissions on the binary.
4
- * npm doesn't preserve file permissions, so we need to set them after install.
5
- */
6
- const { chmodSync } = require('fs');
7
- const { join } = require('path');
8
-
9
- const binaryPath = join(__dirname, 'lean-spec');
10
-
11
- try {
12
- chmodSync(binaryPath, 0o755);
13
- console.log('✓ Set execute permissions on lean-spec binary');
14
- } catch (err) {
15
- console.error('Warning: Could not set execute permissions:', err.message);
16
- // Don't fail the install
17
- }