@bli-cockpit/cli 0.1.7 → 0.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.
@@ -89,7 +89,7 @@ function localSubcommandHelp(command) {
89
89
  "",
90
90
  "Installs, pairs, starts work context(s), syncs once, and prints readiness proof.",
91
91
  "If --repo is a parent folder, scans child git repos/worktrees and rolls them up by repo.",
92
- "Use --email on shared or reused machines; mismatched existing sessions are re-paired.",
92
+ "Run with no flags in a terminal and it prompts for the dashboard email; pass --email to skip the prompt (and on shared/reused machines, where mismatched sessions are re-paired).",
93
93
  ],
94
94
  ],
95
95
  [
@@ -469,6 +469,38 @@ async function runInstall(command, io) {
469
469
  writeLine(io.stdout, "Next: run `cockpit login`, then `cockpit start` inside the repo; add `--ticket <id>` only when ticket work begins.");
470
470
  return 0;
471
471
  }
472
+ function isInteractiveStdin(io) {
473
+ return Boolean(io.stdin.isTTY);
474
+ }
475
+ /**
476
+ * Reads one line from stdin so `cockpit onboard` (no flags) can ask for the
477
+ * dashboard email instead of forcing a `--email` flag. Only called when stdin
478
+ * is a TTY and we're not in --json mode, so headless / piped / spawned runs
479
+ * never block on input — they keep the existing behaviour (email optional; the
480
+ * approving admin's account owns the device). An empty answer or a non-email
481
+ * skips rather than failing, matching `optionalEmail`'s leniency.
482
+ */
483
+ async function promptOnboardEmail(io) {
484
+ io.stdout.write("Dashboard email (press enter to skip): ");
485
+ io.stdin.setEncoding("utf8");
486
+ const raw = await new Promise((resolve) => {
487
+ const onData = (chunk) => {
488
+ io.stdin.removeListener("data", onData);
489
+ io.stdin.pause();
490
+ resolve(chunk);
491
+ };
492
+ io.stdin.resume();
493
+ io.stdin.on("data", onData);
494
+ });
495
+ const answer = raw.trim().toLowerCase();
496
+ if (!answer)
497
+ return undefined;
498
+ if (!answer.includes("@")) {
499
+ writeLine(io.stderr, `"${answer}" is not an email; continuing without one — the approving admin's account will own this device.`);
500
+ return undefined;
501
+ }
502
+ return answer;
503
+ }
472
504
  async function runOnboard(command, io) {
473
505
  let install = null;
474
506
  let pair = null;
@@ -480,6 +512,10 @@ async function runOnboard(command, io) {
480
512
  writeLine(io.stdout, `Dashboard: ${command.dashboardUrl}`);
481
513
  writeLine(io.stdout, `Ticket: ${command.activeTicketId ?? "general ambient"}`);
482
514
  }
515
+ let claimedOwnerEmail = command.claimedOwnerEmail;
516
+ if (!claimedOwnerEmail && !command.json && isInteractiveStdin(io)) {
517
+ claimedOwnerEmail = await promptOnboardEmail(io);
518
+ }
483
519
  install = await installLocalCollector({
484
520
  homeDir: command.homeDir,
485
521
  repoRoot: command.repoRoot,
@@ -496,7 +532,7 @@ async function runOnboard(command, io) {
496
532
  branch: command.branch,
497
533
  });
498
534
  const installedSession = await readOnboardSessionReuseCandidate(command.homeDir);
499
- const canReuseInstalledSession = canReuseOnboardSession(installedSession, command.claimedOwnerEmail, command.dashboardUrl);
535
+ const canReuseInstalledSession = canReuseOnboardSession(installedSession, claimedOwnerEmail, command.dashboardUrl);
500
536
  if (installedStatus.session_state === "valid" && canReuseInstalledSession) {
501
537
  if (!command.json) {
502
538
  writeLine(io.stdout, "2/5 Existing valid device session found; pairing skipped.");
@@ -512,7 +548,7 @@ async function runOnboard(command, io) {
512
548
  pair = await pairLocalCollector({
513
549
  homeDir: command.homeDir,
514
550
  dashboardUrl: command.dashboardUrl,
515
- claimedOwnerEmail: command.claimedOwnerEmail,
551
+ claimedOwnerEmail,
516
552
  deviceName: command.deviceName,
517
553
  pollIntervalMs: command.pollIntervalMs,
518
554
  timeoutMs: command.timeoutMs,
@@ -5,8 +5,8 @@ import os from "node:os";
5
5
  import path from "node:path";
6
6
  import { resolveRepoWorktreeIdentity, } from "./repo-identity.js";
7
7
  import { summarizeLocalUploadSpool } from "./spool/local-spool.js";
8
- export const LOCAL_COLLECTOR_VERSION = "0.1.7";
9
- export const DEFAULT_DASHBOARD_URL = "http://127.0.0.1:3100";
8
+ export const LOCAL_COLLECTOR_VERSION = "0.1.8";
9
+ export const DEFAULT_DASHBOARD_URL = "https://bli-cockpit-dashboard.vercel.app";
10
10
  export function getCollectorRuntimePaths(homeDir = os.homedir()) {
11
11
  const paths = getUserLocalCockpitPaths(homeDir);
12
12
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bli-cockpit/cli",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {