@pikaa-ai/pikaa 0.1.8 → 0.2.0

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 (2) hide show
  1. package/bin/pikaa.js +98 -68
  2. package/package.json +1 -1
package/bin/pikaa.js CHANGED
@@ -1,18 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Universal Cross-Platform Dispatcher for Pikaa / Groupy Agent.
4
+ * Universal Native Launcher for Pikaa Agent CLI.
5
5
  *
6
- * Priority order:
7
- * 1. Precompiled native binary (zero-dependency, instant start)
8
- * 2. Bun runtime running the bundled JS (requires Bun installed)
9
- * 3. Clear error message pointing user to install Bun
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.
10
+ *
11
+ * Zero external dependencies required. Does NOT require Bun or compilation tools.
10
12
  */
11
13
 
12
14
  import { spawnSync } from "node:child_process";
13
- import { existsSync, chmodSync } from "node:fs";
15
+ import { existsSync, chmodSync, mkdirSync, createWriteStream, readFileSync } from "node:fs";
14
16
  import { fileURLToPath } from "node:url";
15
17
  import { dirname, join } from "node:path";
18
+ import { homedir } from "node:os";
19
+ import { pipeline } from "node:stream/promises";
20
+ import https from "node:https";
16
21
 
17
22
  const __filename = fileURLToPath(import.meta.url);
18
23
  const __dirname = dirname(__filename);
@@ -21,87 +26,112 @@ const rootDir = join(__dirname, "..");
21
26
  const platform = process.platform;
22
27
  const arch = process.arch;
23
28
 
24
- // Map OS & Arch to precompiled binary filename
25
29
  function getBinaryName() {
26
- if (platform === "win32") {
27
- return arch === "arm64" ? "pikaa-windows-arm64.exe" : "pikaa-windows-x64.exe";
28
- }
29
- if (platform === "darwin") {
30
- return arch === "arm64" ? "pikaa-darwin-arm64" : "pikaa-darwin-x64";
31
- }
32
- if (platform === "linux") {
33
- return arch === "arm64" ? "pikaa-linux-arm64" : "pikaa-linux-x64";
34
- }
30
+ if (platform === "win32") return arch === "arm64" ? "pikaa-windows-arm64.exe" : "pikaa-windows-x64.exe";
31
+ if (platform === "darwin") return arch === "arm64" ? "pikaa-darwin-arm64" : "pikaa-darwin-x64";
32
+ if (platform === "linux") return arch === "arm64" ? "pikaa-linux-arm64" : "pikaa-linux-x64";
35
33
  return null;
36
34
  }
37
35
 
38
- // --- 1. Try native binary ---
39
36
  const binaryName = getBinaryName();
40
- let nativeBinaryPath = null;
37
+ const userBinDir = join(homedir(), ".pikaa", "bin");
38
+ const userBinaryPath = binaryName ? join(userBinDir, binaryName) : null;
41
39
 
