@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.
Files changed (2) hide show
  1. package/dist/index.js +51 -9
  2. 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 fallback = (detected.length > 0 ? detected : [DEFAULT_CLIENT_KEY]).join(",");
1057
- if (!canPrompt() || yes) return resolveClientKeys(fallback);
1058
- process.stderr.write(
1059
- `
1060
- Available clients: ${ALL_CLIENT_KEYS.join(", ")}
1061
- ` + (detected.length > 0 ? `Detected on this machine: ${detected.join(", ")}
1062
- ` : "No clients auto-detected.\n")
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
- const answer = await promptText("Which to wire? (comma-separated, or 'all')", fallback);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sechroom/cli",
3
- "version": "2026.6.7",
3
+ "version": "2026.6.8",
4
4
  "description": "Sechroom CLI — a thin, generated client over the Sechroom HTTP API. An agent/human surface alongside MCP.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",