windscout 0.3.0 → 0.4.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/README.md CHANGED
@@ -74,6 +74,7 @@ windscout -t 40 -a # longer connect timeout, also list
74
74
  | `-t, --timeout` | seconds to wait for each connection | 20 |
75
75
  | `-a, --all` | include failed attempts in the final table | off |
76
76
  | `-n, --no-speed` | connect-only mode: skip the download test, rank by latency | saved, or off |
77
+ | `-v, --version` | print the installed version, and the update command if a newer one is on npm | |
77
78
 
78
79
  ## Connect-only mode
79
80
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "windscout",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Find which Windscribe locations and protocols work from your network, ranked by speed (unofficial)",
5
5
  "type": "module",
6
6
  "bin": {
package/windscout.js CHANGED
@@ -175,6 +175,8 @@ const updateNotice = () => `update available: ${VERSION} → ${update} · run: $
175
175
 
176
176
  const color = (code, s) => (process.env.NO_COLOR || !process.stdout.isTTY ? s : `\x1b[${code}m${s}\x1b[0m`);
177
177
  const bold = (s) => color(1, s), dim = (s) => color(2, s), green = (s) => color(32, s);
178
+ // underline off (24) instead of a full reset, so it nests inside dim/bold
179
+ const under = (s) => (process.env.NO_COLOR || !process.stdout.isTTY ? s : `\x1b[4m${s}\x1b[24m`);
178
180
  const cyan = (s) => color(36, s), yellow = (s) => color(33, s), red = (s) => color(31, s);
179
181
  const fmt = (v, digits) => (v === null || v === undefined ? "-" : v.toFixed(digits));
180
182
  const list = (s) => s.split(",").map((x) => x.trim()).filter(Boolean);
@@ -271,9 +273,12 @@ function matrix(results, protocols, { minWidth = 0, limit = Infinity } = {}) {
271
273
  const reachable = ranked.filter((c) => c.good).length;
272
274
  const rows = ranked.slice(0, limit).map(({ q, rs }) => {
273
275
  const seen = rs.find((r) => r.status === "ok") ?? rs.find((r) => r.location);
276
+ // nickname = exact datacenter; protocols can land on different ones, so list each that connected
277
+ const nicks = [...new Set(rs.filter((r) => r.status === "ok").map((r) => r.location.split(" - ")[1]).filter(Boolean))];
274
278
  return [
275
279
  `${flag(q)} ${countryName(q)}`,
276
280
  seen?.location?.split(" - ")[0] || dim("-"),
281
+ nicks.join(", ") || dim("-"),
277
282
  ...protocols.map((p) => {
278
283
  const r = rs.find((x) => x.protocol === p);
279
284
  return !r ? dim("·") : r.status === "ok" ? green("✓") : red("✗");
@@ -281,13 +286,13 @@ function matrix(results, protocols, { minWidth = 0, limit = Infinity } = {}) {
281
286
  ];
282
287
  });
283
288
  return grid(
284
- [{ title: "Country" }, { title: "City" }, ...protocols.map((p) => ({ title: p, align: "center" }))],
289
+ [{ title: "Country" }, { title: "City" }, { title: "Location" }, ...protocols.map((p) => ({ title: p, align: "center" }))],
285
290
  rows,
286
291
  {
287
292
  caption: bold("Availability"),
288
293
  captionRight: dim(`${reachable}/${ranked.length} countries reachable${ranked.length > limit ? ` · top ${limit}` : ""}`),
289
294
  minWidth,
290
- stretch: 1,
295
+ stretch: 2,
291
296
  },
292
297
  );
293
298
  }
@@ -409,8 +414,8 @@ function pick(saved, timeout) {
409
414
  top = Math.max(0, Math.min(top, list.length - height));
410
415
 
411
416
  const protoLine = PROTOCOLS.map((p, i) =>
412
- `${dim(String(i + 1))} ${protos.has(p) ? green("● " + p) : dim("○ " + p)}`).join(" ");
413
- const speedLine = `${dim("s")} ${speedTest ? green("● speed test") : dim("○ speed test")} ${dim(speedTest
417
+ `${dim(under(String(i + 1)))} ${protos.has(p) ? green("● " + p) : dim("○ " + p)}`).join(" ");
418
+ const speedLine = `${dim(under("s"))} ${speedTest ? green("● speed test") : dim("○ speed test")} ${dim(speedTest
414
419
  ? "ranks by download speed · adds ~15s per working connection"
415
420
  : "off: connect-only, ranks by latency")}`;
416
421
  const search = searching
@@ -425,7 +430,7 @@ function pick(saved, timeout) {
425
430
  return [`${here ? cyan("❯") : " "} ${mark}`, here ? bold(code) : dim(code), here ? bold(cyan(name)) : name];
426
431
  });
427
432
  if (!body.length) body.push([" ", "", dim("no country matches")]);
428
- const buttons = [["start", "▶ Start"], ["all", query ? "All shown" : "All"], ["none", query ? "None shown" : "None"], ["quit", "Quit"]];
433
+ const buttons = [["start", "▶ Start"], ["all", under("A") + (query ? "ll shown" : "ll")], ["none", under("N") + (query ? "one shown" : "one")], ["quit", under("Q") + "uit"]];
429
434
  const buttonLine = buttons.map(([id, label]) => (id === "start" ? bold(cyan(`[ ${label} ]`)) : dim(`[ ${label} ]`))).join(" ");
430
435
 
431
436
  const table = grid([{ title: "" }, { title: "Code" }, { title: "Country" }], body,
@@ -754,6 +759,7 @@ Options:
754
759
  -t, --timeout SEC seconds to wait for each connection (default: 20)
755
760
  -a, --all also show failed attempts in the final table
756
761
  -n, --no-speed connect-only: skip the download test, rank by latency (faster scan)
762
+ -v, --version show the installed version (and whether a newer one is out)
757
763
  -h, --help show this help
758
764
 
759
765
  Selection is stored in ${CONFIG}
@@ -767,11 +773,17 @@ async function main() {
767
773
  timeout: { type: "string", short: "t", default: "20" },
768
774
  all: { type: "boolean", short: "a", default: false },
769
775
  help: { type: "boolean", short: "h", default: false },
776
+ version: { type: "boolean", short: "v", default: false },
770
777
  "no-speed": { type: "boolean", short: "n", default: false },
771
778
  },
772
779
  });
773
780
  if (a.help) return console.log(HELP);
774
781
  updateCheck = checkUpdate(); // runs while the app starts and the user picks, before the VPN starts switching
782
+ if (a.version) {
783
+ console.log(`windscout ${VERSION}`);
784
+ await updateCheck;
785
+ return update && console.error(yellow(updateNotice()));
786
+ }
775
787
  const timeout = Number(a.timeout);
776
788
  if (!(timeout > 0)) throw new Error("--timeout must be a positive number");
777
789
 
@@ -789,7 +801,7 @@ async function main() {
789
801
  if (!tty) throw new Error("no terminal for the picker: pass countries with -c");
790
802
  const saved = loadConfig();
791
803
  if (protocols && saved) saved.protocols = protocols.filter((p) => PROTOCOLS.includes(p));
792
- speedTest = !a["no-speed"] && (saved?.speed ?? true);
804
+ speedTest = !a["no-speed"] && (saved?.speed ?? false); // first run: connect-only
793
805
  const choice = await pick(saved, timeout);
794
806
  if (!choice) return;
795
807
  countries = choice.countries;