@pikaa-ai/pikaa 0.3.25 → 0.3.27

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.
Files changed (4) hide show
  1. package/bin/pikaa.js +125 -29
  2. package/dist/cli.js +214 -203
  3. package/dist/index.js +120 -120
  4. package/package.json +12 -1
package/bin/pikaa.js CHANGED
@@ -3,12 +3,12 @@
3
3
  /**
4
4
  * Universal Native Launcher for Pikaa Agent CLI.
5
5
  *
6
- * Automatically detects platform (macOS, Linux, Windows) and architecture (arm64, x64).
7
- * If the native binary is already present, runs it with 0ms startup time.
8
- * If not present (e.g. postinstall script skipped by npm allow-scripts), automatically
9
- * downloads the native binary from GitHub Releases to ~/.pikaa/bin/ and executes it.
6
+ * Automatically detects platform (macOS, Linux glibc/musl, Windows) and architecture (arm64, x64).
7
+ * 1. Resolves and executes the precompiled platform binary from optionalDependencies (0ms startup, zero network).
8
+ * 2. If running from local source, finds local dist/bin or compiles on the fly if Bun is present.
9
+ * 3. If installed with --no-optional, falls back to downloading the standalone binary to ~/.pikaa/bin/.
10
10
  *
11
- * Zero external dependencies required. Does NOT require Bun or compilation tools.
11
+ * Zero external dependencies required. Does NOT require Bun or compilation tools for end-users.
12
12
  */
13
13
 
14
14
  import { spawnSync } from "node:child_process";
@@ -17,39 +17,121 @@ import { fileURLToPath } from "node:url";
17
17
  import { dirname, join } from "node:path";
18
18
  import { homedir } from "node:os";
19
19
  import { pipeline } from "node:stream/promises";
20
+ import { createRequire } from "node:module";
20
21
  import https from "node:https";
21
22
 
22
23
  const __filename = fileURLToPath(import.meta.url);
23
24
  const __dirname = dirname(__filename);
24
25
  const rootDir = join(__dirname, "..");
26
+ const require = createRequire(import.meta.url);
25
27
 
26
28
  const platform = process.platform;
27
29
  const arch = process.arch;
28
30
 
29
31
  let version = "";
32
+ let scope = "@pikaa-ai";
30
33
  try {
31
34
  const pkg = JSON.parse(readFileSync(join(rootDir, "package.json"), "utf8"));
32
35
  version = pkg.version || "";
36
+ if (pkg.name && pkg.name.startsWith("@")) {
37
+ scope = pkg.name.split("/")[0];
38
+ }
33
39
  } catch {}
34
40
 
