@telepath-computer/television 0.1.189 → 0.1.191

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/cli.cjs CHANGED
@@ -51781,6 +51781,71 @@ function pad2(value) {
51781
51781
  return String(value).padStart(2, "0");
51782
51782
  }
51783
51783
 
51784
+ // ../server/src/startup-bind-failure.ts
51785
+ var STARTUP_BIND_EXIT_STATUS = 69;
51786
+ var IPV4_OCTET_COUNT = 4;
51787
+ var CGNAT_SECOND_OCTET_MIN = 64;
51788
+ var CGNAT_SECOND_OCTET_MAX = 127;
51789
+ var StartupBindError = class extends Error {
51790
+ exitStatus = STARTUP_BIND_EXIT_STATUS;
51791
+ constructor(attempts) {
51792
+ const failures = attempts.filter((attempt) => attempt.outcome === "failed").map((attempt) => `${attempt.address}:${attempt.port} (${attempt.error.message})`).join(", ");
51793
+ super(`Television could not bind all required listeners: ${failures}`);
51794
+ this.name = "StartupBindError";
51795
+ }
51796
+ };
51797
+ function buildStartupBindFailureRecord(attempts) {
51798
+ return {
51799
+ reason: "required-listener-bind-failed",
51800
+ exitStatus: STARTUP_BIND_EXIT_STATUS,
51801
+ outcomes: attempts.map((attempt) => {
51802
+ if (attempt.outcome === "bound") return attempt;
51803
+ const serializedError = serializeError(attempt.error);
51804
+ const code = typeof serializedError.code === "string" ? serializedError.code : void 0;
51805
+ return {
51806
+ address: attempt.address,
51807
+ port: attempt.port,
51808
+ outcome: attempt.outcome,
51809
+ ...code === void 0 ? {} : { code },
51810
+ ...typeof serializedError.syscall === "string" ? { syscall: serializedError.syscall } : {},
51811
+ cause: bindFailureCause(attempt, code),
51812
+ hint: bindFailureHint(attempt, code)
51813
+ };
51814
+ })
51815
+ };
51816
+ }
51817
+ function bindFailureCause(attempt, code) {
51818
+ if (code === "EADDRNOTAVAIL") {
51819
+ return `Cannot bind ${attempt.address}:${attempt.port} because the address is not assigned to this host.`;
51820
+ }
51821
+ if (code === "EADDRINUSE") {
51822
+ return `Cannot bind ${attempt.address}:${attempt.port} because the address and port are already in use.`;
51823
+ }
51824
+ if (code === "EACCES" || code === "EPERM") {
51825
+ return `Cannot bind ${attempt.address}:${attempt.port} because the process does not have permission.`;
51826
+ }
51827
+ return `Cannot bind ${attempt.address}:${attempt.port}: ${attempt.error.message}`;
51828
+ }
51829
+ function bindFailureHint(attempt, code) {
51830
+ if (code === "EADDRNOTAVAIL" && isCgnatAddress(attempt.address)) {
51831
+ return `Address ${attempt.address} is not assigned to any interface. If this is a Tailscale IP, tailscaled may not be up yet (transient at boot), or the tailnet IP may have changed (permanent until \`tv serve --persist\` is re-run to refresh the configured address). The service manager will retry.`;
51832
+ }
51833
+ if (code === "EADDRNOTAVAIL") {
51834
+ return `Confirm that ${attempt.address} is assigned to a local interface, then retry.`;
51835
+ }
51836
+ if (code === "EADDRINUSE") {
51837
+ return `Stop the process using ${attempt.address}:${attempt.port}, or choose another port, then retry.`;
51838
+ }
51839
+ if (code === "EACCES" || code === "EPERM") {
51840
+ return "Choose an address and port this process is permitted to bind, then retry.";
51841
+ }
51842
+ return "Check that the address and port are available, then retry.";
51843
+ }
51844
+ function isCgnatAddress(address) {
51845
+ const octets = address.split(".").map(Number);
51846
+ return octets.length === IPV4_OCTET_COUNT && octets[0] === 100 && octets[1] !== void 0 && octets[1] >= CGNAT_SECOND_OCTET_MIN && octets[1] <= CGNAT_SECOND_OCTET_MAX;
51847
+ }
51848
+
51784
51849
  // ../server/src/telemetry/emitters.ts
