unbound-cli 0.3.1 → 0.5.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/LOCAL_DEV.md +46 -2
- package/README.md +97 -7
- package/package.json +1 -1
- package/src/commands/discover.js +32 -10
- package/src/commands/onboard.js +134 -0
- package/src/commands/policy.js +1704 -212
- package/src/commands/setup.js +53 -3
- package/src/index.js +32 -7
package/src/commands/setup.js
CHANGED
|
@@ -27,6 +27,10 @@ const MDM_TOOLS = {
|
|
|
27
27
|
// Default tools for --all (uses subscription mode for Claude Code and Codex since only one can be active)
|
|
28
28
|
const MDM_ALL_TOOLS = ['cursor', 'claude-code-subscription', 'gemini-cli', 'codex-subscription'];
|
|
29
29
|
|
|
30
|
+
// Default tools for user-level `unbound setup --all`.
|
|
31
|
+
// Includes Cursor, Claude Code hooks, and Codex hooks (no Gemini CLI).
|
|
32
|
+
const ALL_TOOLS = ['cursor', 'claude-code-subscription', 'codex-subscription'];
|
|
33
|
+
|
|
30
34
|
// Tool name → script mapping for automated tools
|
|
31
35
|
const SETUP_TOOL_MAP = {
|
|
32
36
|
'cursor': { label: 'Cursor', script: 'cursor/setup.py' },
|
|
@@ -130,11 +134,12 @@ function runScriptPiped(scriptPath, args) {
|
|
|
130
134
|
/**
|
|
131
135
|
* Checks that the process is running as root (macOS/Linux).
|
|
132
136
|
* Windows admin check is handled by the Python MDM scripts themselves.
|
|
137
|
+
* Pass a customized hint for the calling command (defaults to "setup mdm").
|
|
133
138
|
*/
|
|
134
|
-
function checkRoot() {
|
|
139
|
+
function checkRoot(commandHint = 'setup mdm') {
|
|
135
140
|
if (process.platform === 'win32') return;
|
|
136
141
|
if (typeof process.getuid !== 'function' || process.getuid() !== 0) {
|
|
137
|
-
throw new Error(
|
|
142
|
+
throw new Error(`MDM setup requires root. Run with: sudo unbound ${commandHint} ...`);
|
|
138
143
|
}
|
|
139
144
|
}
|
|
140
145
|
|
|
@@ -171,6 +176,7 @@ function register(program) {
|
|
|
171
176
|
.option('--clear', 'Remove Unbound configuration for the specified tools')
|
|
172
177
|
.option('--subscription', 'Use subscription mode for Claude Code / Codex (hooks only)')
|
|
173
178
|
.option('--gateway', 'Use gateway mode for Claude Code / Codex (Unbound as AI provider)')
|
|
179
|
+
.option('--all', 'Set up the default bundle: Cursor, Claude Code (hooks), Codex (hooks)')
|
|
174
180
|
.addHelpText('after', `
|
|
175
181
|
Available tools:
|
|
176
182
|
cursor Cursor IDE
|
|
@@ -195,6 +201,10 @@ Examples:
|
|
|
195
201
|
$ unbound setup claude-code --subscription Claude Code hooks only
|
|
196
202
|
$ unbound setup codex --gateway Codex gateway mode
|
|
197
203
|
|
|
204
|
+
Install the default bundle (Cursor + Claude Code hooks + Codex hooks):
|
|
205
|
+
$ unbound setup --all Set up the default bundle
|
|
206
|
+
$ unbound setup --all --api-key <key> Login + set up the bundle
|
|
207
|
+
|
|
198
208
|
One-step login and setup:
|
|
199
209
|
$ unbound setup cursor --api-key <key> Login + set up Cursor
|
|
200
210
|
$ unbound setup cursor claude-code-gateway --api-key <key>
|
|
@@ -217,6 +227,16 @@ automatically to authenticate before proceeding.
|
|
|
217
227
|
const apiKey = config.getApiKey();
|
|
218
228
|
const frontendUrl = config.getFrontendUrl();
|
|
219
229
|
|
|
230
|
+
// --all expands to the default bundle. Cannot be combined with explicit tool names.
|
|
231
|
+
if (opts.all) {
|
|
232
|
+
if (tools.length > 0) {
|
|
233
|
+
output.error('Cannot combine --all with explicit tool names.');
|
|
234
|
+
process.exitCode = 1;
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
tools = [...ALL_TOOLS];
|
|
238
|
+
}
|
|
239
|
+
|
|
220
240
|
// No tools specified → interactive multi-select (existing flow)
|
|
221
241
|
if (tools.length === 0) {
|
|
222
242
|
const selected = await output.multiSelect(
|
|
@@ -477,4 +497,34 @@ Examples:
|
|
|
477
497
|
});
|
|
478
498
|
}
|
|
479
499
|
|
|
480
|
-
|
|
500
|
+
/**
|
|
501
|
+
* Runs the user-level default bundle (Cursor, Claude Code hooks, Codex hooks) with spinners.
|
|
502
|
+
* Assumes the caller has already ensured the user is logged in.
|
|
503
|
+
* Returns true on success, false on failure.
|
|
504
|
+
*/
|
|
505
|
+
async function runSetupAllBundle(apiKey) {
|
|
506
|
+
const resolvedTools = ALL_TOOLS.map(name => ({ name, ...SETUP_TOOL_MAP[name] }));
|
|
507
|
+
const args = `--api-key ${shellEscape(apiKey)}`;
|
|
508
|
+
return runBatch(resolvedTools, (tool) => runScriptPiped(tool.script, args));
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Runs the MDM default bundle (Cursor, Claude Code hooks, Gemini CLI, Codex hooks) with spinners.
|
|
513
|
+
* Caller must ensure the process is running as root.
|
|
514
|
+
* Returns true on success, false on failure.
|
|
515
|
+
*/
|
|
516
|
+
async function runMdmSetupAllBundle(adminApiKey, { url } = {}) {
|
|
517
|
+
const resolvedTools = MDM_ALL_TOOLS.map(name => ({ name, ...MDM_TOOLS[name] }));
|
|
518
|
+
let args = `--api-key ${shellEscape(adminApiKey)}`;
|
|
519
|
+
if (url) args += ` --url ${shellEscape(url)}`;
|
|
520
|
+
return runBatch(resolvedTools, (tool) => runScriptPiped(tool.script, args));
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
module.exports = {
|
|
524
|
+
register,
|
|
525
|
+
runSetupAllBundle,
|
|
526
|
+
runMdmSetupAllBundle,
|
|
527
|
+
checkRoot,
|
|
528
|
+
ALL_TOOLS,
|
|
529
|
+
MDM_ALL_TOOLS,
|
|
530
|
+
};
|
package/src/index.js
CHANGED
|
@@ -23,8 +23,13 @@ AUTHENTICATION
|
|
|
23
23
|
$ unbound whoami Show current user and organization
|
|
24
24
|
$ unbound status Show CLI status and API connectivity
|
|
25
25
|
|
|
26
|
+
ONBOARDING (one-step install + discover)
|
|
27
|
+
$ unbound onboard --api-key <USER_KEY> --discovery-key <DISCOVERY_KEY>
|
|
28
|
+
$ sudo unbound onboard-mdm --admin-api-key <ADMIN_KEY> --discovery-key <DISCOVERY_KEY>
|
|
29
|
+
|
|
26
30
|
TOOL SETUP
|
|
27
31
|
$ unbound setup Select and install multiple tools interactively
|
|
32
|
+
$ unbound setup --all Set up the default bundle (Cursor + Claude Code hooks + Codex hooks)
|
|
28
33
|
$ unbound setup cursor Set up Cursor
|
|
29
34
|
$ unbound setup claude-code Set up Claude Code (interactive mode selection)
|
|
30
35
|
$ unbound setup claude-code --gateway Use Unbound as AI provider
|
|
@@ -68,14 +73,33 @@ MDM AI TOOLS DISCOVERY
|
|
|
68
73
|
$ unbound discover status Show scan schedule and logs
|
|
69
74
|
|
|
70
75
|
POLICY MANAGEMENT
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
$ unbound policy
|
|
75
|
-
$ unbound policy
|
|
76
|
+
Unbound has four policy types. Each type has its own subcommand with guided flags.
|
|
77
|
+
Docs: https://docs.getunbound.ai/policies
|
|
78
|
+
|
|
79
|
+
$ unbound policy Overview and subcommand list
|
|
80
|
+
$ unbound policy form-data Reference data (user groups, models, guardrails, etc.)
|
|
81
|
+
$ unbound policy list List Cost/Model/Security policies
|
|
82
|
+
$ unbound policy get <id> View a policy's details
|
|
76
83
|
$ unbound policy delete <id> Delete a policy
|
|
77
|
-
$ unbound policy effective <id> View effective policies for a user
|
|
78
|
-
|
|
84
|
+
$ unbound policy effective <id> View effective policies for a user or group
|
|
85
|
+
|
|
86
|
+
Cost policies — monthly budget limits per user group:
|
|
87
|
+
$ unbound policy cost create --name "Eng Budget" --monthly-budget 1000 --group engg
|
|
88
|
+
|
|
89
|
+
Model policies — control which AI models are available:
|
|
90
|
+
$ unbound policy model create --name "No Opus" --all-models --excluded claude-3-opus
|
|
91
|
+
|
|
92
|
+
Security policies — guardrails for PII/secrets and routing rules:
|
|
93
|
+
$ unbound policy security create --name "Block PII" --sub-type guardrails --guardrail PII:BLOCK
|
|
94
|
+
|
|
95
|
+
Tool policies — shell command and MCP tool controls (separate backend):
|
|
96
|
+
$ unbound policy tool list
|
|
97
|
+
$ unbound policy tool create-terminal --name "Block rm -rf" --command-family filesystem \\
|
|
98
|
+
--field command='rm -rf*' --action BLOCK --custom-message "Destructive command blocked."
|
|
99
|
+
$ unbound policy tool create-mcp --name "Audit Linear writes" --mcp-server Linear \\
|
|
100
|
+
--mcp-action-type write --action AUDIT
|
|
101
|
+
$ unbound policy tool families Discover terminal command families
|
|
102
|
+
$ unbound policy tool mcp-servers Discover MCP servers and their tools
|
|
79
103
|
|
|
80
104
|
USER & GROUP MANAGEMENT
|
|
81
105
|
$ unbound users list List organization members
|
|
@@ -113,6 +137,7 @@ require('./commands/user-groups').register(program);
|
|
|
113
137
|
require('./commands/tools').register(program);
|
|
114
138
|
require('./commands/setup').register(program);
|
|
115
139
|
require('./commands/discover').register(program);
|
|
140
|
+
require('./commands/onboard').register(program);
|
|
116
141
|
|
|
117
142
|
// config command for managing CLI settings
|
|
118
143
|
const configCmd = program
|