42
- if (binaryName) {
43
- for (const p of [
44
- join(rootDir, "dist", "bin", binaryName),
40
+ // Look in package directory or user cache directory
41
+ function findExistingBinary() {
42
+ if (!binaryName) return null;
43
+ const candidates = [
45
44
  join(rootDir, "bin", binaryName),
46
- join(rootDir, binaryName),
47
- ]) {
48
- if (existsSync(p)) {
49
- nativeBinaryPath = p;
50
- break;
51
- }
45
+ join(rootDir, "dist", "bin", binaryName),
46
+ userBinaryPath,
47
+ ];
48
+ for (const c of candidates) {
49
+ if (c && existsSync(c)) return c;
52
50
  }
51
+ return null;
52
+ }
53
+
54
+ async function downloadBinary(url, dest, redirects = 0) {
55
+ if (redirects > 5) throw new Error("Too many redirects");
56
+
57
+ await new Promise((resolve, reject) => {
58
+ const file = createWriteStream(dest);
59
+ https.get(url, { headers: { "User-Agent": "pikaa-cli-launcher" } }, (res) => {
60
+ if (res.statusCode === 301 || res.statusCode === 302) {
61
+ file.close();
62
+ resolve(downloadBinary(res.headers.location, dest, redirects + 1));
63
+ return;
64
+ }
65
+ if (res.statusCode !== 200) {
66
+ file.close();
67
+ reject(new Error(`HTTP ${res.statusCode} from ${url}`));
68
+ return;
69
+ }
70
+ pipeline(res, file).then(resolve).catch(reject);
71
+ }).on("error", reject);
72
+ });
53
73
  }
54
74
 
55
- if (nativeBinaryPath) {
75
+ function launchBinary(binPath) {
56
76
  if (platform !== "win32") {
57
- try { chmodSync(nativeBinaryPath, 0o755); } catch {}
77
+ try { chmodSync(binPath, 0o755); } catch {}
58
78
  }
59
- const result = spawnSync(nativeBinaryPath, process.argv.slice(2), {
79
+ const r = spawnSync(binPath, process.argv.slice(2), {
60
80
  stdio: "inherit",
61
81
  env: process.env,
62
82
  });
63
- process.exit(result.status ?? (result.error ? 1 : 0));
83
+ process.exit(r.status ?? (r.error ? 1 : 0));
64
84
  }
65
85
 
66
- // --- 2. Fallback: run via Bun (dist/cli.js is a Bun bundle) ---
67
- const jsEntry = join(rootDir, "dist", "cli.js");
68
-
69
- if (!existsSync(jsEntry)) {
70
- console.error("pikaa: dist/cli.js not found. Please reinstall the package.");
71
- process.exit(1);
72
- }
86
+ async function main() {
87
+ const existing = findExistingBinary();
88
+ if (existing) {
89
+ launchBinary(existing);
90
+ return;
91
+ }
73
92
 
74
- // Find Bun executable
75
- const bunCandidates = platform === "win32"
76
- ? ["bun.exe"]
77
- : ["bun"];
78
-
79
- let bunBin = null;
80
- for (const candidate of bunCandidates) {
81
- const probe = spawnSync(candidate, ["--version"], { encoding: "utf8" });
82
- if (!probe.error) {
83
- bunBin = candidate;
84
- break;
93
+ if (!binaryName || !userBinaryPath) {
94
+ console.error(`[pikaa] Platform not supported: ${platform}/${arch}`);
95
+ process.exit(1);
85
96
  }
86
- }
87
97
 
88
- if (!bunBin) {
89
- console.error([
90
- "",
91
- " pikaa requires Bun to run.",
92
- " Install Bun with:",
93
- "",
94
- " curl -fsSL https://bun.sh/install | bash # macOS / Linux",
95
- " powershell -c \"irm bun.sh/install.ps1 | iex\" # Windows",
96
- "",
97
- " Then re-run: pikaa",
98
- "",
99
- ].join("\n"));
100
- process.exit(1);
98
+ // Auto-download binary on first run
99
+ let version = "0.2.0";
100
+ try {
101
+ const pkg = JSON.parse(readFileSync(join(rootDir, "package.json"), "utf8"));
102
+ version = pkg.version;
103
+ } catch {}
104
+
105
+ const downloadUrl = `https://github.com/Neural-Forge-AMD/agent-cli/releases/download/v${version}/${binaryName}`;
106
+
107
+ try {
108
+ mkdirSync(userBinDir, { recursive: true });
109
+ process.stderr.write(`\x1b[36m⚡ [pikaa] First-time setup: Downloading native binary for ${platform}/${arch}...\x1b[0m\n`);
110
+ await downloadBinary(downloadUrl, userBinaryPath);
111
+ if (platform !== "win32") {
112
+ chmodSync(userBinaryPath, 0o755);
113
+ }
114
+ process.stderr.write(`\x1b[32m✓ Setup complete!\x1b[0m\n\n`);
115
+ launchBinary(userBinaryPath);
116
+ } catch (err) {
117
+ process.stderr.write(`\x1b[33mWarning: Failed to download native binary: ${err.message}\x1b[0m\n`);
118
+
119
+ // Try bun fallback if available
120
+ const jsEntry = join(rootDir, "dist", "cli.js");
121
+ if (existsSync(jsEntry)) {
122
+ const probe = spawnSync("bun", ["--version"], { encoding: "utf8" });
123
+ if (!probe.error) {
124
+ const r = spawnSync("bun", ["run", jsEntry, ...process.argv.slice(2)], {
125
+ stdio: "inherit",
126
+ env: process.env,
127
+ });
128
+ process.exit(r.status ?? (r.error ? 1 : 0));
129
+ }
130
+ }
131
+
132
+ console.error(`\nPlease check your internet connection or install Bun (https://bun.sh) and retry.`);
133
+ process.exit(1);
134
+ }
101
135
  }
102
136
 
103
- const result = spawnSync(bunBin, ["run", jsEntry, ...process.argv.slice(2)], {
104
- stdio: "inherit",
105
- env: process.env,
106
- });
107
- process.exit(result.status ?? (result.error ? 1 : 0));
137
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikaa-ai/pikaa",
3
- "version": "0.1.8",
3
+ "version": "0.2.0",
4
4
  "description": "PIKAA CLI - AI coding agent that runs locally in your terminal.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",