35
- function getBinaryName() {
36
- if (platform === "win32") return arch === "arm64" ? "pikaa-windows-arm64.exe" : "pikaa-windows-x64.exe";
37
- if (platform === "darwin") return arch === "arm64" ? "pikaa-darwin-arm64" : "pikaa-darwin-x64";
38
- if (platform === "linux") return arch === "arm64" ? "pikaa-linux-arm64" : "pikaa-linux-x64";
41
+ /**
42
+ * Check if the current Linux system uses musl libc (e.g. Alpine Linux)
43
+ */
44
+ export function isMusl() {
45
+ if (platform !== "linux") return false;
46
+ try {
47
+ if (existsSync("/etc/alpine-release")) return true;
48
+ const ldd = spawnSync("ldd", ["--version"], { encoding: "utf8" });
49
+ const text = (ldd.stdout || "") + (ldd.stderr || "");
50
+ if (text.toLowerCase().includes("musl")) return true;
51
+ } catch {}
52
+ return false;
53
+ }
54
+
55
+ /**
56
+ * Get the platform-specific sub-package information
57
+ */
58
+ export function getPlatformPackageInfo(customScope = scope) {
59
+ const isWindows = platform === "win32";
60
+ const binaryFile = isWindows ? "pikaa.exe" : "pikaa";
61
+
62
+ if (platform === "win32") {
63
+ if (arch === "arm64") {
64
+ return { pkg: `${customScope}/pikaa-windows-arm64`, binary: binaryFile, releaseFile: "pikaa-windows-arm64.exe", fallbackPkg: null };
65
+ }
66
+ return { pkg: `${customScope}/pikaa-windows-x64`, binary: binaryFile, releaseFile: "pikaa-windows-x64.exe", fallbackPkg: null };
67
+ }
68
+
69
+ if (platform === "darwin") {
70
+ if (arch === "arm64") {
71
+ return { pkg: `${customScope}/pikaa-darwin-arm64`, binary: binaryFile, releaseFile: "pikaa-darwin-arm64", fallbackPkg: null };
72
+ }
73
+ return { pkg: `${customScope}/pikaa-darwin-x64`, binary: binaryFile, releaseFile: "pikaa-darwin-x64", fallbackPkg: null };
74
+ }
75
+
76
+ if (platform === "linux") {
77
+ const musl = isMusl();
78
+ if (arch === "arm64") {
79
+ return musl
80
+ ? { pkg: `${customScope}/pikaa-linux-arm64-musl`, binary: binaryFile, releaseFile: "pikaa-linux-arm64-musl", fallbackPkg: `${customScope}/pikaa-linux-arm64` }
81
+ : { pkg: `${customScope}/pikaa-linux-arm64`, binary: binaryFile, releaseFile: "pikaa-linux-arm64", fallbackPkg: `${customScope}/pikaa-linux-arm64-musl` };
82
+ }
83
+ return musl
84
+ ? { pkg: `${customScope}/pikaa-linux-x64-musl`, binary: binaryFile, releaseFile: "pikaa-linux-x64-musl", fallbackPkg: `${customScope}/pikaa-linux-x64` }
85
+ : { pkg: `${customScope}/pikaa-linux-x64`, binary: binaryFile, releaseFile: "pikaa-linux-x64", fallbackPkg: `${customScope}/pikaa-linux-x64-musl` };
86
+ }
87
+
39
88
  return null;
40
89
  }
41
90
 
42
- const binaryName = getBinaryName();
91
+ const platformInfo = getPlatformPackageInfo();
43
92
  const userBinDir = join(homedir(), ".pikaa", "bin");
44
- const userBinaryPath = binaryName && version ? join(userBinDir, `pikaa-v${version}-${binaryName}`) : null;
93
+ const userBinaryPath = platformInfo && version ? join(userBinDir, `pikaa-v${version}-${platformInfo.releaseFile}`) : null;
45
94
 
46
- // Look in package directory or user cache directory
95
+ /**
96
+ * 1. Locate the native binary installed from optionalDependencies
97
+ */
98
+ function findPlatformPackageBinary() {
99
+ if (!platformInfo) return null;
100
+
101
+ const candidates = [platformInfo.pkg, platformInfo.fallbackPkg].filter(Boolean);
102
+
103
+ for (const pkgName of candidates) {
104
+ // A. Resolve through Node.js require.resolve
105
+ try {
106
+ const resolved = require.resolve(pkgName);
107
+ if (resolved && existsSync(resolved)) return resolved;
108
+ } catch {}
109
+
110
+ // B. Direct check in node_modules (local or hoisted)
111
+ const relativePaths = [
112
+ join(rootDir, "node_modules", pkgName, platformInfo.binary),
113
+ join(rootDir, "..", pkgName.replace(`${scope}/`, ""), platformInfo.binary),
114
+ join(rootDir, "..", pkgName, platformInfo.binary),
115
+ join(rootDir, "dist", "packages", pkgName.replace(`${scope}/`, ""), platformInfo.binary),
116
+ ];
117
+
118
+ for (const p of relativePaths) {
119
+ if (existsSync(p)) return p;
120
+ }
121
+ }
122
+
123
+ return null;
124
+ }
125
+
126
+ /**
127
+ * 2. Locate existing local or cached binary
128
+ */
47
129
  function findExistingBinary() {
48
- if (!binaryName) return null;
130
+ if (!platformInfo) return null;
49
131
  const candidates = [
50
132
  join(rootDir, "pikaa.exe"),
51
- join(rootDir, "bin", binaryName),
52
- join(rootDir, "dist", "bin", binaryName),
133
+ join(rootDir, "bin", platformInfo.releaseFile),
134
+ join(rootDir, "dist", "bin", platformInfo.releaseFile),
53
135
  userBinaryPath,
54
136
  ];
55
137
  for (const c of candidates) {
@@ -106,28 +188,36 @@ async function downloadBinary(url, dest, redirects = 0) {
106
188
  }
107
189
 
108
190
  async function main() {
109
- // 1. If local bun and dist/cli.js are available in the package, run immediately
110
- if (tryLaunchWithBun()) {
191
+ // 1. Primary: Use pre-installed native platform binary from optionalDependencies (0ms startup)
192
+ const platformBin = findPlatformPackageBinary();
193
+ if (platformBin) {
194
+ launchBinary(platformBin);
111
195
  return;
112
196
  }
113
197
 
114
- // 2. Otherwise use existing native binary if present
198
+ // 2. Secondary: Use local or cached standalone binary
115
199
  const existing = findExistingBinary();
116
200
  if (existing) {
117
201
  launchBinary(existing);
118
202
  return;
119
203
  }
120
204
 
121
- if (!binaryName || !userBinaryPath) {
122
- console.error(`[pikaa] Platform not supported: ${platform}/${arch}`);
205
+ // 3. Tertiary: If developing locally with Bun installed, run dist/cli.js
206
+ if (tryLaunchWithBun()) {
207
+ return;
208
+ }
209
+
210
+ if (!platformInfo || !userBinaryPath) {
211
+ console.error(`\x1b[31m[pikaa] Error: Unsupported platform/architecture: ${platform}/${arch}\x1b[0m`);
123
212
  process.exit(1);
124
213
  }
125
214
 
126
- const downloadUrl = `https://github.com/Neural-Forge-AMD/agent-cli/releases/download/v${version}/${binaryName}`;
215
+ // 4. Fallback: Download standalone binary from GitHub release (e.g. if installed with --no-optional)
216
+ const downloadUrl = `https://github.com/Neural-Forge-AMD/agent-cli/releases/download/v${version}/${platformInfo.releaseFile}`;
127
217
 
128
218
  try {
129
219
  mkdirSync(userBinDir, { recursive: true });
130
- process.stderr.write(`\x1b[36m⚡ [pikaa] First-time setup: Downloading native binary v${version} for ${platform}/${arch}...\x1b[0m\n`);
220
+ process.stderr.write(`\x1b[36m⚡ [pikaa] Downloading native binary v${version} for ${platform}/${arch}...\x1b[0m\n`);
131
221
  await downloadBinary(downloadUrl, userBinaryPath);
132
222
  if (platform !== "win32") {
133
223
  chmodSync(userBinaryPath, 0o755);
@@ -135,15 +225,21 @@ async function main() {
135
225
  process.stderr.write(`\x1b[32m✓ Setup complete!\x1b[0m\n\n`);
136
226
  launchBinary(userBinaryPath);
137
227
  } catch (err) {
138
- process.stderr.write(`\x1b[33mWarning: Failed to download native binary: ${err.message}\x1b[0m\n`);
228
+ process.stderr.write(`\x1b[33m[pikaa] Warning: Failed to download native binary: ${err.message}\x1b[0m\n`);
139
229
 
140
- if (tryLaunchWithBun()) {
141
- return;
142
- }
143
-
144
- console.error(`\nPlease check your internet connection or install Bun (https://bun.sh) and retry.`);
230
+ console.error(`\n\x1b[31m[pikaa] Could not find or download native executable for ${platform}/${arch}.\x1b[0m`);
231
+ console.error(`Please reinstall with optional dependencies:`);
232
+ console.error(` npm install -g ${scope}/pikaa\n`);
145
233
  process.exit(1);
146
234
  }
147
235
  }
148
236
 
149
- main();
237
+ const isDirectCall = process.argv[1] && (
238
+ process.argv[1].endsWith("pikaa.js") ||
239
+ process.argv[1].endsWith("pikaa") ||
240
+ process.argv[1].endsWith("groupy")
241
+ );
242
+
243
+ if (isDirectCall) {
244
+ main();
245
+ }