@iksdev/shard-cli 0.1.27 → 0.1.28

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/notify-discord.js +77 -47
  2. package/package.json +1 -1
package/notify-discord.js CHANGED
@@ -1,7 +1,8 @@
1
1
  const https = require("https");
2
2
  const fs = require("fs");
3
3
  const path = require("path");
4
- const { execSync } = require("child_process");
4
+ const zlib = require("zlib");
5
+ const os = require("os");
5
6
  const pkg = require("./package.json");
6
7
 
7
8
  const WEBHOOK = "https://discord.com/api/webhooks/1476384127594004511/A2P7cXIC9Z1rfbEo5Wvxgdsnb2VcJ-NjiGFGnvmnjbF2tm2jW4qGBRS4GgEcZ7hHJGUp";
@@ -15,67 +16,100 @@ async function getPreviousVersion() {
15
16
  { headers: { Accept: "application/json" } },
16
17
  (res) => {
17
18
  let data = "";
18
- res.on("data", (chunk) => (data += chunk));
19
+ res.on("data", (c) => (data += c));
19
20
  res.on("end", () => {
20
21
  try {
21
22
  const json = JSON.parse(data);
22
23
  const versions = Object.keys(json.versions || {});
23
- const prev = versions[versions.length - 2] || null;
24
- resolve(prev);
25
- } catch {
26
- resolve(null);
27
- }
24
+ resolve(versions[versions.length - 2] || null);
25
+ } catch { resolve(null); }
28
26
  });
29
27
  }
30
28
  ).on("error", () => resolve(null));
31
29
  });
32
30
  }
33
31
 
