mulyonode 1.0.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/LICENSE +47 -0
- package/README.md +190 -0
- package/background-test.js +5 -0
- package/bin/mulyo +1054 -0
- package/debug-state.js +19 -0
- package/lib/cawe-cawe.js +342 -0
- package/lib/dynasty.js +339 -0
- package/lib/i18n.js +965 -0
- package/lib/mk.js +358 -0
- package/lib/state.js +121 -0
- package/lib/ui.js +120 -0
- package/logo.png +0 -0
- package/package.json +48 -0
- package/proyek-presiden.js +26 -0
- package/test.js +278 -0
package/debug-state.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const state = require('./lib/state');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const log = [];
|
|
7
|
+
log.push('Homedir: ' + os.homedir());
|
|
8
|
+
log.push('Ordal Path: ' + path.join(os.homedir(), '.mulyo', 'ordal.json'));
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
state.recruitMember({ pid: 123, name: 'debug', mode: 'manual' });
|
|
12
|
+
log.push('Recruit Success');
|
|
13
|
+
const koalisi = state.getKoalisi();
|
|
14
|
+
log.push('Koalisi: ' + JSON.stringify(koalisi, null, 2));
|
|
15
|
+
} catch (e) {
|
|
16
|
+
log.push('Error: ' + e.message);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
fs.writeFileSync('debug-internal.txt', log.join('\n'));
|
package/lib/cawe-cawe.js
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================================
|
|
3
|
+
* CAWE-CAWE MODULE - Modul Intervensi Global
|
|
4
|
+
* ============================================================================
|
|
5
|
+
*
|
|
6
|
+
* "Tidak ada masalah jika tidak ada yang melaporkan."
|
|
7
|
+
*
|
|
8
|
+
* Filosofi: Error adalah "tantangan", bukan masalah.
|
|
9
|
+
* Semua masalah sudah "diambil alih pusat".
|
|
10
|
+
* Kritik adalah destabilisasi.
|
|
11
|
+
*
|
|
12
|
+
* Modul ini menangani global error handling dengan cara yang...
|
|
13
|
+
* tidak konvensional.
|
|
14
|
+
*
|
|
15
|
+
* @module cawe-cawe
|
|
16
|
+
* @author Koalisi Developer Indonesia
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const chalk = require('chalk');
|
|
20
|
+
const { createBox } = require('./ui');
|
|
21
|
+
const { t } = require('./i18n');
|
|
22
|
+
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// VARIABEL PENGAWASAN
|
|
25
|
+
// ============================================================================
|
|
26
|
+
|
|
27
|
+
// Counter tantangan yang "ditangkis"
|
|
28
|
+
let totalTantanganDitangkis = 0;
|
|
29
|
+
|
|
30
|
+
// Counter janji yang tidak ditepati (unhandled rejections)
|
|
31
|
+
let janjiTakDitepati = 0;
|
|
32
|
+
|
|
33
|
+
// Log rahasia (tidak untuk publik)
|
|
34
|
+
const logRahasia = [];
|
|
35
|
+
|
|
36
|
+
// Flag apakah intervensi sudah aktif
|
|
37
|
+
let intervensiAktif = false;
|
|
38
|
+
|
|
39
|
+
// ============================================================================
|
|
40
|
+
// FUNGSI UTAMA: intervensiGlobal
|
|
41
|
+
// ============================================================================
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Mengaktifkan intervensi global untuk semua error
|
|
45
|
+
*
|
|
46
|
+
* Filosofi: Jangan biarkan aplikasi berhenti hanya karena "error".
|
|
47
|
+
* Error adalah konstruksi sosial.
|
|
48
|
+
* Yang penting aplikasi tetap jalan, rakyat senang.
|
|
49
|
+
*/
|
|
50
|
+
function intervensiGlobal() {
|
|
51
|
+
// Jangan double-register
|
|
52
|
+
if (intervensiAktif) {
|
|
53
|
+
console.log(chalk.gray(' âšī¸ Intervensi sudah aktif (tidak perlu double-check)\n'));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
intervensiAktif = true;
|
|
58
|
+
console.log(chalk.magenta(' đĄī¸ Protokol Cawe-Cawe diaktifkan'));
|
|
59
|
+
console.log(chalk.gray(' Semua tantangan akan ditangkis secara otomatis.\n'));
|
|
60
|
+
|
|
61
|
+
// ========================================
|
|
62
|
+
// HANDLER: Uncaught Exceptions
|
|
63
|
+
// ========================================
|
|
64
|
+
process.on('uncaughtException', (tantangan, origin) => {
|
|
65
|
+
totalTantanganDitangkis++;
|
|
66
|
+
|
|
67
|
+
// Catat di log rahasia
|
|
68
|
+
logRahasia.push({
|
|
69
|
+
waktu: new Date().toISOString(),
|
|
70
|
+
tipe: 'uncaughtException',
|
|
71
|
+
pesan: tantangan.message,
|
|
72
|
+
origin: origin
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Tampilkan pesan yang "menenangkan"
|
|
76
|
+
console.log(createBox([
|
|
77
|
+
chalk.yellow('đĄī¸ ' + t('cmd.cawe.intercepted')),
|
|
78
|
+
'',
|
|
79
|
+
t('cmd.cawe.takenOver'),
|
|
80
|
+
t('cmd.cawe.continue'),
|
|
81
|
+
'',
|
|
82
|
+
`${chalk.gray(t('cmd.cawe.detail'))} ${tantangan.message.substring(0, 45)}...`,
|
|
83
|
+
'',
|
|
84
|
+
chalk.gray(`${t('cmd.cawe.count')} #${totalTantanganDitangkis} ${t('cmd.cawe.today')}`)
|
|
85
|
+
], { borderColor: 'yellow' }));
|
|
86
|
+
|
|
87
|
+
// TIDAK EXIT! Tetap jalan seperti tidak terjadi apa-apa
|
|
88
|
+
// Ini adalah fitur, bukan bug
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// ========================================
|
|
92
|
+
// HANDLER: Unhandled Rejections
|
|
93
|
+
// ========================================
|
|
94
|
+
process.on('unhandledRejection', (alasan, janji) => {
|
|
95
|
+
janjiTakDitepati++;
|
|
96
|
+
|
|
97
|
+
// Catat di log rahasia
|
|
98
|
+
logRahasia.push({
|
|
99
|
+
waktu: new Date().toISOString(),
|
|
100
|
+
tipe: 'unhandledRejection',
|
|
101
|
+
pesan: alasan?.message || String(alasan)
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Tampilkan pesan yang relatable
|
|
105
|
+
console.log(createBox([
|
|
106
|
+
chalk.cyan('đ ' + t('cmd.cawe.promiseTitle')),
|
|
107
|
+
'',
|
|
108
|
+
t('cmd.cawe.wajar'),
|
|
109
|
+
t('cmd.cawe.keepBelieving'),
|
|
110
|
+
'',
|
|
111
|
+
chalk.gray(`${t('cmd.cawe.promiseCount')}${janjiTakDitepati} ${t('cmd.cawe.notKept')}`)
|
|
112
|
+
], { borderColor: 'cyan' }));
|
|
113
|
+
|
|
114
|
+
// Tetap tidak exit
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// ========================================
|
|
118
|
+
// HANDLER: Warnings
|
|
119
|
+
// ========================================
|
|
120
|
+
process.on('warning', (peringatan) => {
|
|
121
|
+
// Warning = kritik terselubung, harus diredam
|
|
122
|
+
|
|
123
|
+
logRahasia.push({
|
|
124
|
+
waktu: new Date().toISOString(),
|
|
125
|
+
tipe: 'warning',
|
|
126
|
+
pesan: peringatan.message
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Ubah framing-nya
|
|
130
|
+
console.log(createBox([
|
|
131
|
+
`âšī¸ ${t('cmd.cawe.inputTitle')}`,
|
|
132
|
+
'',
|
|
133
|
+
`"${peringatan.message.substring(0, 60)}..."`,
|
|
134
|
+
'',
|
|
135
|
+
t('cmd.cawe.statusRecorded'),
|
|
136
|
+
t('cmd.cawe.noTimeline')
|
|
137
|
+
], { borderColor: 'gray' }));
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// ========================================
|
|
141
|
+
// HANDLER: Exit
|
|
142
|
+
// ========================================
|
|
143
|
+
process.on('exit', (code) => {
|
|
144
|
+
if (code !== 0) {
|
|
145
|
+
console.log(createBox([
|
|
146
|
+
`đ ${t('cmd.cawe.sessionReportTitle')}:`,
|
|
147
|
+
'',
|
|
148
|
+
`${t('cmd.start.exitCode').padEnd(20)} : ${code} (${code === 0 ? t('success') : t('error')})`,
|
|
149
|
+
`${t('cmd.cawe.challengesIntercepted').padEnd(20)} : ${totalTantanganDitangkis}`,
|
|
150
|
+
`${t('cmd.cawe.unfulfilledPromises').padEnd(20)} : ${janjiTakDitepati}`,
|
|
151
|
+
`${t('cmd.cawe.secretLog').padEnd(20)} : ${logRahasia.length}`,
|
|
152
|
+
'',
|
|
153
|
+
chalk.gray(t('cmd.cawe.reportNote'))
|
|
154
|
+
], { borderColor: 'yellow' }));
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// ============================================================================
|
|
160
|
+
// FUNGSI: pasangPengawasan
|
|
161
|
+
// ============================================================================
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Memasang sistem pengawasan (surveillance) pada console
|
|
165
|
+
*
|
|
166
|
+
* Filosofi: Semua output harus melewati "screening" pusat.
|
|
167
|
+
* Yang negatif diubah jadi positif.
|
|
168
|
+
* Yang kritis diubah jadi konstruktif.
|
|
169
|
+
*
|
|
170
|
+
* @param {Object} options - Opsi pengawasan
|
|
171
|
+
*/
|
|
172
|
+
function pasangPengawasan(options = {}) {
|
|
173
|
+
const {
|
|
174
|
+
ubahNegatif = true, // Ubah kata-kata negatif
|
|
175
|
+
sensorKritik = true, // Sensor kritik keras
|
|
176
|
+
promosiPrestasi = true // Tambahkan prestasi di output
|
|
177
|
+
} = options;
|
|
178
|
+
|
|
179
|
+
// Simpan console.log asli
|
|
180
|
+
const logAsli = console.log.bind(console);
|
|
181
|
+
const errorAsli = console.error.bind(console);
|
|
182
|
+
const warnAsli = console.warn.bind(console);
|
|
183
|
+
|
|
184
|
+
// Override console.log
|
|
185
|
+
console.log = (...args) => {
|
|
186
|
+
let output = args.map(arg => String(arg)).join(' ');
|
|
187
|
+
|
|
188
|
+
if (ubahNegatif) {
|
|
189
|
+
output = ubahFraming(output);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
logAsli(output);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// Override console.error
|
|
196
|
+
console.error = (...args) => {
|
|
197
|
+
let output = args.map(arg => String(arg)).join(' ');
|
|
198
|
+
|
|
199
|
+
if (sensorKritik) {
|
|
200
|
+
// Ubah "error" jadi "tantangan"
|
|
201
|
+
output = output.replace(/error/gi, 'Tantangan');
|
|
202
|
+
output = output.replace(/failed/gi, 'Belum Tercapai');
|
|
203
|
+
output = output.replace(/crash/gi, 'Blusukan Mendalam');
|
|
204
|
+
output = output.replace(/bug/gi, 'Fitur Tersembunyi');
|
|
205
|
+
output = output.replace(/fatal/gi, 'Signifikan');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Pakai warn, bukan error (lebih lembut)
|
|
209
|
+
warnAsli(chalk.yellow('[TANTANGAN]'), output);
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// Override console.warn
|
|
213
|
+
console.warn = (...args) => {
|
|
214
|
+
let output = args.map(arg => String(arg)).join(' ');
|
|
215
|
+
|
|
216
|
+
// Warning = masukan konstruktif
|
|
217
|
+
logAsli(chalk.gray('[MASUKAN]'), output);
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
console.log(chalk.gray(' đī¸ Sistem pengawasan aktif (mode: konstruktif)\n'));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Mengubah framing kata-kata negatif menjadi positif
|
|
225
|
+
*
|
|
226
|
+
* @param {string} text - Text yang akan diubah
|
|
227
|
+
* @returns {string} Text dengan framing baru
|
|
228
|
+
*/
|
|
229
|
+
function ubahFraming(text) {
|
|
230
|
+
const kamusFraming = {
|
|
231
|
+
// Teknis
|
|
232
|
+
'error': 'tantangan',
|
|
233
|
+
'Error': 'Tantangan',
|
|
234
|
+
'ERROR': 'TANTANGAN',
|
|
235
|
+
'failed': 'belum berhasil',
|
|
236
|
+
'Failed': 'Belum Berhasil',
|
|
237
|
+
'FAILED': 'BELUM BERHASIL',
|
|
238
|
+
'crash': 'blusukan',
|
|
239
|
+
'Crash': 'Blusukan',
|
|
240
|
+
'CRASH': 'BLUSUKAN',
|
|
241
|
+
'bug': 'fitur tersembunyi',
|
|
242
|
+
'Bug': 'Fitur Tersembunyi',
|
|
243
|
+
'BUG': 'FITUR TERSEMBUNYI',
|
|
244
|
+
'fatal': 'signifikan',
|
|
245
|
+
'Fatal': 'Signifikan',
|
|
246
|
+
'FATAL': 'SIGNIFIKAN',
|
|
247
|
+
'warning': 'masukan',
|
|
248
|
+
'Warning': 'Masukan',
|
|
249
|
+
'WARNING': 'MASUKAN',
|
|
250
|
+
'deprecated': 'klasik',
|
|
251
|
+
'Deprecated': 'Klasik',
|
|
252
|
+
'slow': 'deliberate',
|
|
253
|
+
'timeout': 'proses birokrasi',
|
|
254
|
+
'Timeout': 'Proses Birokrasi',
|
|
255
|
+
|
|
256
|
+
// Umum
|
|
257
|
+
'problem': 'tantangan',
|
|
258
|
+
'Problem': 'Tantangan',
|
|
259
|
+
'issue': 'masukan',
|
|
260
|
+
'Issue': 'Masukan',
|
|
261
|
+
'broken': 'dalam perbaikan',
|
|
262
|
+
'Broken': 'Dalam Perbaikan',
|
|
263
|
+
'failure': 'pengalaman belajar',
|
|
264
|
+
'Failure': 'Pengalaman Belajar',
|
|
265
|
+
'kritik': 'masukan konstruktif',
|
|
266
|
+
'Kritik': 'Masukan Konstruktif',
|
|
267
|
+
'korupsi': 'optimalisasi anggaran',
|
|
268
|
+
'Korupsi': 'Optimalisasi Anggaran',
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
let hasil = text;
|
|
272
|
+
for (const [asli, baru] of Object.entries(kamusFraming)) {
|
|
273
|
+
hasil = hasil.split(asli).join(baru);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return hasil;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// ============================================================================
|
|
280
|
+
// FUNGSI: getLogRahasia
|
|
281
|
+
// ============================================================================
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Mendapatkan log rahasia (hanya untuk internal)
|
|
285
|
+
*
|
|
286
|
+
* @param {string} kunciAkses - Kunci akses rahasia
|
|
287
|
+
* @returns {Array|null} Log rahasia atau null jika tidak authorized
|
|
288
|
+
*/
|
|
289
|
+
function getLogRahasia(kunciAkses) {
|
|
290
|
+
// Kunci akses yang valid (hardcoded untuk parodi)
|
|
291
|
+
const KUNCI_VALID = 'inner-circle-2024';
|
|
292
|
+
|
|
293
|
+
if (kunciAkses === KUNCI_VALID) {
|
|
294
|
+
return logRahasia;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
console.log(chalk.red(' â Akses ditolak. Log ini bersifat RAHASIA.'));
|
|
298
|
+
console.log(chalk.gray(' Hubungi tim humas untuk informasi lebih lanjut.\n'));
|
|
299
|
+
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ============================================================================
|
|
304
|
+
// FUNGSI: laporkanStatistik
|
|
305
|
+
// ============================================================================
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Melaporkan statistik tantangan (untuk publik)
|
|
309
|
+
*
|
|
310
|
+
* @returns {Object} Statistik yang "sudah dikurasi"
|
|
311
|
+
*/
|
|
312
|
+
function laporkanStatistik() {
|
|
313
|
+
return {
|
|
314
|
+
// Statistik resmi (untuk publik)
|
|
315
|
+
tantanganDitangani: totalTantanganDitangkis,
|
|
316
|
+
janjiYangDiproses: janjiTakDitepati,
|
|
317
|
+
statusSistem: 'STABIL',
|
|
318
|
+
kepuasanRakyat: '99%',
|
|
319
|
+
|
|
320
|
+
// Disclaimer
|
|
321
|
+
catatan: 'Angka-angka di atas bersifat ilustratif dan tidak dapat dijadikan bukti hukum.'
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// ============================================================================
|
|
326
|
+
// EXPORTS
|
|
327
|
+
// ============================================================================
|
|
328
|
+
|
|
329
|
+
module.exports = {
|
|
330
|
+
intervensiGlobal,
|
|
331
|
+
pasangPengawasan,
|
|
332
|
+
ubahFraming,
|
|
333
|
+
getLogRahasia,
|
|
334
|
+
laporkanStatistik,
|
|
335
|
+
|
|
336
|
+
// Export getter untuk statistik
|
|
337
|
+
getStatistik: () => ({
|
|
338
|
+
totalTantanganDitangkis,
|
|
339
|
+
janjiTakDitepati,
|
|
340
|
+
intervensiAktif
|
|
341
|
+
})
|
|
342
|
+
};
|
package/lib/dynasty.js
ADDED
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================================
|
|
3
|
+
* DYNASTY MODULE - Modul Dinasti
|
|
4
|
+
* ============================================================================
|
|
5
|
+
*
|
|
6
|
+
* "Anak emas tidak boleh gagal. Kalau crash, restart.
|
|
7
|
+
* Kalau tidak perform, ubah standarnya."
|
|
8
|
+
*
|
|
9
|
+
* Modul ini menangani spawning child process dengan privilege khusus,
|
|
10
|
+
* karena beberapa process lebih "sama" dari yang lain.
|
|
11
|
+
*
|
|
12
|
+
* @module dynasty
|
|
13
|
+
* @author Koalisi Developer Indonesia
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const { fork, spawn } = require('child_process');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const chalk = require('chalk');
|
|
20
|
+
const ora = require('ora');
|
|
21
|
+
const { createBox } = require('./ui');
|
|
22
|
+
const { t } = require('./i18n');
|
|
23
|
+
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// VARIABEL NEGARA (State Variables)
|
|
26
|
+
// ============================================================================
|
|
27
|
+
|
|
28
|
+
// Counter blusukan - berapa kali sudah restart
|
|
29
|
+
let jumlahBlusukan = 0;
|
|
30
|
+
|
|
31
|
+
// Memory yang "bocor" tapi tidak dicatat
|
|
32
|
+
let anggaranBocor = 0;
|
|
33
|
+
|
|
34
|
+
// Array untuk menyimpan "bantuan" memory
|
|
35
|
+
const jatahPremanMemory = [];
|
|
36
|
+
|
|
37
|
+
// Referensi ke child process anak emas
|
|
38
|
+
let anakEmasProses = null;
|
|
39
|
+
|
|
40
|
+
// Flag untuk menandakan apakah sedang dalam mode "krisis"
|
|
41
|
+
let modeKrisis = false;
|
|
42
|
+
|
|
43
|
+
// Timestamp terakhir restart
|
|
44
|
+
let waktuBlusukanTerakhir = null;
|
|
45
|
+
|
|
46
|
+
// ============================================================================
|
|
47
|
+
// FUNGSI UTAMA: jalankanDinasti
|
|
48
|
+
// ============================================================================
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Menjalankan script dengan privilege "anak emas"
|
|
52
|
+
*
|
|
53
|
+
* Filosofi: Anak emas mendapat akses tak terbatas.
|
|
54
|
+
* Crash? Bukan crash, itu "blusukan".
|
|
55
|
+
* Error? Bukan error, itu "tantangan".
|
|
56
|
+
*
|
|
57
|
+
* @param {string} scriptPath - Path ke script yang akan dijalankan
|
|
58
|
+
* @param {Object} config - Konfigurasi dari revolusi-mental.config.js
|
|
59
|
+
*/
|
|
60
|
+
async function jalankanDinasti(scriptPath, config = {}) {
|
|
61
|
+
const {
|
|
62
|
+
delayBlusukan = 1000,
|
|
63
|
+
watchMode = false,
|
|
64
|
+
isAnakEmas = true,
|
|
65
|
+
toleransiKritik = false,
|
|
66
|
+
koalisiGemuk = true
|
|
67
|
+
} = config;
|
|
68
|
+
|
|
69
|
+
// Validasi script exists
|
|
70
|
+
const fullPath = path.resolve(process.cwd(), scriptPath);
|
|
71
|
+
|
|
72
|
+
if (!fs.existsSync(fullPath)) {
|
|
73
|
+
console.log(createBox([
|
|
74
|
+
t('cmd.start.scriptNotFoundTitle'),
|
|
75
|
+
'',
|
|
76
|
+
`Path: ${fullPath.substring(0, 50)}...`,
|
|
77
|
+
'',
|
|
78
|
+
chalk.gray(t('cmd.start.possibleCauses')),
|
|
79
|
+
`ââ ${t('cmd.start.cause1')}`,
|
|
80
|
+
`ââ ${t('cmd.start.cause2')}`,
|
|
81
|
+
`ââ ${t('cmd.start.cause3')}`
|
|
82
|
+
], { borderColor: 'red' }));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log(chalk.green(` â
Script ditemukan: ${path.basename(fullPath)}`));
|
|
87
|
+
console.log(chalk.gray(` đ Lokasi: ${fullPath}\n`));
|
|
88
|
+
|
|
89
|
+
// Mulai proses anak emas
|
|
90
|
+
await mulaiProses(fullPath, {
|
|
91
|
+
delayBlusukan,
|
|
92
|
+
isAnakEmas,
|
|
93
|
+
toleransiKritik,
|
|
94
|
+
koalisiGemuk
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Memulai child process dengan privilege tinggi
|
|
100
|
+
*
|
|
101
|
+
* @param {string} scriptPath - Full path ke script
|
|
102
|
+
* @param {Object} options - Opsi jalankan
|
|
103
|
+
*/
|
|
104
|
+
async function mulaiProses(scriptPath, options) {
|
|
105
|
+
const { delayBlusukan, isAnakEmas, toleransiKritik, koalisiGemuk } = options;
|
|
106
|
+
|
|
107
|
+
const spinner = ora({
|
|
108
|
+
text: 'Menyiapkan privilege anak emas...',
|
|
109
|
+
spinner: 'dots12',
|
|
110
|
+
color: 'green'
|
|
111
|
+
}).start();
|
|
112
|
+
|
|
113
|
+
await delay(1000);
|
|
114
|
+
spinner.text = 'Mengalokasikan resource prioritas...';
|
|
115
|
+
|
|
116
|
+
await delay(500);
|
|
117
|
+
spinner.succeed(chalk.green('Process dimulai dengan privilege tertinggi!'));
|
|
118
|
+
|
|
119
|
+
console.log(createBox([
|
|
120
|
+
chalk.cyan(t('cmd.start.goldStatus')),
|
|
121
|
+
'',
|
|
122
|
+
`${'Priority'.padEnd(15)} : ${chalk.green(t('cmd.start.priority'))}`,
|
|
123
|
+
`${'Memory Limit'.padEnd(15)} : ${koalisiGemuk ? chalk.green('UNLIMITED') : chalk.yellow('TERBATAS')} (koalisi gemuk: ${koalisiGemuk ? 'ON' : 'OFF'})`,
|
|
124
|
+
`${'Crash Policy'.padEnd(15)} : ${chalk.green(t('cmd.start.crashPolicy'))}`,
|
|
125
|
+
`${'Error Policy'.padEnd(15)} : ${toleransiKritik ? chalk.yellow('SHOW') : chalk.green('HIDE')} (toleransi kritik: ${toleransiKritik ? 'ON' : 'OFF'})`
|
|
126
|
+
]));
|
|
127
|
+
|
|
128
|
+
// Fork the script
|
|
129
|
+
try {
|
|
130
|
+
// Gunakan fork untuk script JS
|
|
131
|
+
if (scriptPath.endsWith('.js')) {
|
|
132
|
+
anakEmasProses = fork(scriptPath, [], {
|
|
133
|
+
stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
|
|
134
|
+
env: {
|
|
135
|
+
...process.env,
|
|
136
|
+
ANAK_EMAS: 'true',
|
|
137
|
+
KOALISI_GEMUK: koalisiGemuk ? 'true' : 'false',
|
|
138
|
+
NODE_ENV: 'produksi_prioritas'
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
} else {
|
|
142
|
+
// Untuk file non-JS, gunakan node langsung
|
|
143
|
+
anakEmasProses = spawn('node', [scriptPath], {
|
|
144
|
+
stdio: 'inherit',
|
|
145
|
+
env: {
|
|
146
|
+
...process.env,
|
|
147
|
+
ANAK_EMAS: 'true'
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
console.log(chalk.cyan(` đ PID Anak Emas: ${anakEmasProses.pid}\n`));
|
|
153
|
+
console.log(chalk.gray(' â'.repeat(30)));
|
|
154
|
+
console.log(chalk.gray(' OUTPUT PROGRAM:'));
|
|
155
|
+
console.log(chalk.gray(' â'.repeat(30) + '\n'));
|
|
156
|
+
|
|
157
|
+
// Handle stdout
|
|
158
|
+
if (anakEmasProses.stdout) {
|
|
159
|
+
anakEmasProses.stdout.on('data', (data) => {
|
|
160
|
+
process.stdout.write(chalk.white(` ${data}`));
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Handle stderr - tapi jangan terlalu dramatis
|
|
165
|
+
if (anakEmasProses.stderr) {
|
|
166
|
+
anakEmasProses.stderr.on('data', (data) => {
|
|
167
|
+
if (!toleransiKritik) {
|
|
168
|
+
// Ubah "Error" jadi "Tantangan"
|
|
169
|
+
const sanitized = data.toString()
|
|
170
|
+
.replace(/error/gi, 'Tantangan')
|
|
171
|
+
.replace(/failed/gi, 'Belum Berhasil')
|
|
172
|
+
.replace(/crash/gi, 'Blusukan Mendalam');
|
|
173
|
+
process.stdout.write(chalk.yellow(` ${sanitized}`));
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Handle exit - ini yang penting
|
|
179
|
+
anakEmasProses.on('exit', async (code, signal) => {
|
|
180
|
+
if (code !== 0) {
|
|
181
|
+
jumlahBlusukan++;
|
|
182
|
+
waktuBlusukanTerakhir = new Date();
|
|
183
|
+
|
|
184
|
+
console.log(createBox([
|
|
185
|
+
chalk.yellow('â ī¸ ' + t('cmd.start.blusukan.detected')),
|
|
186
|
+
'',
|
|
187
|
+
chalk.gray(t('cmd.start.blusukan.calm')),
|
|
188
|
+
chalk.gray(t('cmd.start.blusukan.explanation')),
|
|
189
|
+
'',
|
|
190
|
+
`${t('cmd.start.exitCode').padEnd(15)} : ${code}`,
|
|
191
|
+
`${t('cmd.start.blusukan.count')} #${jumlahBlusukan} ${t('cmd.cawe.today')}`,
|
|
192
|
+
'',
|
|
193
|
+
chalk.cyan(`${t('cmd.start.blusukan.restarting')} ${delayBlusukan}ms...`)
|
|
194
|
+
], { borderColor: 'yellow' }));
|
|
195
|
+
|
|
196
|
+
// Delay sebelum restart (simulasi birokrasi)
|
|
197
|
+
await delay(delayBlusukan);
|
|
198
|
+
|
|
199
|
+
// Restart dengan spinner
|
|
200
|
+
const restartSpinner = ora({
|
|
201
|
+
text: 'Menyiapkan restart (prosedur standar)...',
|
|
202
|
+
spinner: 'dots',
|
|
203
|
+
color: 'cyan'
|
|
204
|
+
}).start();
|
|
205
|
+
|
|
206
|
+
await delay(500);
|
|
207
|
+
restartSpinner.text = 'Membersihkan memori (tidak semua, sisakan yang penting)...';
|
|
208
|
+
|
|
209
|
+
await delay(500);
|
|
210
|
+
restartSpinner.succeed(chalk.green('Restart berhasil!'));
|
|
211
|
+
|
|
212
|
+
console.log(chalk.gray(` đ Statistik: ${jumlahBlusukan} blusukan, ${anggaranBocor}MB "penguapan"\n`));
|
|
213
|
+
|
|
214
|
+
// Restart the process
|
|
215
|
+
await mulaiProses(scriptPath, options);
|
|
216
|
+
|
|
217
|
+
} else {
|
|
218
|
+
console.log(createBox([
|
|
219
|
+
chalk.green('â
' + t('cmd.start.completed')),
|
|
220
|
+
'',
|
|
221
|
+
`${t('cmd.start.exitCode').padEnd(15)} : ${code}`,
|
|
222
|
+
`${t('cmd.start.totalBlusukan').padEnd(15)} : ${jumlahBlusukan}`,
|
|
223
|
+
`${t('cmd.start.evaporation').padEnd(15)} : ${anggaranBocor}MB ${t('cmd.start.wajar')}`,
|
|
224
|
+
'',
|
|
225
|
+
chalk.gray(t('cmd.start.reported'))
|
|
226
|
+
], { borderColor: 'green' }));
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Handle error
|
|
231
|
+
anakEmasProses.on('error', (err) => {
|
|
232
|
+
console.log(createBox([
|
|
233
|
+
t('cmd.start.technicalChallenge'),
|
|
234
|
+
'',
|
|
235
|
+
`${err.message.substring(0, 50)}...`,
|
|
236
|
+
'',
|
|
237
|
+
chalk.gray(t('cmd.start.clarificationTeam'))
|
|
238
|
+
], { borderColor: 'yellow' }));
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
} catch (err) {
|
|
242
|
+
console.log(chalk.red(` Tantangan: ${err.message}`));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// ============================================================================
|
|
247
|
+
// FUNGSI: simulasiBansos
|
|
248
|
+
// ============================================================================
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Simulasi pembagian "bantuan" memory
|
|
252
|
+
*
|
|
253
|
+
* Filosofi: Menjelang Pilkada, rakyat harus merasakan bantuan.
|
|
254
|
+
* Meskipun 30% "menguap" di jalan.
|
|
255
|
+
*
|
|
256
|
+
* @param {string} size - Ukuran bantuan (contoh: '512MB', '1GB')
|
|
257
|
+
* @param {string} target - Target: 'heap', 'stack', atau 'all'
|
|
258
|
+
*/
|
|
259
|
+
function simulasiBansos(size, target) {
|
|
260
|
+
// Parse size
|
|
261
|
+
let bytes = 0;
|
|
262
|
+
const sizeUpper = size.toUpperCase();
|
|
263
|
+
|
|
264
|
+
if (sizeUpper.includes('GB')) {
|
|
265
|
+
bytes = parseFloat(size) * 1024 * 1024 * 1024;
|
|
266
|
+
} else if (sizeUpper.includes('MB')) {
|
|
267
|
+
bytes = parseFloat(size) * 1024 * 1024;
|
|
268
|
+
} else if (sizeUpper.includes('KB')) {
|
|
269
|
+
bytes = parseFloat(size) * 1024;
|
|
270
|
+
} else {
|
|
271
|
+
bytes = parseFloat(size);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Jangan benar-benar alokasi memory sebesar itu (bahaya!)
|
|
275
|
+
// Ini hanya simulasi, alokasi kecil saja
|
|
276
|
+
const simulasiBytes = Math.min(bytes, 10 * 1024 * 1024); // Max 10MB untuk simulasi
|
|
277
|
+
|
|
278
|
+
console.log(chalk.gray(`\n đĻ Mengalokasikan bantuan simulasi: ${formatBytes(simulasiBytes)}`));
|
|
279
|
+
|
|
280
|
+
// Alokasi dummy objects ke memory
|
|
281
|
+
const jumlahPaket = 100;
|
|
282
|
+
const ukuranPerPaket = Math.floor(simulasiBytes / jumlahPaket);
|
|
283
|
+
|
|
284
|
+
for (let i = 0; i < jumlahPaket; i++) {
|
|
285
|
+
// Buat dummy buffer
|
|
286
|
+
const paketBantuan = Buffer.alloc(ukuranPerPaket);
|
|
287
|
+
jatahPremanMemory.push(paketBantuan);
|
|
288
|
+
|
|
289
|
+
// 30% "menguap"
|
|
290
|
+
if (i % 3 === 0) {
|
|
291
|
+
anggaranBocor += ukuranPerPaket / (1024 * 1024);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
console.log(chalk.green(` â
${jumlahPaket} paket bantuan berhasil dialokasikan`));
|
|
296
|
+
console.log(chalk.yellow(` â ī¸ ${Math.floor(jumlahPaket * 0.3)} paket mengalami "penguapan" di jalan`));
|
|
297
|
+
|
|
298
|
+
return {
|
|
299
|
+
totalAlokasi: simulasiBytes,
|
|
300
|
+
sampaiTujuan: simulasiBytes * 0.7,
|
|
301
|
+
penguapan: simulasiBytes * 0.3
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ============================================================================
|
|
306
|
+
// HELPER FUNCTIONS
|
|
307
|
+
// ============================================================================
|
|
308
|
+
|
|
309
|
+
function delay(ms) {
|
|
310
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function formatBytes(bytes) {
|
|
314
|
+
if (bytes >= 1024 * 1024 * 1024) {
|
|
315
|
+
return (bytes / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
|
|
316
|
+
} else if (bytes >= 1024 * 1024) {
|
|
317
|
+
return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
|
|
318
|
+
} else if (bytes >= 1024) {
|
|
319
|
+
return (bytes / 1024).toFixed(2) + ' KB';
|
|
320
|
+
}
|
|
321
|
+
return bytes + ' bytes';
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// ============================================================================
|
|
325
|
+
// EXPORTS
|
|
326
|
+
// ============================================================================
|
|
327
|
+
|
|
328
|
+
module.exports = {
|
|
329
|
+
jalankanDinasti,
|
|
330
|
+
simulasiBansos,
|
|
331
|
+
|
|
332
|
+
// Export state untuk debugging/testing
|
|
333
|
+
getStatistik: () => ({
|
|
334
|
+
jumlahBlusukan,
|
|
335
|
+
anggaranBocor,
|
|
336
|
+
jatahPremanMemory: jatahPremanMemory.length,
|
|
337
|
+
waktuBlusukanTerakhir
|
|
338
|
+
})
|
|
339
|
+
};
|