@rikipurpur/puru-ai 1.3.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.
package/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # @rikipurpur/puru-ai (npm)
2
+
3
+ CLI resmi PURU-AI — **tanpa web server** secara default.
4
+ Binary Go di-download otomatis dari GitHub Releases saat install.
5
+
6
+ ```bash
7
+ npm i -g @rikipurpur/puru-ai
8
+ puru setup # wizard → tulis ~/.puru/config.json
9
+ puru gateway # jalankan bot Telegram (long-polling, tanpa /health)
10
+ puru gateway --health --port 8080 # opt-in health check (Docker/VPS)
11
+ puru chat "halo" # debug lokal tanpa Telegram
12
+ ```
13
+
14
+ Non-interaktif (CI):
15
+
16
+ ```bash
17
+ TELEGRAM_BOT_TOKEN=x PURU_BASE_URL=... PURU_API_KEY=... PURU_MODEL=puru \
18
+ puru setup --force
19
+ ```
20
+
21
+ Env installer: `PURU_AI_VERSION` (default = versi package), `PURU_AI_REPO`
22
+ (default `purujawa06-bot/PURU-AI`), `PURU_AI_BINARY` (pakai binary lokal),
23
+ `PURU_AI_SKIP_DOWNLOAD=1` (skip download).
24
+
25
+ ## Termux (Android)
26
+
27
+ HP 64-bit (umum) pakai binary `puru-linux-arm64`, HP 32-bit pakai
28
+ `puru-linux-arm` (armv7) — installer otomatis pilih yang benar.
29
+
30
+ ```bash
31
+ pkg install nodejs
32
+ npm i -g @rikipurpur/puru-ai
33
+ puru setup
34
+ puru gateway
35
+ ```
36
+
37
+ Tips: jalankan di bawah `termux-wake-lock` agar bot tidak mati saat layar
38
+ mati. Tanpa Node pun bisa — download binary langsung dari
39
+ [Releases](https://github.com/purujawa06-bot/PURU-AI/releases)
40
+ (`puru-linux-arm64` atau `puru-linux-arm`), `chmod +x`, lalu
41
+ `./puru-linux-arm64 setup`.
package/bin/puru.js ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ // Thin launcher: forward all args to the downloaded Go binary.
4
+ const { spawnSync } = require('child_process');
5
+ const fs = require('fs');
6
+ const { binaryPath } = require('../scripts/binary');
7
+
8
+ const bin = binaryPath();
9
+ if (!fs.existsSync(bin)) {
10
+ console.error(`[puru-ai] binary tidak ditemukan: ${bin}`);
11
+ console.error('[puru-ai] Jalankan `npm rebuild -g @rikipurpur/puru-ai` atau reinstall.');
12
+ console.error('[puru-ai] Alternatif: set PURU_AI_BINARY=/path/ke/puru');
13
+ process.exit(1);
14
+ }
15
+ const res = spawnSync(bin, process.argv.slice(2), { stdio: 'inherit' });
16
+ process.exit(res.status == null ? 1 : res.status);
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@rikipurpur/puru-ai",
3
+ "version": "1.3.0",
4
+ "description": "PURU-AI CLI — setup & gateway Telegram bot tanpa web server. Binary Go dibungkus npm.",
5
+ "license": "MIT",
6
+ "author": "Ricky",
7
+ "homepage": "https://github.com/purujawa06-bot/PURU-AI",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/purujawa06-bot/PURU-AI.git"
11
+ },
12
+ "keywords": [
13
+ "telegram",
14
+ "ai",
15
+ "bot",
16
+ "cli",
17
+ "gateway"
18
+ ],
19
+ "engines": {
20
+ "node": ">=18"
21
+ },
22
+ "bin": {
23
+ "puru": "bin/puru.js"
24
+ },
25
+ "scripts": {
26
+ "postinstall": "node scripts/install.js"
27
+ },
28
+ "files": [
29
+ "bin/",
30
+ "scripts/install.js",
31
+ "scripts/binary.js",
32
+ "README.md"
33
+ ]
34
+ }
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+ // Shared helper: resolve platform/arch + vendor binary path.
3
+ const path = require('path');
4
+ const os = require('os');
5
+
6
+ function mapOS(platform = process.platform) {
7
+ if (platform === 'win32') return 'windows';
8
+ if (platform === 'darwin') return 'darwin';
9
+ // Termux di Android lapor 'linux' — binary linux statik (CGO_ENABLED=0) jalan langsung.
10
+ if (platform === 'linux' || platform === 'android') return 'linux';
11
+ throw new Error(`OS tidak didukung: ${platform} (didukung: linux, darwin, windows)`);
12
+ }
13
+
14
+ function mapArch(arch = process.arch) {
15
+ if (arch === 'x64') return 'amd64';
16
+ if (arch === 'arm64') return 'arm64';
17
+ // HP Android 32-bit (armv7) — Termux lapor 'arm'.
18
+ if (arch === 'arm') return 'arm';
19
+ throw new Error(`Arch tidak didukung: ${arch} (didukung: x64, arm64, arm)`);
20
+ }
21
+
22
+ function assetName(goos, goarch) {
23
+ const base = `puru-${goos}-${goarch}`;
24
+ return goos === 'windows' ? `${base}.exe` : base;
25
+ }
26
+
27
+ function binaryPath() {
28
+ if (process.env.PURU_AI_BINARY) return process.env.PURU_AI_BINARY;
29
+ const goos = mapOS();
30
+ const goarch = mapArch();
31
+ const bin = assetName(goos, goarch);
32
+ // Vendor dir lives next to this file: scripts/vendor/<bin>
33
+ return path.join(__dirname, 'vendor', bin);
34
+ }
35
+
36
+ function downloadURL({ repo, tag, goos, goarch }) {
37
+ return `https://github.com/${repo}/releases/download/${tag}/${assetName(goos, goarch)}`;
38
+ }
39
+
40
+ function cacheDir() {
41
+ return process.env.PURU_AI_CACHE || path.join(os.homedir(), '.puru', 'bin');
42
+ }
43
+
44
+ module.exports = { mapOS, mapArch, assetName, binaryPath, downloadURL, cacheDir };
@@ -0,0 +1,81 @@
1
+ 'use strict';
2
+ // postinstall: download prebuilt `puru` Go binary from GitHub Releases.
3
+ // Env override:
4
+ // PURU_AI_VERSION=v1.2.3 | 1.2.3 (default: version di package.json)
5
+ // PURU_AI_REPO=owner/repo (default: purujawa06-bot/PURU-AI)
6
+ // PURU_AI_SKIP_DOWNLOAD=1 (skip, untuk CI/offline)
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+ const https = require('https');
10
+ const { mapOS, mapArch, assetName, binaryPath, downloadURL } = require('./binary');
11
+
12
+ function pkgVersion() {
13
+ const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
14
+ return pkg.version;
15
+ }
16
+
17
+ function resolveTag() {
18
+ const v = (process.env.PURU_AI_VERSION || pkgVersion()).trim();
19
+ return v.startsWith('v') ? v : `v${v}`;
20
+ }
21
+
22
+ function fetch(url, dest, redirects = 5) {
23
+ return new Promise((resolve, reject) => {
24
+ https.get(url, { headers: { 'User-Agent': 'puru-ai-npm-install' } }, (res) => {
25
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
26
+ if (redirects === 0) return reject(new Error('Terlalu banyak redirect'));
27
+ res.resume();
28
+ const next = res.headers.location.startsWith('http')
29
+ ? res.headers.location
30
+ : new URL(res.headers.location, url).toString();
31
+ return fetch(next, dest, redirects - 1).then(resolve, reject);
32
+ }
33
+ if (res.statusCode !== 200) {
34
+ res.resume();
35
+ return reject(new Error(`Download gagal HTTP ${res.statusCode}: ${url}`));
36
+ }
37
+ const out = fs.createWriteStream(dest, { mode: 0o755 });
38
+ res.pipe(out);
39
+ out.on('finish', () => out.close(() => resolve()));
40
+ out.on('error', reject);
41
+ }).on('error', reject);
42
+ });
43
+ }
44
+
45
+ async function main() {
46
+ if (process.env.PURU_AI_SKIP_DOWNLOAD === '1') {
47
+ console.log('[puru-ai] skip download (PURU_AI_SKIP_DOWNLOAD=1)');
48
+ return;
49
+ }
50
+ const repo = process.env.PURU_AI_REPO || 'purujawa06-bot/PURU-AI';
51
+ const tag = resolveTag();
52
+ const goos = mapOS();
53
+ const goarch = mapArch();
54
+ const url = downloadURL({ repo, tag, goos, goarch });
55
+ const dest = binaryPath();
56
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
57
+ console.log(`[puru-ai] download ${assetName(goos, goarch)} ${tag} dari ${repo}...`);
58
+ try {
59
+ await fetch(url, dest);
60
+ } catch (err) {
61
+ try { fs.unlinkSync(dest); } catch (_) {}
62
+ console.error(`[puru-ai] GAGAL: ${err.message}`);
63
+ console.error(`[puru-ai] Cek release ada di https://github.com/${repo}/releases/tag/${tag}`);
64
+ console.error(`[puru-ai] Atau set PURU_AI_BINARY=/path/ke/puru lalu install ulang.`);
65
+ throw err;
66
+ }
67
+ if (goos !== 'windows') {
68
+ try { fs.chmodSync(dest, 0o755); } catch (_) {}
69
+ }
70
+ console.log(`[puru-ai] OK: ${dest}`);
71
+ console.log('[puru-ai] Lanjut: puru setup → puru gateway');
72
+ }
73
+
74
+ if (require.main === module) {
75
+ main().catch((e) => {
76
+ console.error(e.message || e);
77
+ process.exit(1);
78
+ });
79
+ }
80
+
81
+ module.exports = { resolveTag, fetch };