51785
51850
  var MEDIAN_PAIR_DIVISOR = 2;
51786
51851
  function createServerStoreTelemetryHooks(store, capture2) {
@@ -52493,7 +52558,7 @@ function disabledTelemetryRuntime() {
52493
52558
 
52494
52559
  // ../server/src/updates/version.ts
52495
52560
  function readVersionStamp() {
52496
- if ("0.1.189".length > 0) return "0.1.189";
52561
+ if ("0.1.191".length > 0) return "0.1.191";
52497
52562
  return void 0;
52498
52563
  }
52499
52564
  function resolveUpdateReleaseVersion(env = process.env, stamp = readVersionStamp()) {
@@ -52672,7 +52737,6 @@ var Server = class {
52672
52737
  authMode;
52673
52738
  bindAddresses;
52674
52739
  telemetryOptions;
52675
- bindFailures = [];
52676
52740
  telemetryRuntime = null;
52677
52741
  updateChannel = null;
52678
52742
  listeningPort;
@@ -52776,9 +52840,11 @@ var Server = class {
52776
52840
  }
52777
52841
  }
52778
52842
  async start() {
52779
- this.bindFailures.length = 0;
52780
52843
  this.baseURLs = [];
52781
52844
  let resolvedPort = this.port;
52845
+ const attempts = [];
52846
+ const boundServers = [];
52847
+ const pendingBaseURLs = [];
52782
52848
  for (const [index, server] of this.httpServers.entries()) {
52783
52849
  const address = this.bindAddresses[index];
52784
52850
  const port = index === 0 ? this.port : resolvedPort;
@@ -52788,21 +52854,26 @@ var Server = class {
52788
52854
  if (typeof serverAddress === "object" && serverAddress) {
52789
52855
  resolvedPort = serverAddress.port;
52790
52856
  }
52791
- this.listeningPort = resolvedPort;
52792
52857
  const baseURL = buildServerURL(address, resolvedPort);
52793
- this.baseURLs.push(baseURL);
52794
- log(this.store.storagePath, `bound ${address}:${resolvedPort}`, { address, port: resolvedPort, baseURL });
52858
+ attempts.push({ address, port: resolvedPort, outcome: "bound" });
52859
+ boundServers.push(server);
52860
+ pendingBaseURLs.push(baseURL);
52795
52861
  } catch (error48) {
52796
52862
  const bindError = error48 instanceof Error ? error48 : new Error(String(error48));
52797
- this.bindFailures.push({ address, port, error: bindError });
52863
+ attempts.push({ address, port, outcome: "failed", error: bindError });
52798
52864
  console.error(`Television failed to bind ${address}:${port}: ${bindError.message}`);
52799
- log(this.store.storagePath, `bind failed on ${address}:${port}`, { address, port, error: bindError });
52800
52865
  }
52801
52866
  }
52802
- if (this.baseURLs.length === 0) {
52803
- const message = `Television failed to bind every requested address: ${this.bindFailures.map((failure) => `${failure.address}:${failure.port} (${failure.error.message})`).join(", ")}`;
52804
- log(this.store.storagePath, message, { reason: "all bind addresses failed", snapshot: this.configurationSnapshot() });
52805
- throw new Error(message);
52867
+ if (attempts.some((attempt) => attempt.outcome === "failed")) {
52868
+ log(this.store.storagePath, "server startup failed", buildStartupBindFailureRecord(attempts));
52869
+ await Promise.allSettled(boundServers.map((server) => this.closeServer(server)));
52870
+ throw new StartupBindError(attempts);
52871
+ }
52872
+ this.listeningPort = resolvedPort;
52873
+ this.baseURLs = pendingBaseURLs;
52874
+ for (const [index, baseURL] of this.baseURLs.entries()) {
52875
+ const address = this.bindAddresses[index];
52876
+ log(this.store.storagePath, `bound ${address}:${resolvedPort}`, { address, port: resolvedPort, baseURL });
52806
52877
  }
52807
52878
  await this.startTelemetry();
52808
52879
  this.startUpdateChannel();
@@ -52828,9 +52899,6 @@ var Server = class {
52828
52899
  getBaseURLs() {
52829
52900
  return [...this.baseURLs];
52830
52901
  }
52831
- getBindFailures() {
52832
- return [...this.bindFailures];
52833
- }
52834
52902
  getAuthToken() {
52835
52903
  return this.store.authToken;
52836
52904
  }
@@ -52953,11 +53021,6 @@ var Server = class {
52953
53021
  port: this.getListeningPort(),
52954
53022
  bindAddresses: this.bindAddresses,
52955
53023
  boundURLs: this.baseURLs,
52956
- bindFailures: this.bindFailures.map((failure) => ({
52957
- address: failure.address,
52958
- port: failure.port,
52959
- error: serializeError(failure.error)
52960
- })),
52961
53024
  authMode: this.authMode
52962
53025
  };
52963
53026
  }
@@ -52995,8 +53058,8 @@ var Server = class {
52995
53058
  };
52996
53059
  };
52997
53060
  function readServerPackageVersion() {
52998
- if ("0.1.189".length > 0) {
52999
- return telemetryVersion("0.1.189");
53061
+ if ("0.1.191".length > 0) {
53062
+ return telemetryVersion("0.1.191");
53000
53063
  }
53001
53064
  const packageJsonPath = import_node_path11.default.resolve(import_node_path11.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url)), "..", "package.json");
53002
53065
  if (!(0, import_node_fs9.existsSync)(packageJsonPath)) return telemetryVersion("0.0.0");
@@ -54513,6 +54576,7 @@ var DAEMON_NAME = "com.television.server";
54513
54576
  var TELEMETRY_LAUNCH_MODE_ENV = "TELEVISION_LAUNCH_MODE";
54514
54577
  var SKILL_INSTALL_TELEMETRY_TIMEOUT_MS2 = 1e3;
54515
54578
  var MAX_PORT = 65535;
54579
+ var MAX_PROCESS_EXIT_STATUS = 255;
54516
54580
  var HTTP_UNAUTHORIZED_STATUS2 = 401;
54517
54581
  var HELP_POINTER = "Television ships bundled skills. The main skill is `television` \u2014 keep its guidance available for screens, lifecycle, the `tv` CLI, and artifact workflow. Re-read it only if it is not already in context or you know the installed skill changed. Additional `tv-*` skills cover specialized artifact types and theming. Install all bundled skills with `tv skills install <path>` (e.g. ~/.openclaw/skills) or `tv skills install -i`.";
54518
54582
  var CLIDirectiveError = class extends Error {
@@ -54572,8 +54636,8 @@ function resolveVercelSkillsInstallerBin() {
54572
54636
  return localRequire.resolve("skills/bin/cli.mjs");
54573
54637
  }
54574
54638
  function readCLIVersion() {
54575
- if ("0.1.189".length > 0) {
54576
- return "0.1.189";
54639
+ if ("0.1.191".length > 0) {
54640
+ return "0.1.191";
54577
54641
  }
54578
54642
  const devPackageJsonPath = import_node_path17.default.join(getDevPackageDir(), "package.json");
54579
54643
  if (!(0, import_node_fs14.existsSync)(devPackageJsonPath)) {
@@ -54634,6 +54698,11 @@ function storagePathFromArgv(argv) {
54634
54698
  }
54635
54699
  return void 0;
54636
54700
  }
54701
+ function exitStatusFromError(error48) {
54702
+ if (typeof error48 !== "object" || error48 === null || !("exitStatus" in error48)) return void 0;
54703
+ const exitStatus = error48.exitStatus;
54704
+ return typeof exitStatus === "number" && Number.isInteger(exitStatus) && exitStatus > 0 && exitStatus <= MAX_PROCESS_EXIT_STATUS ? exitStatus : void 0;
54705
+ }
54637
54706
  function formatCLIError(error48, argv = []) {
54638
54707
  if (error48 instanceof CLIDirectiveError) {
54639
54708
  return error48.message;
@@ -55325,7 +55394,7 @@ async function runCLI(argv, environment = {}) {
55325
55394
  }
55326
55395
  env.stderr.write(`${formatCLIError(error48, argv)}
55327
55396
  `);
55328
- return 1;
55397
+ return exitStatusFromError(error48) ?? 1;
55329
55398
  }
55330
55399
  }
55331
55400
  if (!isVitestRuntime()) {