@ade-syofyan/feature-map-pro 0.21.0-pro.2 → 0.21.0-pro.4
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 +3 -1
- package/bin/feature-map-pro.mjs +4 -2
- package/lib/installer.mjs +7 -1
- package/lib/prompts.mjs +68 -0
- package/package.json +1 -1
- package/release.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,9 @@ Source mesin Pro tidak termasuk dalam paket npm; binary diunduh dari rilis resmi
|
|
|
7
7
|
npx @ade-syofyan/feature-map-pro@preview install
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
-
Masukkan email pembelian dan kode lisensi dari Ade Syofyan.
|
|
10
|
+
Masukkan email pembelian dan kode lisensi dari Ade Syofyan. Saat mengetik atau paste,
|
|
11
|
+
kode disamarkan dengan titik dan jumlah karakter. Tekan Enter untuk memeriksa lisensi;
|
|
12
|
+
Ctrl+U menghapus input dan Ctrl+C membatalkan. Anda juga bisa memakai
|
|
11
13
|
`--license-file /path/to/buyer.license`. Jangan memasukkan kode ke argumen command.
|
|
12
14
|
Setelah aktif, buka sesi agent baru. Status: `npx @ade-syofyan/feature-map-pro@preview license status`.
|
|
13
15
|
|
package/bin/feature-map-pro.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import {fileURLToPath} from 'node:url';
|
|
4
4
|
import {activateAndInstall,ensurePayload,installSkills,runEngine} from '../lib/installer.mjs';
|
|
5
|
+
import {activateWithPrompt} from '../lib/prompts.mjs';
|
|
5
6
|
|
|
6
7
|
const manifest=JSON.parse(fs.readFileSync(fileURLToPath(new URL('../release.json',import.meta.url)),'utf8'));
|
|
7
8
|
const args=process.argv.slice(2);
|
|
@@ -17,7 +18,8 @@ if(!args.length||args[0]==='--help'||args[0]==='help') {
|
|
|
17
18
|
if(!['--email','--license-file'].includes(args[i])||!args[i+1]) throw new Error('Opsi instalasi tidak dikenal. Gunakan --help.');
|
|
18
19
|
activation.push(args[i]==='--license-file'?'--file':args[i],args[++i]);
|
|
19
20
|
}
|
|
20
|
-
|
|
21
|
+
const result=await activateWithPrompt(root,activation);
|
|
22
|
+
activateAndInstall(()=>result,()=>{
|
|
21
23
|
const backup=activateOnly?null:installSkills(root);
|
|
22
24
|
console.log('Pro aktif. Buka sesi baru untuk memuat instruksi Pro.');
|
|
23
25
|
if(backup) console.log('Salinan skill sebelumnya: '+backup);
|
|
@@ -25,5 +27,5 @@ if(!args.length||args[0]==='--help'||args[0]==='help') {
|
|
|
25
27
|
} else {
|
|
26
28
|
process.exitCode=runEngine(root,args).status??2;
|
|
27
29
|
}
|
|
28
|
-
} catch(error) {console.error('Gagal: '+error.message);process.exitCode=2;}
|
|
30
|
+
} catch(error) {console.error('Gagal: '+error.message);process.exitCode=error.exitCode||2;}
|
|
29
31
|
}
|
package/lib/installer.mjs
CHANGED
|
@@ -75,8 +75,14 @@ function engineValid(root,entry,platform) {
|
|
|
75
75
|
verifyChecksum(fs.readFileSync(file),entry.engine_sha256);return true;
|
|
76
76
|
} catch {return false;}
|
|
77
77
|
}
|
|
78
|
+
export function tarExecutable(platform=process.platform,systemRoot=process.env.SystemRoot||process.env.SYSTEMROOT) {
|
|
79
|
+
if(platform!=='win32') return 'tar';
|
|
80
|
+
const executable=systemRoot&&path.join(systemRoot,'System32','tar.exe');
|
|
81
|
+
if(!executable||!fs.existsSync(executable)) throw new Error('Tar bawaan Windows tidak tersedia. Gunakan Windows 10/11 dengan tar.');
|
|
82
|
+
return executable;
|
|
83
|
+
}
|
|
78
84
|
function tar(args) {
|
|
79
|
-
const result=spawnSync(
|
|
85
|
+
const result=spawnSync(tarExecutable(),args,{encoding:'utf8',maxBuffer:8*1024*1024});
|
|
80
86
|
if(result.error||result.status!==0) throw new Error('Paket tidak bisa dibaca. Pastikan tar tersedia.');
|
|
81
87
|
return result.stdout;
|
|
82
88
|
}
|
package/lib/prompts.mjs
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import {createInterface,emitKeypressEvents} from 'node:readline';
|
|
2
|
+
import {runEngine} from './installer.mjs';
|
|
3
|
+
|
|
4
|
+
export function readLicense({input=process.stdin,output=process.stdout}={}) {
|
|
5
|
+
return new Promise((resolve,reject)=>{
|
|
6
|
+
let value='',pasting=false,finished=false;
|
|
7
|
+
const wasRaw=Boolean(input.isRaw);
|
|
8
|
+
const draw=(message='')=>output.write('\r\x1b[2KKode lisensi: '+ '•'.repeat(Math.min([...value].length,20))+` (${[...value].length} karakter)`+(message?' — '+message:''));
|
|
9
|
+
function finish(error) {
|
|
10
|
+
if(finished)return;finished=true;
|
|
11
|
+
input.removeListener('keypress',onKey);input.removeListener('end',onEnd);input.removeListener('error',onError);
|
|
12
|
+
input.setRawMode(wasRaw);input.pause();output.write('\x1b[?2004l\n');
|
|
13
|
+
if(error)reject(error);else resolve(value);
|
|
14
|
+
value='';
|
|
15
|
+
}
|
|
16
|
+
const onEnd=()=>finish(new Error('Input lisensi terputus. Coba lagi.'));
|
|
17
|
+
const onError=()=>finish(new Error('Input lisensi tidak bisa dibaca.'));
|
|
18
|
+
function onKey(text,key={}) {
|
|
19
|
+
if(finished)return;
|
|
20
|
+
if(key.name==='paste-start'){pasting=true;return;}
|
|
21
|
+
if(key.name==='paste-end'){pasting=false;draw();return;}
|
|
22
|
+
if(key.ctrl&&key.name==='c')return finish(Object.assign(new Error('Aktivasi dibatalkan.'),{exitCode:130}));
|
|
23
|
+
if(key.ctrl&&key.name==='d')return onEnd();
|
|
24
|
+
if(key.ctrl&&key.name==='u'){value='';draw();return;}
|
|
25
|
+
if(key.name==='return'||key.name==='enter') {
|
|
26
|
+
if(pasting)return;
|
|
27
|
+
if(!value.trim()){draw('Masukkan kode lisensi');return;}
|
|
28
|
+
return finish();
|
|
29
|
+
}
|
|
30
|
+
if(key.name==='backspace'){value=[...value].slice(0,-1).join('');draw();return;}
|
|
31
|
+
if(text&&!key.ctrl&&!key.meta&&!text.includes('\x1b')) {
|
|
32
|
+
value+=(text.replace(/[\x00-\x20\x7f]/g,''));
|
|
33
|
+
if(value.length>16384)return finish(new Error('Kode lisensi terlalu panjang. Cek lagi.'));
|
|
34
|
+
draw();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
emitKeypressEvents(input);input.setRawMode(true);
|
|
38
|
+
input.on('keypress',onKey);input.once('end',onEnd);input.once('error',onError);
|
|
39
|
+
output.write('Tempel kode lisensi, lalu tekan Enter. Ctrl+U hapus; Ctrl+C batal.\n\x1b[?2004h');draw();input.resume();
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function activateWithPrompt(root,args,{input=process.stdin,output=process.stdout,run=runEngine}={}) {
|
|
44
|
+
if(!input.isTTY||!output.isTTY||args.includes('--file'))return run(root,['license','activate',...args]);
|
|
45
|
+
const activation=[...args];
|
|
46
|
+
if(!activation.includes('--email')) {
|
|
47
|
+
const prompt=createInterface({input,output});
|
|
48
|
+
try {
|
|
49
|
+
const email=await new Promise((resolve,reject)=>{
|
|
50
|
+
let settled=false;
|
|
51
|
+
const finish=(error,value)=>{
|
|
52
|
+
if(settled)return;settled=true;
|
|
53
|
+
prompt.removeListener('close',closed);prompt.removeListener('SIGINT',cancelled);input.removeListener('error',failed);
|
|
54
|
+
if(error)reject(error);else resolve(value);
|
|
55
|
+
};
|
|
56
|
+
const closed=()=>finish(new Error('Input email terputus. Coba lagi.'));
|
|
57
|
+
const cancelled=()=>finish(Object.assign(new Error('Aktivasi dibatalkan.'),{exitCode:130}));
|
|
58
|
+
const failed=()=>finish(new Error('Input email tidak bisa dibaca.'));
|
|
59
|
+
prompt.once('close',closed);prompt.once('SIGINT',cancelled);input.once('error',failed);
|
|
60
|
+
prompt.question('Email pembelian: ',value=>finish(null,value));
|
|
61
|
+
});
|
|
62
|
+
activation.push('--email',email);
|
|
63
|
+
} finally {prompt.close();}
|
|
64
|
+
}
|
|
65
|
+
const token=await readLicense({input,output});
|
|
66
|
+
output.write('Memeriksa lisensi…\n');
|
|
67
|
+
return run(root,['license','activate',...activation],{input:token+'\n',stdio:['pipe','inherit','inherit']});
|
|
68
|
+
}
|
package/package.json
CHANGED