@telepath-computer/television 0.1.188 → 0.1.190

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.188".length > 0) return "0.1.188";
52561
+ if ("0.1.190".length > 0) return "0.1.190";
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.188".length > 0) {
52999
- return telemetryVersion("0.1.188");
53061
+ if ("0.1.190".length > 0) {
53062
+ return telemetryVersion("0.1.190");
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");
@@ -53706,16 +53769,21 @@ function isBundledViewID(id) {
53706
53769
  return BUNDLED_VIEW_IDS.has(id);
53707
53770
  }
53708
53771
  function hasExistingTelevisionDataStructure(storagePath) {
53709
- return [
53710
- getDisplayStatePath(storagePath),
53711
- getTokenPath(storagePath),
53712
- getOnboardingStatePath(storagePath),
53713
- getOnboardingArtifactSentinelPath(storagePath),
53714
- getScreensDir(storagePath),
53715
- getArtifactsMetadataDir(storagePath),
53716
- getThemesDir(storagePath),
53717
- getAgentArtifactsDir(storagePath)
53718
- ].some((markerPath) => (0, import_node_fs13.existsSync)(markerPath));
53772
+ if ((0, import_node_fs13.existsSync)(getDisplayStatePath(storagePath))) return true;
53773
+ if ((0, import_node_fs13.existsSync)(getOnboardingStatePath(storagePath))) return true;
53774
+ if ((0, import_node_fs13.existsSync)(getOnboardingArtifactSentinelPath(storagePath))) return true;
53775
+ if (directoryIsNonEmpty(getScreensDir(storagePath))) return true;
53776
+ if (directoryIsNonEmpty(getArtifactsMetadataDir(storagePath))) return true;
53777
+ if (directoryIsNonEmpty(getThemesDir(storagePath))) return true;
53778
+ if (directoryIsNonEmpty(getAgentArtifactsDir(storagePath))) return true;
53779
+ return false;
53780
+ }
53781
+ function directoryIsNonEmpty(dir) {
53782
+ try {
53783
+ return (0, import_node_fs13.readdirSync)(dir).length > 0;
53784
+ } catch {
53785
+ return false;
53786
+ }
53719
53787
  }
53720
53788
  function artifactWatchTarget(artifact) {
53721
53789
  if (artifact.kind === "url") {
@@ -54508,6 +54576,7 @@ var DAEMON_NAME = "com.television.server";
54508
54576
  var TELEMETRY_LAUNCH_MODE_ENV = "TELEVISION_LAUNCH_MODE";
54509
54577
  var SKILL_INSTALL_TELEMETRY_TIMEOUT_MS2 = 1e3;
54510
54578
  var MAX_PORT = 65535;
54579
+ var MAX_PROCESS_EXIT_STATUS = 255;
54511
54580
  var HTTP_UNAUTHORIZED_STATUS2 = 401;
54512
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`.";
54513
54582
  var CLIDirectiveError = class extends Error {
@@ -54567,8 +54636,8 @@ function resolveVercelSkillsInstallerBin() {
54567
54636
  return localRequire.resolve("skills/bin/cli.mjs");
54568
54637
  }
54569
54638
  function readCLIVersion() {
54570
- if ("0.1.188".length > 0) {
54571
- return "0.1.188";
54639
+ if ("0.1.190".length > 0) {
54640
+ return "0.1.190";
54572
54641
  }
54573
54642
  const devPackageJsonPath = import_node_path17.default.join(getDevPackageDir(), "package.json");
54574
54643
  if (!(0, import_node_fs14.existsSync)(devPackageJsonPath)) {
@@ -54629,6 +54698,11 @@ function storagePathFromArgv(argv) {
54629
54698
  }
54630
54699
  return void 0;
54631
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
+ }
54632
54706
  function formatCLIError(error48, argv = []) {
54633
54707
  if (error48 instanceof CLIDirectiveError) {
54634
54708
  return error48.message;
@@ -55320,7 +55394,7 @@ async function runCLI(argv, environment = {}) {
55320
55394
  }
55321
55395
  env.stderr.write(`${formatCLIError(error48, argv)}
55322
55396
  `);
55323
- return 1;
55397
+ return exitStatusFromError(error48) ?? 1;
55324
55398
  }
55325
55399
  }
55326
55400
  if (!isVitestRuntime()) {