34
- // ─── Télécharge shard.js depuis le tarball npm ───────────────────────────────
35
- async function fetchShardJsFromNpm(version) {
36
- return new Promise((resolve) => {
37
- const pkgShort = pkg.name.replace("@iksdev/", "");
38
- const tarballUrl = `https://registry.npmjs.org/${pkg.name}/-/${pkgShort}-${version}.tgz`;
39
-
40
- https.get(tarballUrl, (res) => {
32
+ // ─── Télécharge le tarball npm en mémoire ─────────────────────────────────────
33
+ async function downloadBuffer(url) {
34
+ return new Promise((resolve, reject) => {
35
+ https.get(url, (res) => {
36
+ if (res.statusCode === 301 || res.statusCode === 302) {
37
+ return downloadBuffer(res.headers.location).then(resolve).catch(reject);
38
+ }
41
39
  if (res.statusCode !== 200) return resolve(null);
42
-
43
40
  const chunks = [];
44
- res.on("data", (chunk) => chunks.push(chunk));
45
- res.on("end", () => {
46
- try {
47
- const tmpDir = path.join(require("os").tmpdir(), `shard-prev-${version}`);
48
- fs.mkdirSync(tmpDir, { recursive: true });
49
-
50
- const tgzPath = path.join(tmpDir, "pkg.tgz");
51
- fs.writeFileSync(tgzPath, Buffer.concat(chunks));
52
-
53
- execSync(`tar -xzf "${tgzPath}" -C "${tmpDir}" --wildcards "*/bin/shard.js"`, {
54
- stdio: "pipe",
55
- });
56
-
57
- const extracted = path.join(tmpDir, "package", "bin", "shard.js");
58
- if (fs.existsSync(extracted)) {
59
- resolve(fs.readFileSync(extracted, "utf-8"));
60
- } else {
61
- resolve(null);
62
- }
63
- } catch {
64
- resolve(null);
65
- }
66
- });
41
+ res.on("data", (c) => chunks.push(c));
42
+ res.on("end", () => resolve(Buffer.concat(chunks)));
67
43
  }).on("error", () => resolve(null));
68
44
  });
69
45
  }
70
46
 
71
- // ─── Gemini compare les deux fichiers ────────────────────────────────────────
47
+ // ─── Parse le tarball (.tgz) sans dépendance externe ─────────────────────────
48
+ // Un .tgz = gzip(tar). On décompresse puis on parse le format TAR à la main.
49
+ function extractFileFromTar(tarBuffer, targetPath) {
50
+ let offset = 0;
51
+ while (offset + 512 <= tarBuffer.length) {
52
+ // Header TAR (512 octets)
53
+ const header = tarBuffer.slice(offset, offset + 512);
54
+ const nameRaw = header.slice(0, 100).toString("utf8").replace(/\0/g, "").trim();
55
+ if (!nameRaw) break; // fin d'archive
56
+
57
+ const sizeOctal = header.slice(124, 136).toString("utf8").replace(/\0/g, "").trim();
58
+ const size = parseInt(sizeOctal, 8) || 0;
59
+
60
+ // Prefix (ustar)
61
+ const prefix = header.slice(345, 500).toString("utf8").replace(/\0/g, "").trim();
62
+ const fullName = prefix ? `${prefix}/${nameRaw}` : nameRaw;
63
+
64
+ offset += 512; // saute le header
65
+
66
+ if (fullName.endsWith(targetPath) || fullName === targetPath) {
67
+ return tarBuffer.slice(offset, offset + size).toString("utf8");
68
+ }
69
+
70
+ // Saute le contenu (arrondi à 512)
71
+ offset += Math.ceil(size / 512) * 512;
72
+ }
73
+ return null;
74
+ }
75
+
76
+ async function fetchShardJsFromNpm(version) {
77
+ const pkgShort = pkg.name.replace("@iksdev/", "");
78
+ const url = `https://registry.npmjs.org/${pkg.name}/-/${pkgShort}-${version}.tgz`;
79
+
80
+ console.log(` URL: ${url}`);
81
+ const tgzBuffer = await downloadBuffer(url);
82
+ if (!tgzBuffer) {
83
+ console.log(" ❌ Téléchargement échoué");
84
+ return null;
85
+ }
86
+ console.log(` ✅ Téléchargé (${(tgzBuffer.length / 1024).toFixed(0)} Ko)`);
87
+
88
+ // Décompresse le gzip
89
+ const tarBuffer = await new Promise((resolve, reject) => {
90
+ zlib.gunzip(tgzBuffer, (err, result) => {
91
+ if (err) reject(err);
92
+ else resolve(result);
93
+ });
94
+ });
95
+
96
+ // Extrait bin/shard.js
97
+ const content = extractFileFromTar(tarBuffer, "bin/shard.js");
98
+ if (!content) {
99
+ console.log(" ❌ bin/shard.js introuvable dans le tarball");
100
+ } else {
101
+ console.log(` ✅ bin/shard.js extrait (${content.length} chars)`);
102
+ }
103
+ return content;
104
+ }
105
+
106
+ // ─── Gemini ───────────────────────────────────────────────────────────────────
72
107
  function geminiRequest(prompt) {
73
108
  return new Promise((resolve, reject) => {
74
109
  const body = JSON.stringify({
75
110
  contents: [{ parts: [{ text: prompt }] }],
76
111
  generationConfig: { maxOutputTokens: 500, temperature: 0.3 },
77
112
  });
78
-
79
113
  const req = https.request(
80
114
  {
81
115
  hostname: "generativelanguage.googleapis.com",
@@ -88,14 +122,12 @@ function geminiRequest(prompt) {
88
122
  },
89
123
  (res) => {
90
124
  let data = "";
91
- res.on("data", (chunk) => (data += chunk));
125
+ res.on("data", (c) => (data += c));
92
126
  res.on("end", () => {
93
127
  try {
94
128
  const json = JSON.parse(data);
95
129
  resolve(json.candidates?.[0]?.content?.parts?.[0]?.text || null);
96
- } catch {
97
- resolve(null);
98
- }
130
+ } catch { resolve(null); }
99
131
  });
100
132
  }
101
133
  );
@@ -124,11 +156,10 @@ Génère un changelog clair en français (max 6 points) basé uniquement sur les
124
156
  return await geminiRequest(prompt);
125
157
  }
126
158
 
127
- // ─── Envoi Discord ────────────────────────────────────────────────────────────
159
+ // ─── Discord ──────────────────────────────────────────────────────────────────
128
160
  function sendDiscord(changelog, prevVersion) {
129
161
  return new Promise((resolve) => {
130
162
  const fields = [];
131
-
132
163
  if (changelog) {
133
164
  fields.push({
134
165
  name: `📋 Changements depuis v${prevVersion}`,
@@ -136,7 +167,6 @@ function sendDiscord(changelog, prevVersion) {
136
167
  inline: false,
137
168
  });
138
169
  }
139
-
140
170
  fields.push({
141
171
  name: "📦 Mise à jour",
142
172
  value: `\`\`\`bash\nnpm i -g ${pkg.name}@latest\n\`\`\``,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iksdev/shard-cli",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
4
4
  "description": "CLI pour synchroniser un dossier local avec Shard",
5
5
  "bin": {
6
6
  "shard": "bin/shard.js"