@sechroom/cli 2026.6.7 → 2026.6.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/dist/index.js +51 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -393,6 +393,46 @@ async function promptSelect(question, choices, def) {
|
|
|
393
393
|
rl.close();
|
|
394
394
|
}
|
|
395
395
|
}
|
|
396
|
+
async function promptMultiSelect(question, choices, preselected = []) {
|
|
397
|
+
if (choices.length === 0) return [];
|
|
398
|
+
const pre = (v) => preselected.includes(v);
|
|
399
|
+
const preValues = () => choices.filter((c) => pre(c.value)).map((c) => c.value);
|
|
400
|
+
if (!canPrompt()) return preValues();
|
|
401
|
+
const { createInterface } = await import("readline");
|
|
402
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
403
|
+
try {
|
|
404
|
+
process.stderr.write(
|
|
405
|
+
`${style.bold(question)} ${style.dim("(numbers or 'all', comma-separated; Enter keeps \u25C9)")}
|
|
406
|
+
`
|
|
407
|
+
);
|
|
408
|
+
choices.forEach((c, i) => {
|
|
409
|
+
const box = pre(c.value) ? style.cyan("\u25C9") : "\u25CB";
|
|
410
|
+
const hint = c.hint ? ` ${style.dim(`\u2014 ${c.hint}`)}` : "";
|
|
411
|
+
process.stderr.write(` ${box} ${style.bold(String(i + 1))}. ${c.label}${hint}
|
|
412
|
+
`);
|
|
413
|
+
});
|
|
414
|
+
const answer = await new Promise((resolve) => {
|
|
415
|
+
rl.question(`Select ${style.dim("[Enter = \u25C9]")} `, resolve);
|
|
416
|
+
});
|
|
417
|
+
const trimmed = answer.trim().toLowerCase();
|
|
418
|
+
if (!trimmed) return preValues();
|
|
419
|
+
if (trimmed === "all") return choices.map((c) => c.value);
|
|
420
|
+
const picks = [];
|
|
421
|
+
for (const tok of trimmed.split(",").map((t) => t.trim()).filter(Boolean)) {
|
|
422
|
+
const n = Number(tok);
|
|
423
|
+
if (Number.isInteger(n) && n >= 1 && n <= choices.length) {
|
|
424
|
+
picks.push(choices[n - 1].value);
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
const byLabel = choices.find((c) => c.label.toLowerCase().startsWith(tok));
|
|
428
|
+
if (byLabel) picks.push(byLabel.value);
|
|
429
|
+
}
|
|
430
|
+
const uniq = [...new Set(picks)];
|
|
431
|
+
return uniq.length > 0 ? uniq : preValues();
|
|
432
|
+
} finally {
|
|
433
|
+
rl.close();
|
|
434
|
+
}
|
|
435
|
+
}
|
|
396
436
|
async function withSpinner(text, fn) {
|
|
397
437
|
const s = spinner(text);
|
|
398
438
|
try {
|
|
@@ -1053,16 +1093,18 @@ async function ensureTimezone(cfg, opts) {
|
|
|
1053
1093
|
async function chooseClients(clientFlag, yes, cwd) {
|
|
1054
1094
|
if (clientFlag) return resolveClientKeys(clientFlag);
|
|
1055
1095
|
const detected = detectInstalledClients(cwd);
|
|
1056
|
-
const
|
|
1057
|
-
if (!canPrompt() || yes) return
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1096
|
+
const preselected = detected.length > 0 ? detected : [DEFAULT_CLIENT_KEY];
|
|
1097
|
+
if (!canPrompt() || yes) return preselected;
|
|
1098
|
+
const picks = await promptMultiSelect(
|
|
1099
|
+
"Which AI clients should I wire?",
|
|
1100
|
+
ALL_CLIENT_KEYS.map((k) => ({
|
|
1101
|
+
label: k,
|
|
1102
|
+
value: k,
|
|
1103
|
+
hint: detected.includes(k) ? "detected" : void 0
|
|
1104
|
+
})),
|
|
1105
|
+
preselected
|
|
1063
1106
|
);
|
|
1064
|
-
|
|
1065
|
-
return resolveClientKeys(answer);
|
|
1107
|
+
return picks.length > 0 ? picks : preselected;
|
|
1066
1108
|
}
|
|
1067
1109
|
function registerOnboard(program2) {
|
|
1068
1110
|
program2.command("onboard").description("Guided first-run setup: configure, sign in, set timezone, detect clients, and wire this project").option("--client <list>", `comma-separated clients (${ALL_CLIENT_KEYS.join(", ")}) or 'all' (default: auto-detected)`).option("--local", "save tenant + base URL to a directory-local .sechroom.json instead of the global config", false).option("--cli-only", "configure the CLI only \u2014 don't wire any AI client (no MCP config, no agent files)", false).option("--no-mcp", "skip the MCP server config (.mcp.json etc.); still write the agent instruction files").option("--copy", "make a personal copy of the agent instructions you can edit (default: prompt on a TTY, else skip)").option("--dry-run", "walk through without writing files or changing the profile", false).option("-y, --yes", "non-interactive: accept defaults (system timezone, detected clients, global config, full wire)", false).addHelpText(
|
package/package.json
CHANGED