unbound-cli 1.1.6 → 1.1.8
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
CHANGED
package/src/commands/discover.js
CHANGED
|
@@ -11,6 +11,13 @@ const LAUNCH_AGENT_LABEL = 'ai.getunbound.discovery';
|
|
|
11
11
|
// (e.g. Linux). Treated as a skipped scan, not a failure.
|
|
12
12
|
const DISCOVERY_EXIT_UNSUPPORTED_OS = 3;
|
|
13
13
|
|
|
14
|
+
// Self-imposed discovery run timeout (seconds), forwarded through install.sh to
|
|
15
|
+
// the discovery process so `unbound onboard` / `unbound discover` can't hang
|
|
16
|
+
// indefinitely. Discovery enforces this itself — on expiry it releases its lock,
|
|
17
|
+
// reports the run as failed, and exits non-zero. Kept in sync with
|
|
18
|
+
// setup/mdm/onboard.py's DISCOVERY_TIMEOUT_SECONDS.
|
|
19
|
+
const DISCOVERY_TIMEOUT_SECONDS = 1800;
|
|
20
|
+
|
|
14
21
|
// Classifies a discovery subprocess exit code:
|
|
15
22
|
// 'success' (scan ran), 'unsupported' (skipped on this OS), or 'failure'.
|
|
16
23
|
function classifyDiscoveryExit(code) {
|
|
@@ -146,7 +153,16 @@ async function runDiscoveryScan({ apiKey, domain }) {
|
|
|
146
153
|
console.log('');
|
|
147
154
|
}
|
|
148
155
|
|
|
156
|
+
// Don't pass --timeout: install.sh is fetched from coding-discovery-tool/main,
|
|
157
|
+
// and an older discovery there would reject the unknown flag (argparse exits
|
|
158
|
+
// non-zero) and fail the scan. Discovery self-bounds via its own default (kept
|
|
159
|
+
// equal to DISCOVERY_TIMEOUT_SECONDS), so this is correct regardless of merge
|
|
160
|
+
// order. Surface the bound so the wait isn't a mystery; on expiry the discovery
|
|
161
|
+
// process prints its own line (stdio is inherited) and exits non-zero.
|
|
149
162
|
const args = `--api-key ${shellEscape(apiKey)} --domain ${shellEscape(domain)}`;
|
|
163
|
+
if (!isWindowsNative()) {
|
|
164
|
+
output.info(`Discovery stops on its own after ${Math.round(DISCOVERY_TIMEOUT_SECONDS / 60)} minutes if it can't finish.`);
|
|
165
|
+
}
|
|
150
166
|
await runDiscoveryScript('install.sh', args);
|
|
151
167
|
}
|
|
152
168
|
|
package/src/commands/onboard.js
CHANGED
|
@@ -221,9 +221,11 @@ Examples:
|
|
|
221
221
|
// user's explicit --*-url flag.
|
|
222
222
|
const written = config.setUrls({
|
|
223
223
|
backend: opts.backendUrl,
|
|
224
|
+
frontend: opts.frontendUrl,
|
|
224
225
|
gateway: opts.gatewayUrl,
|
|
225
226
|
});
|
|
226
227
|
const backendUrl = written.base_url || config.getBaseUrl();
|
|
228
|
+
const frontendUrl = written.frontend_url || config.getFrontendUrl();
|
|
227
229
|
const gatewayUrl = written.gateway_url || config.getGatewayUrl();
|
|
228
230
|
discoveryDomain = opts.domain || backendUrl;
|
|
229
231
|
|
|
@@ -240,7 +242,7 @@ Examples:
|
|
|
240
242
|
console.log('');
|
|
241
243
|
output.info('Step 1/2: Installing MDM tool bundle');
|
|
242
244
|
const { ok, skipped } = await runMdmSetupAllBundle(adminApiKey, {
|
|
243
|
-
backendUrl, gatewayUrl, backfill: !!opts.backfill,
|
|
245
|
+
backendUrl, frontendUrl, gatewayUrl, backfill: !!opts.backfill,
|
|
244
246
|
});
|
|
245
247
|
if (!ok) return;
|
|
246
248
|
setupSucceeded = true;
|
package/src/commands/setup.js
CHANGED
|
@@ -241,8 +241,9 @@ async function runPythonScriptWindows(scriptPath, args, { capture }) {
|
|
|
241
241
|
/**
|
|
242
242
|
* Builds the shared argv tail for setup.py invocations. Always passes the
|
|
243
243
|
* tenant URL flags so the script's behavior is not sensitive to drift in its
|
|
244
|
-
* own defaults.
|
|
245
|
-
*
|
|
244
|
+
* own defaults. The frontend URL goes to non-MDM scripts as --domain (also
|
|
245
|
+
* their browser-auth host) and to MDM scripts as --frontend-url (persist-only,
|
|
246
|
+
* no auth flow). Either way it lands in ~/.unbound/config.json as frontend_url.
|
|
246
247
|
*/
|
|
247
248
|
function buildScriptArgs(apiKey, { backendUrl, frontendUrl, gatewayUrl, clear, mdm, backfill } = {}) {
|
|
248
249
|
// --clear runs no auth in the Python scripts, so the key may be absent. Omit
|
|
@@ -250,7 +251,7 @@ function buildScriptArgs(apiKey, { backendUrl, frontendUrl, gatewayUrl, clear, m
|
|
|
250
251
|
let args = apiKey ? `--api-key ${shellEscape(apiKey)}` : '';
|
|
251
252
|
if (backendUrl) args += ` --backend-url ${shellEscape(backendUrl)}`;
|
|
252
253
|
if (gatewayUrl) args += ` --gateway-url ${shellEscape(gatewayUrl)}`;
|
|
253
|
-
if (
|
|
254
|
+
if (frontendUrl) args += mdm ? ` --frontend-url ${shellEscape(frontendUrl)}` : ` --domain ${shellEscape(frontendUrl)}`;
|
|
254
255
|
if (clear) args += ' --clear';
|
|
255
256
|
if (backfill) args += ' --backfill';
|
|
256
257
|
return args.trim();
|
|
@@ -819,9 +820,11 @@ Clear examples (no API key required):
|
|
|
819
820
|
// UNBOUND_*_URL can't shadow the explicit --*-url flag.
|
|
820
821
|
const written = config.setUrls({
|
|
821
822
|
backend: globalOpts.backendUrl,
|
|
823
|
+
frontend: globalOpts.frontendUrl,
|
|
822
824
|
gateway: globalOpts.gatewayUrl,
|
|
823
825
|
});
|
|
824
826
|
const backendUrl = written.base_url || config.getBaseUrl();
|
|
827
|
+
const frontendUrl = written.frontend_url || config.getFrontendUrl();
|
|
825
828
|
const gatewayUrl = written.gateway_url || config.getGatewayUrl();
|
|
826
829
|
|
|
827
830
|
if (globalOpts.all && tools.length > 0) {
|
|
@@ -890,6 +893,7 @@ Clear examples (no API key required):
|
|
|
890
893
|
(tool) => {
|
|
891
894
|
const toolArgs = buildScriptArgs(adminApiKey, {
|
|
892
895
|
backendUrl,
|
|
896
|
+
frontendUrl,
|
|
893
897
|
gatewayUrl,
|
|
894
898
|
clear: globalOpts.clear,
|
|
895
899
|
mdm: true,
|
|
@@ -1030,7 +1034,7 @@ async function runSetupAllBundle(apiKey, { backendUrl, frontendUrl, gatewayUrl,
|
|
|
1030
1034
|
* Caller must ensure the process is running as root.
|
|
1031
1035
|
* Returns true on success, false on failure.
|
|
1032
1036
|
*/
|
|
1033
|
-
async function runMdmSetupAllBundle(adminApiKey, { backendUrl, gatewayUrl, backfill = false } = {}) {
|
|
1037
|
+
async function runMdmSetupAllBundle(adminApiKey, { backendUrl, frontendUrl, gatewayUrl, backfill = false } = {}) {
|
|
1034
1038
|
const resolvedTools = MDM_ALL_TOOLS.map(name => ({ name, ...MDM_TOOLS[name] }));
|
|
1035
1039
|
if (backfill) {
|
|
1036
1040
|
for (const tool of resolvedTools) {
|
|
@@ -1039,7 +1043,7 @@ async function runMdmSetupAllBundle(adminApiKey, { backendUrl, gatewayUrl, backf
|
|
|
1039
1043
|
}
|
|
1040
1044
|
return runBatch(resolvedTools, (tool) => {
|
|
1041
1045
|
const args = buildScriptArgs(adminApiKey, {
|
|
1042
|
-
backendUrl, gatewayUrl, mdm: true,
|
|
1046
|
+
backendUrl, frontendUrl, gatewayUrl, mdm: true,
|
|
1043
1047
|
backfill: backfill && scriptSupportsBackfill(tool.script),
|
|
1044
1048
|
});
|
|
1045
1049
|
return runScriptPiped(tool.script, args);
|
package/test/setup-args.test.js
CHANGED
|
@@ -70,14 +70,16 @@ test('scriptSupportsBackfill: cursor and gateway-mode scripts are unsupported',
|
|
|
70
70
|
assert.ok(!scriptSupportsBackfill('gemini-cli/gateway/setup.py'));
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
-
// MDM scripts have no browser-auth flow, so
|
|
74
|
-
//
|
|
75
|
-
|
|
73
|
+
// MDM scripts have no browser-auth flow, so the frontend URL goes via
|
|
74
|
+
// --frontend-url (persist-only), never --domain. It must still be passed so
|
|
75
|
+
// frontend_url lands in each user's ~/.unbound/config.json.
|
|
76
|
+
test('buildScriptArgs: mdm:true passes frontend as --frontend-url, not --domain', () => {
|
|
76
77
|
const args = buildScriptArgs('sk-x', {
|
|
77
78
|
mdm: true,
|
|
78
79
|
frontendUrl: 'https://gateway.acme.com',
|
|
79
80
|
});
|
|
80
81
|
assert.ok(!args.includes('--domain'), args);
|
|
82
|
+
assert.ok(args.includes("--frontend-url 'https://gateway.acme.com'"), args);
|
|
81
83
|
});
|
|
82
84
|
|
|
83
85
|
test('buildScriptArgs: non-mdm includes --domain when frontendUrl passed', () => {
|