@bigbrainforge/setup 3.19.0 → 3.20.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/dist/setup.cjs +153 -79
- package/package.json +1 -1
package/dist/setup.cjs
CHANGED
|
@@ -189,6 +189,21 @@ var require_license = __commonJS({
|
|
|
189
189
|
}
|
|
190
190
|
});
|
|
191
191
|
|
|
192
|
+
// ../forge-plugin/lib/sanitize-terminal.js
|
|
193
|
+
var require_sanitize_terminal = __commonJS({
|
|
194
|
+
"../forge-plugin/lib/sanitize-terminal.js"(exports2, module2) {
|
|
195
|
+
var TERMINAL_CONTROL_RE = (
|
|
196
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: matching control characters is the entire point.
|
|
197
|
+
/[\u0000-\u001F\u007F-\u009F\u00AD\u061C\u200B-\u200F\u2028-\u202E\u2060-\u2064\u2066-\u2069\uFEFF]/g
|
|
198
|
+
);
|
|
199
|
+
function sanitizeForTerminal2(value) {
|
|
200
|
+
const text = value === null || value === void 0 ? "" : String(value);
|
|
201
|
+
return text.replace(TERMINAL_CONTROL_RE, "");
|
|
202
|
+
}
|
|
203
|
+
module2.exports = { sanitizeForTerminal: sanitizeForTerminal2 };
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
|
|
192
207
|
// ../forge-plugin/lib/discover-instance.js
|
|
193
208
|
var require_discover_instance = __commonJS({
|
|
194
209
|
"../forge-plugin/lib/discover-instance.js"(exports2, module2) {
|
|
@@ -196,6 +211,14 @@ var require_discover_instance = __commonJS({
|
|
|
196
211
|
var os2 = require("node:os");
|
|
197
212
|
var path2 = require("node:path");
|
|
198
213
|
var { resolveLicense } = require_license();
|
|
214
|
+
var { sanitizeForTerminal: sanitizeForTerminal2 } = require_sanitize_terminal();
|
|
215
|
+
function failure(reason, hint, extra = {}) {
|
|
216
|
+
const cleaned = {};
|
|
217
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
218
|
+
cleaned[key] = typeof value === "string" ? sanitizeForTerminal2(value) : value;
|
|
219
|
+
}
|
|
220
|
+
return { ok: false, reason, hint: sanitizeForTerminal2(hint), ...cleaned };
|
|
221
|
+
}
|
|
199
222
|
var DEFAULT_LICENSING_URL2 = "https://licensing.bigbrainforge.com";
|
|
200
223
|
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "::1", "[::1]"]);
|
|
201
224
|
function isSecureUrl2(value) {
|
|
@@ -215,17 +238,12 @@ var require_discover_instance = __commonJS({
|
|
|
215
238
|
const parsed = new URL(base);
|
|
216
239
|
scheme = `${parsed.protocol}//${parsed.hostname}`;
|
|
217
240
|
} catch {
|
|
218
|
-
return {
|
|
219
|
-
ok: false,
|
|
220
|
-
reason: "insecure_licensing_url",
|
|
221
|
-
hint: `FORGE_LICENSING_URL is not a valid URL: ${base}`
|
|
222
|
-
};
|
|
241
|
+
return failure("insecure_licensing_url", `FORGE_LICENSING_URL is not a valid URL: ${base}`);
|
|
223
242
|
}
|
|
224
|
-
return
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
};
|
|
243
|
+
return failure(
|
|
244
|
+
"insecure_licensing_url",
|
|
245
|
+
`FORGE_LICENSING_URL must use https:// (got ${scheme}). Plain http:// is allowed only for loopback (127.0.0.1, localhost, ::1) \u2014 refusing to send the license credential in cleartext.`
|
|
246
|
+
);
|
|
229
247
|
}
|
|
230
248
|
function pluginConfigPath(io = {}) {
|
|
231
249
|
const env = io.env ?? process.env;
|
|
@@ -235,7 +253,8 @@ var require_discover_instance = __commonJS({
|
|
|
235
253
|
function readPinnedUrl(io) {
|
|
236
254
|
try {
|
|
237
255
|
const config = JSON.parse(fs.readFileSync(pluginConfigPath(io), "utf8"));
|
|
238
|
-
|
|
256
|
+
const pinned = typeof config.mcp_url === "string" && config.mcp_url.length > 0 ? config.mcp_url : null;
|
|
257
|
+
return pinned === null ? null : sanitizeForTerminal2(pinned);
|
|
239
258
|
} catch {
|
|
240
259
|
return null;
|
|
241
260
|
}
|
|
@@ -276,11 +295,10 @@ var require_discover_instance = __commonJS({
|
|
|
276
295
|
signal: AbortSignal.timeout(15e3)
|
|
277
296
|
});
|
|
278
297
|
} catch {
|
|
279
|
-
return
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
};
|
|
298
|
+
return failure(
|
|
299
|
+
"discovery_unreachable",
|
|
300
|
+
`licensing service unreachable \u2014 check network egress to ${base}`
|
|
301
|
+
);
|
|
284
302
|
}
|
|
285
303
|
let body = {};
|
|
286
304
|
try {
|
|
@@ -289,43 +307,39 @@ var require_discover_instance = __commonJS({
|
|
|
289
307
|
body = {};
|
|
290
308
|
}
|
|
291
309
|
if (response.status === 401) {
|
|
292
|
-
return
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
};
|
|
310
|
+
return failure(
|
|
311
|
+
"license_invalid",
|
|
312
|
+
body.error || "unknown or revoked license \u2014 contact your org admin"
|
|
313
|
+
);
|
|
297
314
|
}
|
|
298
315
|
if (!response.ok || typeof body.instance_url !== "string" || body.instance_url.length === 0) {
|
|
299
|
-
return
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
};
|
|
316
|
+
return failure(
|
|
317
|
+
"discovery_unreachable",
|
|
318
|
+
`discovery failed (HTTP ${response.status}) at ${base}/license/discover`
|
|
319
|
+
);
|
|
304
320
|
}
|
|
305
321
|
return {
|
|
306
322
|
ok: true,
|
|
307
|
-
instance_url: body.instance_url.replace(/\/$/, ""),
|
|
308
|
-
deployment_model: body.deployment_model
|
|
323
|
+
instance_url: sanitizeForTerminal2(body.instance_url).replace(/\/$/, ""),
|
|
324
|
+
deployment_model: body.deployment_model === null || body.deployment_model === void 0 ? null : sanitizeForTerminal2(body.deployment_model)
|
|
309
325
|
};
|
|
310
326
|
}
|
|
311
327
|
function checkPinConflict(pinned, discovered, acceptNewInstance) {
|
|
312
328
|
if (!pinned || sameHost(pinned, discovered) || acceptNewInstance === true) {
|
|
313
329
|
return null;
|
|
314
330
|
}
|
|
315
|
-
return
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
pinned_url: pinned,
|
|
319
|
-
|
|
320
|
-
hint: `discovery returned ${discovered} but this machine is pinned to ${pinned}. Refusing to release the license to a new host. If the change is expected (your org migrated instances), re-run with --accept-new-instance.`
|
|
321
|
-
};
|
|
331
|
+
return failure(
|
|
332
|
+
"pin_conflict",
|
|
333
|
+
`discovery returned ${discovered} but this machine is pinned to ${pinned}. Refusing to release the license to a new host. If the change is expected (your org migrated instances), re-run with --accept-new-instance.`,
|
|
334
|
+
{ pinned_url: pinned, discovered_url: discovered }
|
|
335
|
+
);
|
|
322
336
|
}
|
|
323
337
|
async function discoverInstance2(io = {}) {
|
|
324
338
|
const env = io.env ?? process.env;
|
|
325
339
|
const doFetch = io.fetchImpl ?? fetch;
|
|
326
340
|
const license = resolveLicense(io);
|
|
327
341
|
if (license.value === null) {
|
|
328
|
-
return
|
|
342
|
+
return failure("no_license", license.hint);
|
|
329
343
|
}
|
|
330
344
|
const pinned = readPinnedUrl(io);
|
|
331
345
|
if (pinned && io.forceDiscovery !== true) {
|
|
@@ -342,11 +356,10 @@ var require_discover_instance = __commonJS({
|
|
|
342
356
|
}
|
|
343
357
|
const { instance_url: discovered, deployment_model: deploymentModel } = discovery;
|
|
344
358
|
if (!isSecureUrl2(discovered)) {
|
|
345
|
-
return
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
};
|
|
359
|
+
return failure(
|
|
360
|
+
"insecure_instance_url",
|
|
361
|
+
`discovery returned an insecure instance_url (${discovered}) \u2014 refusing to pin it. The instance must be served over https:// (plain http:// is allowed only for loopback), so the license is never exchanged over a cleartext connection.`
|
|
362
|
+
);
|
|
350
363
|
}
|
|
351
364
|
const conflict = checkPinConflict(pinned, discovered, io.acceptNewInstance);
|
|
352
365
|
if (conflict) {
|
|
@@ -355,7 +368,7 @@ var require_discover_instance = __commonJS({
|
|
|
355
368
|
if (!pinned || !sameHost(pinned, discovered)) {
|
|
356
369
|
const pinResult = pinInstanceUrl(io, discovered);
|
|
357
370
|
if (!pinResult.ok) {
|
|
358
|
-
return
|
|
371
|
+
return failure("discovery_unreachable", pinResult.error);
|
|
359
372
|
}
|
|
360
373
|
}
|
|
361
374
|
return {
|
|
@@ -911,6 +924,22 @@ var require_exec_cli = __commonJS({
|
|
|
911
924
|
}
|
|
912
925
|
});
|
|
913
926
|
|
|
927
|
+
// ../forge-plugin/lib/prompt-abort.js
|
|
928
|
+
var require_prompt_abort = __commonJS({
|
|
929
|
+
"../forge-plugin/lib/prompt-abort.js"(exports2, module2) {
|
|
930
|
+
var PROMPT_ABORTED = "PROMPT_ABORTED";
|
|
931
|
+
function promptAbortError2(what = "prompt") {
|
|
932
|
+
const err = new Error(`${what} aborted (Ctrl-C or end of input).`);
|
|
933
|
+
err.code = PROMPT_ABORTED;
|
|
934
|
+
return err;
|
|
935
|
+
}
|
|
936
|
+
function isPromptAbort2(err) {
|
|
937
|
+
return Boolean(err) && err.code === PROMPT_ABORTED;
|
|
938
|
+
}
|
|
939
|
+
module2.exports = { PROMPT_ABORTED, promptAbortError: promptAbortError2, isPromptAbort: isPromptAbort2 };
|
|
940
|
+
}
|
|
941
|
+
});
|
|
942
|
+
|
|
914
943
|
// src/setup.js
|
|
915
944
|
var os = require("node:os");
|
|
916
945
|
var path = require("node:path");
|
|
@@ -924,6 +953,8 @@ var {
|
|
|
924
953
|
assertSafeVersion
|
|
925
954
|
} = require_plugin_bundle();
|
|
926
955
|
var { resolveSpawn } = require_exec_cli();
|
|
956
|
+
var { sanitizeForTerminal } = require_sanitize_terminal();
|
|
957
|
+
var { isPromptAbort, promptAbortError } = require_prompt_abort();
|
|
927
958
|
var LICENSE_RE = /^forge_lic_[0-9A-Za-z]{43}$/;
|
|
928
959
|
var DEFAULT_LICENSING_URL = "https://licensing.bigbrainforge.com";
|
|
929
960
|
var DEFAULT_DIST_URL = "https://licensing.bigbrainforge.com";
|
|
@@ -937,26 +968,52 @@ function runShim(io, cmd, args) {
|
|
|
937
968
|
function errMessage(err) {
|
|
938
969
|
return err && err.message ? err.message : String(err);
|
|
939
970
|
}
|
|
971
|
+
async function promptHidden(q, { input = process.stdin, output = process.stdout } = {}) {
|
|
972
|
+
const readline = require("node:readline");
|
|
973
|
+
return new Promise((res, rej) => {
|
|
974
|
+
const rl = readline.createInterface({ input, output, terminal: true });
|
|
975
|
+
let settled = false;
|
|
976
|
+
rl.on("close", () => {
|
|
977
|
+
if (settled) return;
|
|
978
|
+
settled = true;
|
|
979
|
+
output.write("\n");
|
|
980
|
+
rej(promptAbortError("license prompt"));
|
|
981
|
+
});
|
|
982
|
+
const orig = rl._writeToOutput.bind(rl);
|
|
983
|
+
const columnsAt = (k) => {
|
|
984
|
+
const saved = rl.cursor;
|
|
985
|
+
rl.cursor = k;
|
|
986
|
+
const pos = rl.getCursorPos();
|
|
987
|
+
rl.cursor = saved;
|
|
988
|
+
return pos.rows === 0 ? pos.cols : pos.rows * rl.columns + pos.cols;
|
|
989
|
+
};
|
|
990
|
+
rl._writeToOutput = (s) => {
|
|
991
|
+
if (s.includes("\n") || s.includes("\r")) return orig("");
|
|
992
|
+
if (s.startsWith(q)) {
|
|
993
|
+
return orig(q + "*".repeat(Math.max(0, columnsAt(rl.line.length) - columnsAt(0))));
|
|
994
|
+
}
|
|
995
|
+
const end = rl.cursor;
|
|
996
|
+
const start = Math.max(0, end - s.length);
|
|
997
|
+
if (rl.line.slice(start, end) === s) {
|
|
998
|
+
return orig("*".repeat(Math.max(0, columnsAt(end) - columnsAt(start))));
|
|
999
|
+
}
|
|
1000
|
+
return orig(s.replace(/[^ ]/g, "*"));
|
|
1001
|
+
};
|
|
1002
|
+
rl.question(q, (a) => {
|
|
1003
|
+
settled = true;
|
|
1004
|
+
rl.close();
|
|
1005
|
+
output.write("\n");
|
|
1006
|
+
res(a.trim());
|
|
1007
|
+
});
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
940
1010
|
function defaultIo() {
|
|
941
1011
|
return {
|
|
942
1012
|
homedir: os.homedir(),
|
|
943
1013
|
env: process.env,
|
|
944
1014
|
print: (l) => process.stdout.write(`${l}
|
|
945
1015
|
`),
|
|
946
|
-
promptHidden:
|
|
947
|
-
const readline = require("node:readline");
|
|
948
|
-
return new Promise((res) => {
|
|
949
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
950
|
-
const orig = rl._writeToOutput.bind(rl);
|
|
951
|
-
rl._writeToOutput = (s) => s.includes("\n") || s === q ? orig(s) : orig("");
|
|
952
|
-
process.stdout.write(q);
|
|
953
|
-
rl.question("", (a) => {
|
|
954
|
-
rl.close();
|
|
955
|
-
process.stdout.write("\n");
|
|
956
|
-
res(a.trim());
|
|
957
|
-
});
|
|
958
|
-
});
|
|
959
|
-
},
|
|
1016
|
+
promptHidden: (q) => promptHidden(q),
|
|
960
1017
|
fetch: (url, opts) => globalThis.fetch(url, opts),
|
|
961
1018
|
run: (cmd, args = [], opts = {}) => {
|
|
962
1019
|
const { stdio, ...rest } = opts;
|
|
@@ -969,15 +1026,19 @@ function defaultIo() {
|
|
|
969
1026
|
}
|
|
970
1027
|
};
|
|
971
1028
|
}
|
|
1029
|
+
function say(io, line) {
|
|
1030
|
+
io.print(sanitizeForTerminal(line));
|
|
1031
|
+
}
|
|
972
1032
|
function fail(io, tier, message, fix) {
|
|
973
|
-
io
|
|
974
|
-
io
|
|
975
|
-
if (fix) io
|
|
1033
|
+
say(io, "");
|
|
1034
|
+
say(io, `\u2717 [${tier}] ${message}`);
|
|
1035
|
+
if (fix) say(io, ` fix: ${fix}`);
|
|
976
1036
|
return 1;
|
|
977
1037
|
}
|
|
978
1038
|
async function runSetup(argv, io = defaultIo()) {
|
|
979
1039
|
const args = argv.filter((a) => !a.startsWith("--"));
|
|
980
1040
|
const acceptNewInstance = argv.includes("--accept-new-instance");
|
|
1041
|
+
const print = (line) => say(io, line);
|
|
981
1042
|
const tarProbe = io.run("tar", ["--version"]);
|
|
982
1043
|
if (tarProbe.error || tarProbe.status !== 0) {
|
|
983
1044
|
return fail(
|
|
@@ -988,7 +1049,19 @@ async function runSetup(argv, io = defaultIo()) {
|
|
|
988
1049
|
);
|
|
989
1050
|
}
|
|
990
1051
|
let license = args[0] ?? "";
|
|
991
|
-
if (!license)
|
|
1052
|
+
if (!license) {
|
|
1053
|
+
try {
|
|
1054
|
+
license = await io.promptHidden("Paste your Forge license: ");
|
|
1055
|
+
} catch (err) {
|
|
1056
|
+
if (!isPromptAbort(err)) throw err;
|
|
1057
|
+
return fail(
|
|
1058
|
+
io,
|
|
1059
|
+
"credential",
|
|
1060
|
+
"setup was cancelled at the license prompt \u2014 nothing on this machine was changed",
|
|
1061
|
+
`rerun when you have the license to hand: ${RERUN_SETUP_CMD}`
|
|
1062
|
+
);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
992
1065
|
if (!LICENSE_RE.test(license)) {
|
|
993
1066
|
return fail(
|
|
994
1067
|
io,
|
|
@@ -1006,11 +1079,12 @@ async function runSetup(argv, io = defaultIo()) {
|
|
|
1006
1079
|
`fix the named problem (usually permissions on ~/.claude/forge), then rerun: ${RERUN_SETUP_CMD}`
|
|
1007
1080
|
);
|
|
1008
1081
|
}
|
|
1009
|
-
|
|
1082
|
+
print(`\u2713 license stored (${wrote.path})`);
|
|
1010
1083
|
const licensingUrl = io.env.FORGE_LICENSING_URL || DEFAULT_LICENSING_URL;
|
|
1011
1084
|
const discoveryFetch = async (url, opts) => {
|
|
1012
1085
|
const res = await io.fetch(url, opts);
|
|
1013
|
-
|
|
1086
|
+
if (res.ok !== void 0) return res;
|
|
1087
|
+
return { ...res, ok: res.status >= 200 && res.status < 300 };
|
|
1014
1088
|
};
|
|
1015
1089
|
const discovered = await discoverInstance({
|
|
1016
1090
|
homedir: io.homedir,
|
|
@@ -1034,7 +1108,7 @@ async function runSetup(argv, io = defaultIo()) {
|
|
|
1034
1108
|
) : `check network egress to ${licensingUrl} (it must be on your allowlist)`
|
|
1035
1109
|
);
|
|
1036
1110
|
}
|
|
1037
|
-
|
|
1111
|
+
print(`\u2713 instance pinned: ${discovered.instance_url} (${discovered.deployment_model})`);
|
|
1038
1112
|
let npmrc;
|
|
1039
1113
|
try {
|
|
1040
1114
|
npmrc = writeNpmrcLicense(license, { homedir: io.homedir, env: io.env });
|
|
@@ -1048,11 +1122,11 @@ async function runSetup(argv, io = defaultIo()) {
|
|
|
1048
1122
|
}
|
|
1049
1123
|
if (npmrc.status === "declined") {
|
|
1050
1124
|
const legacyNote = npmrc.replacedLegacy ? " (a legacy npm.pkg.github.com credential line found alongside it was removed)" : "";
|
|
1051
|
-
|
|
1125
|
+
print(
|
|
1052
1126
|
npmrc.foreignScopeTarget === "" ? `! npm NOT seeded \u2014 ~/.npmrc has a malformed @bigbrainforge:registry= line (no value). Fix or remove that line, then rerun setup; otherwise no action is needed.${legacyNote}` : `! npm NOT seeded \u2014 @bigbrainforge:registry already points at ${npmrc.foreignScopeTarget} (an enterprise proxy or other custom config). If that isn't your organization's proxy, remove that line from ~/.npmrc and rerun setup; otherwise no action is needed.${legacyNote}`
|
|
1053
1127
|
);
|
|
1054
1128
|
} else {
|
|
1055
|
-
|
|
1129
|
+
print(
|
|
1056
1130
|
npmrc.status === "seeded" ? `\u2713 npm seeded (${npmrc.path})${npmrc.replacedLegacy ? " \u2014 legacy GitHub Packages lines replaced" : ""}` : `\u2713 npm already seeded (${npmrc.path}) \u2014 no change needed`
|
|
1057
1131
|
);
|
|
1058
1132
|
}
|
|
@@ -1148,7 +1222,7 @@ async function runSetup(argv, io = defaultIo()) {
|
|
|
1148
1222
|
`the download may be corrupted or tampered \u2014 rerun to retry: ${RERUN_SETUP_CMD} (if it persists, contact your Forge administrator)`
|
|
1149
1223
|
);
|
|
1150
1224
|
}
|
|
1151
|
-
|
|
1225
|
+
print(`\u2713 plugin bundle ${manifest.version} verified (sha256) and staged at ${staged.target}`);
|
|
1152
1226
|
const root = bundleRoot(io.homedir);
|
|
1153
1227
|
const addRes = runShim(io, "claude", ["plugin", "marketplace", "add", root]);
|
|
1154
1228
|
const installRes = addRes.status === 0 ? runShim(io, "claude", ["plugin", "install", "forge@forge"]) : addRes;
|
|
@@ -1157,19 +1231,19 @@ async function runSetup(argv, io = defaultIo()) {
|
|
|
1157
1231
|
${installRes.stderr || ""}`
|
|
1158
1232
|
);
|
|
1159
1233
|
if (addRes.status === 0 && installRes.status === 0) {
|
|
1160
|
-
|
|
1234
|
+
print("\u2713 plugin installed from the local Forge marketplace");
|
|
1161
1235
|
} else if (alreadyRegistered) {
|
|
1162
|
-
|
|
1236
|
+
print("\u2713 plugin already installed from the local Forge marketplace \u2014 nothing to do");
|
|
1163
1237
|
} else {
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1238
|
+
print("");
|
|
1239
|
+
print("! Claude Code CLI not reachable from this shell \u2014 run these two commands yourself:");
|
|
1240
|
+
print("");
|
|
1241
|
+
print(` claude plugin marketplace add "${root}"`);
|
|
1242
|
+
print(" claude plugin install forge@forge");
|
|
1243
|
+
print("");
|
|
1170
1244
|
}
|
|
1171
1245
|
const bundledBootstrap = path.join(staged.target, "scripts", "bootstrap.js");
|
|
1172
|
-
|
|
1246
|
+
print("Handing off to the Forge plugin bootstrap (server check + issue tracker)\u2026");
|
|
1173
1247
|
const hand = io.run(process.execPath, [bundledBootstrap], { stdio: "inherit" });
|
|
1174
1248
|
if (hand.status !== 0) {
|
|
1175
1249
|
return fail(
|
|
@@ -1179,15 +1253,15 @@ ${installRes.stderr || ""}`
|
|
|
1179
1253
|
`rerun it yourself: node "${bundledBootstrap}"`
|
|
1180
1254
|
);
|
|
1181
1255
|
}
|
|
1182
|
-
|
|
1183
|
-
|
|
1256
|
+
print("");
|
|
1257
|
+
print("Done. Open Claude Code \u2014 Forge is ready.");
|
|
1184
1258
|
return 0;
|
|
1185
1259
|
}
|
|
1186
|
-
module.exports = { runSetup, LICENSE_RE, defaultIo, RERUN_SETUP_CMD };
|
|
1260
|
+
module.exports = { runSetup, LICENSE_RE, defaultIo, promptHidden, RERUN_SETUP_CMD };
|
|
1187
1261
|
if (require.main === module) {
|
|
1188
1262
|
runSetup(process.argv.slice(2)).then((code) => process.exit(code)).catch((err) => {
|
|
1189
1263
|
process.stderr.write(`
|
|
1190
|
-
\u2717 [unexpected] ${errMessage(err)}
|
|
1264
|
+
\u2717 [unexpected] ${sanitizeForTerminal(errMessage(err))}
|
|
1191
1265
|
`);
|
|
1192
1266
|
process.stderr.write(
|
|
1193
1267
|
" fix: this is unexpected \u2014 please report it (including this message) to your Forge administrator\n"
|
package/package.json
CHANGED