unbound-cli 1.1.0 → 1.1.1
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/package.json +1 -1
- package/src/commands/setup.js +49 -33
- package/src/index.js +2 -2
package/package.json
CHANGED
package/src/commands/setup.js
CHANGED
|
@@ -332,6 +332,23 @@ function checkRoot(commandHint = 'setup mdm') {
|
|
|
332
332
|
}
|
|
333
333
|
}
|
|
334
334
|
|
|
335
|
+
/**
|
|
336
|
+
* Returns true when the process has the privileges needed to touch system-level
|
|
337
|
+
* (MDM) configuration. On Windows, `net session` succeeds only when elevated, so
|
|
338
|
+
* it doubles as an Administrator check — this keeps nuke's scope (and the copy it
|
|
339
|
+
* shows) accurate instead of assuming admin.
|
|
340
|
+
*/
|
|
341
|
+
function hasRootPrivileges() {
|
|
342
|
+
if (process.platform === 'win32') {
|
|
343
|
+
try {
|
|
344
|
+
return spawnSync('net', ['session'], { stdio: 'ignore', windowsHide: true }).status === 0;
|
|
345
|
+
} catch {
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return typeof process.getuid === 'function' && process.getuid() === 0;
|
|
350
|
+
}
|
|
351
|
+
|
|
335
352
|
/**
|
|
336
353
|
* Runs a batch of tools sequentially with spinners.
|
|
337
354
|
* Stops on first failure. Returns true if all succeeded.
|
|
@@ -839,52 +856,49 @@ Clear examples (no API key required):
|
|
|
839
856
|
.command('nuke')
|
|
840
857
|
.alias('uninstall')
|
|
841
858
|
.description(
|
|
842
|
-
'Remove Unbound and start fresh
|
|
843
|
-
'
|
|
844
|
-
|
|
859
|
+
'Remove Unbound and start fresh: clears AI-tool configuration and deletes ' +
|
|
860
|
+
'stored credentials. Scope follows your privileges — run with sudo to also ' +
|
|
861
|
+
'remove MDM (system-level) config for all users; without root it clears only ' +
|
|
862
|
+
'the current user.'
|
|
845
863
|
)
|
|
846
864
|
.option('-y, --yes', 'Skip the confirmation prompt')
|
|
847
|
-
.option('--user', "Clear only THIS user's tool config and credentials — skip MDM (no root required)")
|
|
848
865
|
.addHelpText('after', `
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
866
|
+
Scope is chosen automatically from your privileges:
|
|
867
|
+
Run with sudo (root) Clears every user-level AND MDM (system-level) tool
|
|
868
|
+
config for all users on the device, then deletes
|
|
869
|
+
credentials.
|
|
870
|
+
Run without root Clears only the current user's tool config and
|
|
871
|
+
credentials. MDM (system-level) config is skipped —
|
|
872
|
+
re-run with sudo to remove it too.
|
|
856
873
|
|
|
857
874
|
What it clears:
|
|
858
875
|
- USER-level tool config — Cursor, GitHub Copilot, Claude Code (subscription +
|
|
859
|
-
gateway), Gemini CLI, Codex (subscription + gateway).
|
|
860
|
-
- MDM (system-level) tool config across all users
|
|
861
|
-
- Stored credentials and settings (~/.unbound/config.json).
|
|
876
|
+
gateway), Gemini CLI, Codex (subscription + gateway).
|
|
877
|
+
- MDM (system-level) tool config across all users [only when run as root]
|
|
878
|
+
- Stored credentials and settings (~/.unbound/config.json).
|
|
862
879
|
|
|
863
880
|
After it finishes, run \`unbound login\` (or \`unbound onboard\`) to set things up
|
|
864
881
|
fresh. Clearing never contacts the Unbound API, so no API key is needed.
|
|
865
882
|
|
|
866
883
|
Examples:
|
|
867
|
-
$ sudo unbound nuke
|
|
868
|
-
$ sudo unbound nuke --yes
|
|
869
|
-
$ unbound nuke
|
|
870
|
-
$ unbound nuke --
|
|
871
|
-
$
|
|
884
|
+
$ sudo unbound nuke Remove everything on the device (asks to confirm)
|
|
885
|
+
$ sudo unbound nuke --yes Remove everything, no confirmation
|
|
886
|
+
$ unbound nuke Clear just your tools + credentials (no sudo)
|
|
887
|
+
$ unbound nuke --yes Same, no confirmation
|
|
888
|
+
$ unbound uninstall 'uninstall' is an alias for 'nuke'
|
|
872
889
|
`)
|
|
873
890
|
.action(async (opts) => {
|
|
874
891
|
try {
|
|
875
|
-
//
|
|
876
|
-
//
|
|
877
|
-
//
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
process.exitCode = 1;
|
|
881
|
-
return;
|
|
882
|
-
}
|
|
892
|
+
// Scope follows privileges: with root (or Windows Administrator) we also
|
|
893
|
+
// remove system-level MDM config for all users; otherwise we clear only
|
|
894
|
+
// this user. Detecting elevation up front keeps the confirmation honest
|
|
895
|
+
// (no promising MDM removal we can't perform).
|
|
896
|
+
const includeMdm = hasRootPrivileges();
|
|
883
897
|
|
|
884
898
|
if (!opts.yes) {
|
|
885
|
-
output.warn(
|
|
886
|
-
? 'This removes
|
|
887
|
-
: 'This removes
|
|
899
|
+
output.warn(includeMdm
|
|
900
|
+
? 'This removes ALL Unbound tool configuration on this device (user-level and MDM) and deletes your stored credentials.'
|
|
901
|
+
: 'This removes your user-level Unbound tool configuration and deletes your stored credentials. (MDM/system-level config needs root and will be skipped — re-run with sudo to remove it too.)');
|
|
888
902
|
const ok = await confirm('Continue?');
|
|
889
903
|
if (!ok) {
|
|
890
904
|
output.info('Cancelled. Nothing was changed.');
|
|
@@ -902,11 +916,13 @@ Examples:
|
|
|
902
916
|
const userTools = Object.keys(SETUP_TOOL_MAP).map(name => ({ name, ...SETUP_TOOL_MAP[name] }));
|
|
903
917
|
const userFailed = await clearToolsBestEffort('user', userTools, { mdm: false, backendUrl, gatewayUrl, frontendUrl });
|
|
904
918
|
|
|
905
|
-
// MDM clears
|
|
919
|
+
// MDM clears need root and touch all users — run them only when we have it.
|
|
906
920
|
let mdmFailed = [];
|
|
907
|
-
if (
|
|
921
|
+
if (includeMdm) {
|
|
908
922
|
const mdmTools = Object.keys(MDM_TOOLS).map(name => ({ name, ...MDM_TOOLS[name] }));
|
|
909
923
|
mdmFailed = await clearToolsBestEffort('mdm', mdmTools, { mdm: true, backendUrl, gatewayUrl });
|
|
924
|
+
} else {
|
|
925
|
+
output.info('Skipped MDM (system-level) config — that needs root. Re-run with sudo to remove it too.');
|
|
910
926
|
}
|
|
911
927
|
|
|
912
928
|
// Wipe credentials + settings last, regardless of tool-clear outcomes.
|
|
@@ -915,7 +931,7 @@ Examples:
|
|
|
915
931
|
|
|
916
932
|
console.log('');
|
|
917
933
|
const failed = [...userFailed, ...mdmFailed];
|
|
918
|
-
const scope =
|
|
934
|
+
const scope = includeMdm ? 'on this device' : 'for your user';
|
|
919
935
|
if (failed.length === 0) {
|
|
920
936
|
output.success(`Unbound removed ${scope}. The CLI is back to a fresh state — run "unbound login" to start over.`);
|
|
921
937
|
} else {
|
package/src/index.js
CHANGED
|
@@ -82,8 +82,8 @@ TOOL SETUP
|
|
|
82
82
|
$ unbound setup --all --clear Remove config for every tool
|
|
83
83
|
|
|
84
84
|
Full uninstall (all tools + credentials):
|
|
85
|
-
$ sudo unbound nuke Wipe everything on the device (MDM + user)
|
|
86
|
-
$ unbound nuke
|
|
85
|
+
$ sudo unbound nuke Wipe everything on the device (MDM + user)
|
|
86
|
+
$ unbound nuke Wipe just your tools + credentials (no sudo)
|
|
87
87
|
|
|
88
88
|
MDM SETUP (admin, requires root)
|
|
89
89
|
$ sudo unbound setup mdm --admin-api-key KEY --all
|