@tiny-fish/cli 0.29.1-next.239 → 0.29.1-next.240

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.
@@ -210,6 +210,10 @@ async function processHarness(detection, opts, prompt, oauthBudget, hoistedCliIn
210
210
  if (spentBrowserSlot && e instanceof ConnectStepError && NO_BROWSER_REASONS.has(e.failureReason)) {
211
211
  oauthBudget.spent = false;
212
212
  }
213
+ // Detection saw a name on PATH; the probe proved nothing is behind it.
214
+ if (e instanceof ConnectStepError && e.failureReason === "harness_not_installed") {
215
+ return { ...base, detected: false, outcome: "not_detected" };
216
+ }
213
217
  // Both reasons carry the same "flag not listed" message; the upgrade nudge is in it.
214
218
  if (e instanceof ConnectStepError && TOO_OLD_REASONS.has(e.failureReason)) {
215
219
  return {
@@ -268,9 +272,6 @@ function summaryLine(result, uninstall) {
268
272
  ? `… ${name} — ${result.errorMessage}. Finish it in a terminal: ${result.fixCommand}`
269
273
  : `… ${name} — needs a browser sign-in. Run in a terminal: ${result.fixCommand}`;
270
274
  }
271
- if (result.outcome === "deselected") {
272
- return `… ${name} — skipped, not selected. Fix: ${result.fixCommand}`;
273
- }
274
275
  if (result.outcome === "uninstall_pointer") {
275
276
  return `… ${name} — not removed automatically (config is owned by ${name}). Run: ${result.fixCommand}`;
276
277
  }
@@ -307,6 +308,20 @@ function summaryLine(result, uninstall) {
307
308
  }
308
309
  return `✓ ${name} — installed, ${verifyLabel}`;
309
310
  }
311
+ /** Absent and unpicked harnesses are noise once something real happened. */
312
+ function renderSummary(results, uninstall) {
313
+ if (!results.some(actionable))
314
+ return results.map((r) => summaryLine(r, uninstall));
315
+ // Ids, not display names: they double as the `connect` argument.
316
+ const skipped = results.filter((r) => r.outcome === "deselected").map((r) => r.harness);
317
+ const lines = results
318
+ .filter((r) => r.outcome !== "deselected" && r.outcome !== "not_detected")
319
+ .map((r) => summaryLine(r, uninstall));
320
+ if (skipped.length === 0)
321
+ return lines;
322
+ lines.push("", `Skipped (not selected): ${skipped.join(", ")}`);
323
+ return lines;
324
+ }
310
325
  /** A config-writing connect needs no binary; every other harness spawns one. */
311
326
  function isStaleConfig(detection) {
312
327
  return (detection.detected &&
@@ -475,7 +490,9 @@ export async function runConnectAll(opts) {
475
490
  const outro = new Set();
476
491
  const results = [];
477
492
  const oauthBudget = { spent: false };
478
- const stepTotal = detections.length - deselected.size;
493
+ // Mirrors processHarness's own short-circuits: absent has no work, stale only when removing.
494
+ const stepped = (d) => !deselected.has(d.harness) && d.detected && (opts.uninstall || !isStaleConfig(d));
495
+ const stepTotal = detections.filter(stepped).length;
479
496
  let step = 0;
480
497
  for (const detection of detections) {
481
498
  const { harness } = detection;
@@ -488,6 +505,9 @@ export async function runConnectAll(opts) {
488
505
  });
489
506
  continue;
490
507
  }
508
+ // The pad loop below records these; announcing them is the noise this command had.
509
+ if (!stepped(detection))
510
+ continue;
491
511
  step += 1;
492
512
  errLine(`step ${step} of ${stepTotal} — ${DISPLAY_NAMES[harness]}`);
493
513
  let result;
@@ -533,8 +553,8 @@ export async function runConnectAll(opts) {
533
553
  }
534
554
  outLine("");
535
555
  outLine("TinyFish setup summary:");
536
- for (const result of results)
537
- outLine(summaryLine(result, opts.uninstall));
556
+ for (const line of renderSummary(results, opts.uninstall))
557
+ outLine(line);
538
558
  // Before the launch handover: anything printed after it is never seen.
539
559
  for (const line of outro)
540
560
  errLine(line);
@@ -137,7 +137,8 @@ export function requireCommandSupport(client) {
137
137
  env: { ...process.env, FORCE_COLOR: "0", NO_COLOR: "1" },
138
138
  timeout: NON_INTERACTIVE_TIMEOUT_MS,
139
139
  });
140
- if (commandNotFound(result.error)) {
140
+ // 127 is the shell's not-found code; a wrapper shim with no real binary behind it exits that.
141
+ if (commandNotFound(result.error) || result.status === 127) {
141
142
  throw new PrerequisiteError(`${client.displayName} is not installed or not available on PATH.`, "harness_not_installed", { cause: result.error });
142
143
  }
143
144
  if (result.error || result.status !== 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiny-fish/cli",
3
- "version": "0.29.1-next.239",
3
+ "version": "0.29.1-next.240",
4
4
  "description": "TinyFish CLI — run web automations from your terminal",
5
5
  "type": "module",
6
6
  "bin": {