alurkerja-cli 1.0.21 → 1.0.22
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/index.js +1 -1
- package/package.json +1 -1
- package/index.js.backup +0 -288
- package/package.json.backup +0 -31
package/index.js
CHANGED
|
@@ -14,7 +14,7 @@ const { execSync, spawn } = require('child_process');
|
|
|
14
14
|
const os = require('os');
|
|
15
15
|
|
|
16
16
|
const GITLAB_BASE = 'https://gitlab.javan.co.id/alurkerja/on-premises/toolkits/alurkerja-cli';
|
|
17
|
-
const GITLAB_TOKEN = 'javan-
|
|
17
|
+
const GITLAB_TOKEN = 'javan-Lv77immsAVHiT3RnqrKa'; // GitLab private token
|
|
18
18
|
const VERSION = 'v1.0.0'; // Will be replaced during build
|
|
19
19
|
const INSTALL_DIR = path.join(os.homedir(), '.alurkerja', 'bin');
|
|
20
20
|
const BINARY_NAME = os.platform() === 'win32' ? 'alurkerja.exe' : 'alurkerja';
|
package/package.json
CHANGED
package/index.js.backup
DELETED
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Alurkerja CLI - npx Wrapper
|
|
5
|
-
*
|
|
6
|
-
* This is a bootstrapper that downloads and executes the Go binary.
|
|
7
|
-
* As per PRD: npx wrapper should NOT contain business logic.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
const fs = require('fs');
|
|
11
|
-
const path = require('path');
|
|
12
|
-
const https = require('https');
|
|
13
|
-
const { execSync, spawn } = require('child_process');
|
|
14
|
-
const os = require('os');
|
|
15
|
-
|
|
16
|
-
const GITLAB_BASE = 'https://gitlab.javan.co.id/alurkerja/on-premises/toolkits/alurkerja-cli';
|
|
17
|
-
const GITLAB_TOKEN = 'javan-_P_JrtswtvrZekJDk1Lt'; // GitLab private token
|
|
18
|
-
const VERSION = 'v1.0.0'; // Will be replaced during build
|
|
19
|
-
const INSTALL_DIR = path.join(os.homedir(), '.alurkerja', 'bin');
|
|
20
|
-
const BINARY_NAME = os.platform() === 'win32' ? 'alurkerja.exe' : 'alurkerja';
|
|
21
|
-
const BINARY_PATH = path.join(INSTALL_DIR, BINARY_NAME);
|
|
22
|
-
const CACHE_DURATION_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Detect current platform
|
|
26
|
-
*/
|
|
27
|
-
function detectPlatform() {
|
|
28
|
-
const platform = os.platform();
|
|
29
|
-
const arch = os.arch();
|
|
30
|
-
|
|
31
|
-
let osName;
|
|
32
|
-
switch (platform) {
|
|
33
|
-
case 'linux': osName = 'linux'; break;
|
|
34
|
-
case 'darwin': osName = 'darwin'; break;
|
|
35
|
-
case 'win32': osName = 'windows'; break;
|
|
36
|
-
default: throw new Error(`Unsupported platform: ${platform}`);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
let archName;
|
|
40
|
-
switch (arch) {
|
|
41
|
-
case 'x64': archName = 'amd64'; break;
|
|
42
|
-
case 'arm64': archName = 'arm64'; break;
|
|
43
|
-
default: throw new Error(`Unsupported architecture: ${arch}`);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return { os: osName, arch: archName };
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Get the version to download
|
|
51
|
-
*/
|
|
52
|
-
function getVersion() {
|
|
53
|
-
return VERSION;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Download binary from GitLab releases
|
|
58
|
-
*/
|
|
59
|
-
async function downloadBinary(version, platform) {
|
|
60
|
-
const binaryName = `alurkerja-${platform.os}-${platform.arch}${platform.os === 'windows' ? '.exe' : ''}`;
|
|
61
|
-
|
|
62
|
-
// Use GitLab API v4 to get raw file with PRIVATE-TOKEN authentication
|
|
63
|
-
const projectPath = encodeURIComponent('alurkerja/on-premises/toolkits/alurkerja-cli');
|
|
64
|
-
const filePath = encodeURIComponent(`dist/${binaryName}`);
|
|
65
|
-
const downloadUrl = `https://gitlab.javan.co.id/api/v4/projects/${projectPath}/repository/files/${filePath}/raw?ref=master`;
|
|
66
|
-
|
|
67
|
-
console.log(`📥 Downloading Alurkerja CLI ${version} for ${platform.os}-${platform.arch}...`);
|
|
68
|
-
|
|
69
|
-
// Ensure install directory exists
|
|
70
|
-
fs.mkdirSync(INSTALL_DIR, { recursive: true });
|
|
71
|
-
|
|
72
|
-
// Use temporary file to avoid ETXTBSY error
|
|
73
|
-
const tempPath = `${BINARY_PATH}.tmp`;
|
|
74
|
-
|
|
75
|
-
return new Promise((resolve, reject) => {
|
|
76
|
-
const file = fs.createWriteStream(tempPath);
|
|
77
|
-
let downloadComplete = false;
|
|
78
|
-
|
|
79
|
-
const downloadFile = (targetUrl) => {
|
|
80
|
-
const url = new URL(targetUrl);
|
|
81
|
-
const options = {
|
|
82
|
-
hostname: url.hostname,
|
|
83
|
-
path: url.pathname + url.search,
|
|
84
|
-
headers: {
|
|
85
|
-
'PRIVATE-TOKEN': GITLAB_TOKEN
|
|
86
|
-
},
|
|
87
|
-
followRedirect: true
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const req = https.get(options, (res) => {
|
|
91
|
-
if (res.statusCode === 302 || res.statusCode === 301) {
|
|
92
|
-
// Follow redirect with PRIVATE-TOKEN header
|
|
93
|
-
const redirectUrl = res.headers.location.startsWith('http')
|
|
94
|
-
? res.headers.location
|
|
95
|
-
: `https://${url.hostname}${res.headers.location}`;
|
|
96
|
-
|
|
97
|
-
return downloadFile(redirectUrl);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (res.statusCode !== 200) {
|
|
101
|
-
file.close();
|
|
102
|
-
try { fs.unlinkSync(tempPath); } catch {}
|
|
103
|
-
reject(new Error(`Download failed with status ${res.statusCode}`));
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
res.pipe(file);
|
|
108
|
-
res.on('end', () => {
|
|
109
|
-
downloadComplete = true;
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
req.on('error', (err) => {
|
|
114
|
-
if (!downloadComplete) {
|
|
115
|
-
file.close();
|
|
116
|
-
try { fs.unlinkSync(tempPath); } catch {}
|
|
117
|
-
reject(err);
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
req.setTimeout(30000, () => {
|
|
122
|
-
if (!downloadComplete) {
|
|
123
|
-
req.abort();
|
|
124
|
-
file.close();
|
|
125
|
-
try { fs.unlinkSync(tempPath); } catch {}
|
|
126
|
-
reject(new Error('Download timeout'));
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
downloadFile(downloadUrl);
|
|
132
|
-
|
|
133
|
-
file.on('error', (err) => {
|
|
134
|
-
try { fs.unlinkSync(tempPath); } catch {}
|
|
135
|
-
reject(err);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
file.on('finish', () => {
|
|
139
|
-
file.close((err) => {
|
|
140
|
-
if (err) {
|
|
141
|
-
try { fs.unlinkSync(tempPath); } catch {}
|
|
142
|
-
reject(err);
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Validate the downloaded file
|
|
147
|
-
const stats = fs.statSync(tempPath);
|
|
148
|
-
if (stats.size < 1000) {
|
|
149
|
-
try { fs.unlinkSync(tempPath); } catch {}
|
|
150
|
-
reject(new Error(`Download failed: received invalid file (${stats.size} bytes)`));
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Make executable on Unix systems
|
|
155
|
-
if (platform.os !== 'windows') {
|
|
156
|
-
try {
|
|
157
|
-
fs.chmodSync(tempPath, '755');
|
|
158
|
-
} catch (err) {
|
|
159
|
-
try { fs.unlinkSync(tempPath); } catch {}
|
|
160
|
-
reject(new Error(`Failed to make binary executable: ${err.message}`));
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Rename temp file to final path
|
|
166
|
-
try {
|
|
167
|
-
if (fs.existsSync(BINARY_PATH)) {
|
|
168
|
-
fs.unlinkSync(BINARY_PATH);
|
|
169
|
-
}
|
|
170
|
-
fs.renameSync(tempPath, BINARY_PATH);
|
|
171
|
-
resolve();
|
|
172
|
-
} catch (err) {
|
|
173
|
-
try { fs.unlinkSync(tempPath); } catch {}
|
|
174
|
-
reject(new Error(`Failed to install binary: ${err.message}`));
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Check if binary exists and is executable
|
|
183
|
-
*/
|
|
184
|
-
function binaryExists() {
|
|
185
|
-
try {
|
|
186
|
-
fs.accessSync(BINARY_PATH, fs.constants.F_OK | fs.constants.X_OK);
|
|
187
|
-
return true;
|
|
188
|
-
} catch {
|
|
189
|
-
return false;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Get version of installed binary
|
|
195
|
-
*/
|
|
196
|
-
function getInstalledVersion() {
|
|
197
|
-
try {
|
|
198
|
-
const output = execSync(`"${BINARY_PATH}" --version`, { encoding: 'utf8', timeout: 5000 });
|
|
199
|
-
const match = output.match(/v?(\d+\.\d+\.\d+)/);
|
|
200
|
-
return match ? match[1] : null;
|
|
201
|
-
} catch {
|
|
202
|
-
return null;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Check if binary file is older than cache duration
|
|
208
|
-
*/
|
|
209
|
-
function isBinaryStale() {
|
|
210
|
-
try {
|
|
211
|
-
const stats = fs.statSync(BINARY_PATH);
|
|
212
|
-
const ageMs = Date.now() - stats.mtimeMs;
|
|
213
|
-
return ageMs > CACHE_DURATION_MS;
|
|
214
|
-
} catch {
|
|
215
|
-
return true; // If can't read stats, consider it stale
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Check if force download flag is present
|
|
221
|
-
*/
|
|
222
|
-
function hasForceDownloadFlag() {
|
|
223
|
-
return process.argv.includes('--force-download');
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Execute the Go binary with provided arguments
|
|
228
|
-
*/
|
|
229
|
-
function executeBinary(args) {
|
|
230
|
-
const child = spawn(BINARY_PATH, args, {
|
|
231
|
-
stdio: 'inherit',
|
|
232
|
-
shell: false
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
child.on('error', (err) => {
|
|
236
|
-
console.error(`❌ Failed to execute binary: ${err.message}`);
|
|
237
|
-
process.exit(1);
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
child.on('exit', (code) => {
|
|
241
|
-
process.exit(code || 0);
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Main bootstrap logic
|
|
247
|
-
*/
|
|
248
|
-
async function bootstrap() {
|
|
249
|
-
try {
|
|
250
|
-
const platform = detectPlatform();
|
|
251
|
-
const version = getVersion();
|
|
252
|
-
const installedVersion = getInstalledVersion();
|
|
253
|
-
const forceDownload = hasForceDownloadFlag();
|
|
254
|
-
|
|
255
|
-
// Check if we need to download the binary
|
|
256
|
-
const needsDownload = forceDownload ||
|
|
257
|
-
!binaryExists() ||
|
|
258
|
-
(installedVersion !== version && version !== 'dev') ||
|
|
259
|
-
isBinaryStale();
|
|
260
|
-
|
|
261
|
-
if (needsDownload) {
|
|
262
|
-
if (forceDownload) {
|
|
263
|
-
console.log('🔄 Force download requested...');
|
|
264
|
-
}
|
|
265
|
-
await downloadBinary(version, platform);
|
|
266
|
-
console.log(`✅ Alurkerja CLI ${version} ready!`);
|
|
267
|
-
// Small delay to ensure file system sync after download
|
|
268
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Execute the binary with all arguments passed to this script
|
|
272
|
-
// Filter out --force-download flag before passing to binary
|
|
273
|
-
const args = process.argv.slice(2).filter(arg => arg !== '--force-download');
|
|
274
|
-
executeBinary(args);
|
|
275
|
-
|
|
276
|
-
} catch (error) {
|
|
277
|
-
console.error(`❌ Bootstrap failed: ${error.message}`);
|
|
278
|
-
console.log('💡 Try installing directly: curl -fsSL https://alurkerja.com/install.sh | bash');
|
|
279
|
-
process.exit(1);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// Handle termination signals
|
|
284
|
-
process.on('SIGINT', () => process.exit(0));
|
|
285
|
-
process.on('SIGTERM', () => process.exit(0));
|
|
286
|
-
|
|
287
|
-
// Start bootstrap
|
|
288
|
-
bootstrap();
|
package/package.json.backup
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "alurkerja-cli",
|
|
3
|
-
"version": "1.0.20",
|
|
4
|
-
"description": "Alurkerja CLI - npx wrapper for Go binary",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"private": false,
|
|
7
|
-
"bin": {
|
|
8
|
-
"alurkerja": "./index.js"
|
|
9
|
-
},
|
|
10
|
-
"keywords": [
|
|
11
|
-
"alurkerja",
|
|
12
|
-
"cli",
|
|
13
|
-
"addon",
|
|
14
|
-
"ci",
|
|
15
|
-
"cd"
|
|
16
|
-
],
|
|
17
|
-
"author": "Alurkerja Team",
|
|
18
|
-
"license": "MIT",
|
|
19
|
-
"engines": {
|
|
20
|
-
"node": ">=14.0.0"
|
|
21
|
-
},
|
|
22
|
-
"repository": {
|
|
23
|
-
"type": "git",
|
|
24
|
-
"url": "https://github.com/alurkerja/alurkerja-cli"
|
|
25
|
-
},
|
|
26
|
-
"homepage": "https://alurkerja.com",
|
|
27
|
-
"publishConfig": {
|
|
28
|
-
"access": "public"
|
|
29
|
-
},
|
|
30
|
-
"dependencies": {}
|
|
31
|
-
}
|