@telepath-computer/television 0.1.169 → 0.1.171

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
@@ -1194,7 +1194,7 @@ var require_command = __commonJS({
1194
1194
  "../../node_modules/commander/lib/command.js"(exports2) {
1195
1195
  var EventEmitter2 = require("node:events").EventEmitter;
1196
1196
  var childProcess = require("node:child_process");
1197
- var path12 = require("node:path");
1197
+ var path15 = require("node:path");
1198
1198
  var fs4 = require("node:fs");
1199
1199
  var process3 = require("node:process");
1200
1200
  var { Argument: Argument2, humanReadableArgName } = require_argument();
@@ -2207,9 +2207,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
2207
2207
  let launchWithNode = false;
2208
2208
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
2209
2209
  function findFile(baseDir, baseName) {
2210
- const localBin = path12.resolve(baseDir, baseName);
2210
+ const localBin = path15.resolve(baseDir, baseName);
2211
2211
  if (fs4.existsSync(localBin)) return localBin;
2212
- if (sourceExt.includes(path12.extname(baseName))) return void 0;
2212
+ if (sourceExt.includes(path15.extname(baseName))) return void 0;
2213
2213
  const foundExt = sourceExt.find(
2214
2214
  (ext) => fs4.existsSync(`${localBin}${ext}`)
2215
2215
  );
@@ -2227,17 +2227,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
2227
2227
  } catch {
2228
2228
  resolvedScriptPath = this._scriptPath;
2229
2229
  }
2230
- executableDir = path12.resolve(
2231
- path12.dirname(resolvedScriptPath),
2230
+ executableDir = path15.resolve(
2231
+ path15.dirname(resolvedScriptPath),
2232
2232
  executableDir
2233
2233
  );
2234
2234
  }
2235
2235
  if (executableDir) {
2236
2236
  let localFile = findFile(executableDir, executableFile);
2237
2237
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
2238
- const legacyName = path12.basename(
2238
+ const legacyName = path15.basename(
2239
2239
  this._scriptPath,
2240
- path12.extname(this._scriptPath)
2240
+ path15.extname(this._scriptPath)
2241
2241
  );
2242
2242
  if (legacyName !== this._name) {
2243
2243
  localFile = findFile(
@@ -2248,7 +2248,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2248
2248
  }
2249
2249
  executableFile = localFile || executableFile;
2250
2250
  }
2251
- launchWithNode = sourceExt.includes(path12.extname(executableFile));
2251
+ launchWithNode = sourceExt.includes(path15.extname(executableFile));
2252
2252
  let proc;
2253
2253
  if (process3.platform !== "win32") {
2254
2254
  if (launchWithNode) {
@@ -3163,7 +3163,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
3163
3163
  * @return {Command}
3164
3164
  */
3165
3165
  nameFromFilename(filename) {
3166
- this._name = path12.basename(filename, path12.extname(filename));
3166
+ this._name = path15.basename(filename, path15.extname(filename));
3167
3167
  return this;
3168
3168
  }
3169
3169
  /**
@@ -3177,9 +3177,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
3177
3177
  * @param {string} [path]
3178
3178
  * @return {(string|null|Command)}
3179
3179
  */
3180
- executableDir(path13) {
3181
- if (path13 === void 0) return this._executableDir;
3182
- this._executableDir = path13;
3180
+ executableDir(path16) {
3181
+ if (path16 === void 0) return this._executableDir;
3182
+ this._executableDir = path16;
3183
3183
  return this;
3184
3184
  }
3185
3185
  /**
@@ -21480,11 +21480,11 @@ var require_mime_types = __commonJS({
21480
21480
  }
21481
21481
  return exts[0];
21482
21482
  }
21483
- function lookup(path12) {
21484
- if (!path12 || typeof path12 !== "string") {
21483
+ function lookup(path15) {
21484
+ if (!path15 || typeof path15 !== "string") {
21485
21485
  return false;
21486
21486
  }
21487
- var extension3 = extname("x." + path12).toLowerCase().substr(1);
21487
+ var extension3 = extname("x." + path15).toLowerCase().substr(1);
21488
21488
  if (!extension3) {
21489
21489
  return false;
21490
21490
  }
@@ -24221,7 +24221,7 @@ var require_path_to_regexp = __commonJS({
24221
24221
  "../../node_modules/path-to-regexp/index.js"(exports2, module2) {
24222
24222
  module2.exports = pathToRegexp;
24223
24223
  var MATCHING_GROUP_REGEXP = /\\.|\((?:\?<(.*?)>)?(?!\?)/g;
24224
- function pathToRegexp(path12, keys, options) {
24224
+ function pathToRegexp(path15, keys, options) {
24225
24225
  options = options || {};
24226
24226
  keys = keys || [];
24227
24227
  var strict = options.strict;
@@ -24235,8 +24235,8 @@ var require_path_to_regexp = __commonJS({
24235
24235
  var pos = 0;
24236
24236
  var backtrack = "";
24237
24237
  var m2;
24238
- if (path12 instanceof RegExp) {
24239
- while (m2 = MATCHING_GROUP_REGEXP.exec(path12.source)) {
24238
+ if (path15 instanceof RegExp) {
24239
+ while (m2 = MATCHING_GROUP_REGEXP.exec(path15.source)) {
24240
24240
  if (m2[0][0] === "\\") continue;
24241
24241
  keys.push({
24242
24242
  name: m2[1] || name++,
@@ -24244,20 +24244,20 @@ var require_path_to_regexp = __commonJS({
24244
24244
  offset: m2.index
24245
24245
  });
24246
24246
  }
24247
- return path12;
24247
+ return path15;
24248
24248
  }
24249
- if (Array.isArray(path12)) {
24250
- path12 = path12.map(function(value) {
24249
+ if (Array.isArray(path15)) {
24250
+ path15 = path15.map(function(value) {
24251
24251
  return pathToRegexp(value, keys, options).source;
24252
24252
  });
24253
- return new RegExp(path12.join("|"), flags);
24253
+ return new RegExp(path15.join("|"), flags);
24254
24254
  }
24255
- if (typeof path12 !== "string") {
24255
+ if (typeof path15 !== "string") {
24256
24256
  throw new TypeError("path must be a string, array of strings, or regular expression");
24257
24257
  }
24258
- path12 = path12.replace(
24258
+ path15 = path15.replace(
24259
24259
  /\\.|(\/)?(\.)?:(\w+)(\(.*?\))?(\*)?(\?)?|[.*]|\/\(/g,
24260
- function(match, slash, format, key, capture, star, optional2, offset) {
24260
+ function(match, slash, format, key, capture2, star, optional2, offset) {
24261
24261
  if (match[0] === "\\") {
24262
24262
  backtrack += match;
24263
24263
  pos += 2;
@@ -24272,7 +24272,7 @@ var require_path_to_regexp = __commonJS({
24272
24272
  if (slash || format) {
24273
24273
  backtrack = "";
24274
24274
  } else {
24275
- backtrack += path12.slice(pos, offset);
24275
+ backtrack += path15.slice(pos, offset);
24276
24276
  }
24277
24277
  pos = offset + match.length;
24278
24278
  if (match === "*") {
@@ -24288,7 +24288,7 @@ var require_path_to_regexp = __commonJS({
24288
24288
  slash = slash || "";
24289
24289
  format = format ? "\\." : "";
24290
24290
  optional2 = optional2 || "";
24291
- capture = capture ? capture.replace(/\\.|\*/, function(m3) {
24291
+ capture2 = capture2 ? capture2.replace(/\\.|\*/, function(m3) {
24292
24292
  return m3 === "*" ? "(.*)" : m3;
24293
24293
  }) : backtrack ? "((?:(?!/|" + backtrack + ").)+?)" : "([^/" + format + "]+?)";
24294
24294
  keys.push({
@@ -24296,13 +24296,13 @@ var require_path_to_regexp = __commonJS({
24296
24296
  optional: !!optional2,
24297
24297
  offset: offset + extraOffset
24298
24298
  });
24299
- var result = "(?:" + format + slash + capture + (star ? "((?:[/" + format + "].+?)?)" : "") + ")" + optional2;
24299
+ var result = "(?:" + format + slash + capture2 + (star ? "((?:[/" + format + "].+?)?)" : "") + ")" + optional2;
24300
24300
  backtrack = "";
24301
24301
  extraOffset += result.length - match.length;
24302
24302
  return result;
24303
24303
  }
24304
24304
  );
24305
- while (m2 = MATCHING_GROUP_REGEXP.exec(path12)) {
24305
+ while (m2 = MATCHING_GROUP_REGEXP.exec(path15)) {
24306
24306
  if (m2[0][0] === "\\") continue;
24307
24307
  if (keysOffset + i === keys.length || keys[keysOffset + i].offset > m2.index) {
24308
24308
  keys.splice(keysOffset + i, 0, {
@@ -24314,13 +24314,13 @@ var require_path_to_regexp = __commonJS({
24314
24314
  }
24315
24315
  i++;
24316
24316
  }
24317
- path12 += strict ? "" : path12[path12.length - 1] === "/" ? "?" : "/?";
24317
+ path15 += strict ? "" : path15[path15.length - 1] === "/" ? "?" : "/?";
24318
24318
  if (end) {
24319
- path12 += "$";
24320
- } else if (path12[path12.length - 1] !== "/") {
24321
- path12 += lookahead ? "(?=/|$)" : "(?:/|$)";
24319
+ path15 += "$";
24320
+ } else if (path15[path15.length - 1] !== "/") {
24321
+ path15 += lookahead ? "(?=/|$)" : "(?:/|$)";
24322
24322
  }
24323
- return new RegExp("^" + path12, flags);
24323
+ return new RegExp("^" + path15, flags);
24324
24324
  }
24325
24325
  }
24326
24326
  });
@@ -24333,19 +24333,19 @@ var require_layer = __commonJS({
24333
24333
  var debug = require_src3()("express:router:layer");
24334
24334
  var hasOwnProperty = Object.prototype.hasOwnProperty;
24335
24335
  module2.exports = Layer;
24336
- function Layer(path12, options, fn) {
24336
+ function Layer(path15, options, fn) {
24337
24337
  if (!(this instanceof Layer)) {
24338
- return new Layer(path12, options, fn);
24338
+ return new Layer(path15, options, fn);
24339
24339
  }
24340
- debug("new %o", path12);
24340
+ debug("new %o", path15);
24341
24341
  var opts = options || {};
24342
24342
  this.handle = fn;
24343
24343
  this.name = fn.name || "<anonymous>";
24344
24344
  this.params = void 0;
24345
24345
  this.path = void 0;
24346
- this.regexp = pathRegexp(path12, this.keys = [], opts);
24347
- this.regexp.fast_star = path12 === "*";
24348
- this.regexp.fast_slash = path12 === "/" && opts.end === false;
24346
+ this.regexp = pathRegexp(path15, this.keys = [], opts);
24347
+ this.regexp.fast_star = path15 === "*";
24348
+ this.regexp.fast_slash = path15 === "/" && opts.end === false;
24349
24349
  }
24350
24350
  Layer.prototype.handle_error = function handle_error(error48, req, res, next) {
24351
24351
  var fn = this.handle;
@@ -24369,20 +24369,20 @@ var require_layer = __commonJS({
24369
24369
  next(err);
24370
24370
  }
24371
24371
  };
24372
- Layer.prototype.match = function match(path12) {
24372
+ Layer.prototype.match = function match(path15) {
24373
24373
  var match2;
24374
- if (path12 != null) {
24374
+ if (path15 != null) {
24375
24375
  if (this.regexp.fast_slash) {
24376
24376
  this.params = {};
24377
24377
  this.path = "";
24378
24378
  return true;
24379
24379
  }
24380
24380
  if (this.regexp.fast_star) {
24381
- this.params = { "0": decode_param(path12) };
24382
- this.path = path12;
24381
+ this.params = { "0": decode_param(path15) };
24382
+ this.path = path15;
24383
24383
  return true;
24384
24384
  }
24385
- match2 = this.regexp.exec(path12);
24385
+ match2 = this.regexp.exec(path15);
24386
24386
  }
24387
24387
  if (!match2) {
24388
24388
  this.params = void 0;
@@ -24475,10 +24475,10 @@ var require_route = __commonJS({
24475
24475
  var slice = Array.prototype.slice;
24476
24476
  var toString = Object.prototype.toString;
24477
24477
  module2.exports = Route;
24478
- function Route(path12) {
24479
- this.path = path12;
24478
+ function Route(path15) {
24479
+ this.path = path15;
24480
24480
  this.stack = [];
24481
- debug("new %o", path12);
24481
+ debug("new %o", path15);
24482
24482
  this.methods = {};
24483
24483
  }
24484
24484
  Route.prototype._handles_method = function _handles_method(method) {
@@ -24690,8 +24690,8 @@ var require_router = __commonJS({
24690
24690
  if (++sync > 100) {
24691
24691
  return setImmediate(next, err);
24692
24692
  }
24693
- var path12 = getPathname(req);
24694
- if (path12 == null) {
24693
+ var path15 = getPathname(req);
24694
+ if (path15 == null) {
24695
24695
  return done(layerError);
24696
24696
  }
24697
24697
  var layer;
@@ -24699,7 +24699,7 @@ var require_router = __commonJS({
24699
24699
  var route;
24700
24700
  while (match !== true && idx < stack.length) {
24701
24701
  layer = stack[idx++];
24702
- match = matchLayer(layer, path12);
24702
+ match = matchLayer(layer, path15);
24703
24703
  route = layer.route;
24704
24704
  if (typeof match !== "boolean") {
24705
24705
  layerError = layerError || match;
@@ -24737,18 +24737,18 @@ var require_router = __commonJS({
24737
24737
  } else if (route) {
24738
24738
  layer.handle_request(req, res, next);
24739
24739
  } else {
24740
- trim_prefix(layer, layerError, layerPath, path12);
24740
+ trim_prefix(layer, layerError, layerPath, path15);
24741
24741
  }
24742
24742
  sync = 0;
24743
24743
  });
24744
24744
  }
24745
- function trim_prefix(layer, layerError, layerPath, path12) {
24745
+ function trim_prefix(layer, layerError, layerPath, path15) {
24746
24746
  if (layerPath.length !== 0) {
24747
- if (layerPath !== path12.slice(0, layerPath.length)) {
24747
+ if (layerPath !== path15.slice(0, layerPath.length)) {
24748
24748
  next(layerError);
24749
24749
  return;
24750
24750
  }
24751
- var c = path12[layerPath.length];
24751
+ var c = path15[layerPath.length];
24752
24752
  if (c && c !== "/" && c !== ".") return next(layerError);
24753
24753
  debug("trim prefix (%s) from url %s", layerPath, req.url);
24754
24754
  removed = layerPath;
@@ -24826,7 +24826,7 @@ var require_router = __commonJS({
24826
24826
  };
24827
24827
  proto.use = function use(fn) {
24828
24828
  var offset = 0;
24829
- var path12 = "/";
24829
+ var path15 = "/";
24830
24830
  if (typeof fn !== "function") {
24831
24831
  var arg = fn;
24832
24832
  while (Array.isArray(arg) && arg.length !== 0) {
@@ -24834,7 +24834,7 @@ var require_router = __commonJS({
24834
24834
  }
24835
24835
  if (typeof arg !== "function") {
24836
24836
  offset = 1;
24837
- path12 = fn;
24837
+ path15 = fn;
24838
24838
  }
24839
24839
  }
24840
24840
  var callbacks = flatten(slice.call(arguments, offset));
@@ -24846,8 +24846,8 @@ var require_router = __commonJS({
24846
24846
  if (typeof fn !== "function") {
24847
24847
  throw new TypeError("Router.use() requires a middleware function but got a " + gettype(fn));
24848
24848
  }
24849
- debug("use %o %s", path12, fn.name || "<anonymous>");
24850
- var layer = new Layer(path12, {
24849
+ debug("use %o %s", path15, fn.name || "<anonymous>");
24850
+ var layer = new Layer(path15, {
24851
24851
  sensitive: this.caseSensitive,
24852
24852
  strict: false,
24853
24853
  end: false
@@ -24857,9 +24857,9 @@ var require_router = __commonJS({
24857
24857
  }
24858
24858
  return this;
24859
24859
  };
24860
- proto.route = function route(path12) {
24861
- var route2 = new Route(path12);
24862
- var layer = new Layer(path12, {
24860
+ proto.route = function route(path15) {
24861
+ var route2 = new Route(path15);
24862
+ var layer = new Layer(path15, {
24863
24863
  sensitive: this.caseSensitive,
24864
24864
  strict: this.strict,
24865
24865
  end: true
@@ -24869,8 +24869,8 @@ var require_router = __commonJS({
24869
24869
  return route2;
24870
24870
  };
24871
24871
  methods.concat("all").forEach(function(method) {
24872
- proto[method] = function(path12) {
24873
- var route = this.route(path12);
24872
+ proto[method] = function(path15) {
24873
+ var route = this.route(path15);
24874
24874
  route[method].apply(route, slice.call(arguments, 1));
24875
24875
  return this;
24876
24876
  };
@@ -24906,9 +24906,9 @@ var require_router = __commonJS({
24906
24906
  }
24907
24907
  return toString.call(obj).replace(objectRegExp, "$1");
24908
24908
  }
24909
- function matchLayer(layer, path12) {
24909
+ function matchLayer(layer, path15) {
24910
24910
  try {
24911
- return layer.match(path12);
24911
+ return layer.match(path15);
24912
24912
  } catch (err) {
24913
24913
  return err;
24914
24914
  }
@@ -25026,13 +25026,13 @@ var require_view = __commonJS({
25026
25026
  "../../node_modules/express/lib/view.js"(exports2, module2) {
25027
25027
  "use strict";
25028
25028
  var debug = require_src3()("express:view");
25029
- var path12 = require("path");
25029
+ var path15 = require("path");
25030
25030
  var fs4 = require("fs");
25031
- var dirname = path12.dirname;
25032
- var basename = path12.basename;
25033
- var extname = path12.extname;
25034
- var join2 = path12.join;
25035
- var resolve = path12.resolve;
25031
+ var dirname = path15.dirname;
25032
+ var basename = path15.basename;
25033
+ var extname = path15.extname;
25034
+ var join2 = path15.join;
25035
+ var resolve = path15.resolve;
25036
25036
  module2.exports = View;
25037
25037
  function View(name, options) {
25038
25038
  var opts = options || {};
@@ -25061,17 +25061,17 @@ var require_view = __commonJS({
25061
25061
  this.path = this.lookup(fileName);
25062
25062
  }
25063
25063
  View.prototype.lookup = function lookup(name) {
25064
- var path13;
25064
+ var path16;
25065
25065
  var roots = [].concat(this.root);
25066
25066
  debug('lookup "%s"', name);
25067
- for (var i = 0; i < roots.length && !path13; i++) {
25067
+ for (var i = 0; i < roots.length && !path16; i++) {
25068
25068
  var root = roots[i];
25069
25069
  var loc = resolve(root, name);
25070
25070
  var dir = dirname(loc);
25071
25071
  var file2 = basename(loc);
25072
- path13 = this.resolve(dir, file2);
25072
+ path16 = this.resolve(dir, file2);
25073
25073
  }
25074
- return path13;
25074
+ return path16;
25075
25075
  };
25076
25076
  View.prototype.render = function render(options, callback) {
25077
25077
  debug('render "%s"', this.path);
@@ -25079,21 +25079,21 @@ var require_view = __commonJS({
25079
25079
  };
25080
25080
  View.prototype.resolve = function resolve2(dir, file2) {
25081
25081
  var ext = this.ext;
25082
- var path13 = join2(dir, file2);
25083
- var stat = tryStat(path13);
25082
+ var path16 = join2(dir, file2);
25083
+ var stat = tryStat(path16);
25084
25084
  if (stat && stat.isFile()) {
25085
- return path13;
25085
+ return path16;
25086
25086
  }
25087
- path13 = join2(dir, basename(file2, ext), "index" + ext);
25088
- stat = tryStat(path13);
25087
+ path16 = join2(dir, basename(file2, ext), "index" + ext);
25088
+ stat = tryStat(path16);
25089
25089
  if (stat && stat.isFile()) {
25090
- return path13;
25090
+ return path16;
25091
25091
  }
25092
25092
  };
25093
- function tryStat(path13) {
25094
- debug('stat "%s"', path13);
25093
+ function tryStat(path16) {
25094
+ debug('stat "%s"', path16);
25095
25095
  try {
25096
- return fs4.statSync(path13);
25096
+ return fs4.statSync(path16);
25097
25097
  } catch (e) {
25098
25098
  return void 0;
25099
25099
  }
@@ -25871,7 +25871,7 @@ var require_types = __commonJS({
25871
25871
  // ../../node_modules/mime/mime.js
25872
25872
  var require_mime = __commonJS({
25873
25873
  "../../node_modules/mime/mime.js"(exports2, module2) {
25874
- var path12 = require("path");
25874
+ var path15 = require("path");
25875
25875
  var fs4 = require("fs");
25876
25876
  function Mime() {
25877
25877
  this.types = /* @__PURE__ */ Object.create(null);
@@ -25901,8 +25901,8 @@ var require_mime = __commonJS({
25901
25901
  this.define(map2);
25902
25902
  this._loading = null;
25903
25903
  };
25904
- Mime.prototype.lookup = function(path13, fallback) {
25905
- var ext = path13.replace(/^.*[\.\/\\]/, "").toLowerCase();
25904
+ Mime.prototype.lookup = function(path16, fallback) {
25905
+ var ext = path16.replace(/^.*[\.\/\\]/, "").toLowerCase();
25906
25906
  return this.types[ext] || fallback || this.default_type;
25907
25907
  };
25908
25908
  Mime.prototype.extension = function(mimeType) {
@@ -26136,28 +26136,28 @@ var require_send = __commonJS({
26136
26136
  var ms = require_ms5();
26137
26137
  var onFinished = require_on_finished();
26138
26138
  var parseRange = require_range_parser();
26139
- var path12 = require("path");
26139
+ var path15 = require("path");
26140
26140
  var statuses = require_statuses();
26141
26141
  var Stream = require("stream");
26142
26142
  var util = require("util");
26143
- var extname = path12.extname;
26144
- var join2 = path12.join;
26145
- var normalize = path12.normalize;
26146
- var resolve = path12.resolve;
26147
- var sep = path12.sep;
26143
+ var extname = path15.extname;
26144
+ var join2 = path15.join;
26145
+ var normalize = path15.normalize;
26146
+ var resolve = path15.resolve;
26147
+ var sep = path15.sep;
26148
26148
  var BYTES_RANGE_REGEXP = /^ *bytes=/;
26149
26149
  var MAX_MAXAGE = 60 * 60 * 24 * 365 * 1e3;
26150
26150
  var UP_PATH_REGEXP = /(?:^|[\\/])\.\.(?:[\\/]|$)/;
26151
26151
  module2.exports = send2;
26152
26152
  module2.exports.mime = mime;
26153
- function send2(req, path13, options) {
26154
- return new SendStream(req, path13, options);
26153
+ function send2(req, path16, options) {
26154
+ return new SendStream(req, path16, options);
26155
26155
  }
26156
- function SendStream(req, path13, options) {
26156
+ function SendStream(req, path16, options) {
26157
26157
  Stream.call(this);
26158
26158
  var opts = options || {};
26159
26159
  this.options = opts;
26160
- this.path = path13;
26160
+ this.path = path16;
26161
26161
  this.req = req;
26162
26162
  this._acceptRanges = opts.acceptRanges !== void 0 ? Boolean(opts.acceptRanges) : true;
26163
26163
  this._cacheControl = opts.cacheControl !== void 0 ? Boolean(opts.cacheControl) : true;
@@ -26203,8 +26203,8 @@ var require_send = __commonJS({
26203
26203
  this._index = index2;
26204
26204
  return this;
26205
26205
  }, "send.index: pass index as option");
26206
- SendStream.prototype.root = function root(path13) {
26207
- this._root = resolve(String(path13));
26206
+ SendStream.prototype.root = function root(path16) {
26207
+ this._root = resolve(String(path16));
26208
26208
  debug("root %s", this._root);
26209
26209
  return this;
26210
26210
  };
@@ -26317,10 +26317,10 @@ var require_send = __commonJS({
26317
26317
  var lastModified = this.res.getHeader("Last-Modified");
26318
26318
  return parseHttpDate(lastModified) <= parseHttpDate(ifRange);
26319
26319
  };
26320
- SendStream.prototype.redirect = function redirect(path13) {
26320
+ SendStream.prototype.redirect = function redirect(path16) {
26321
26321
  var res = this.res;
26322
26322
  if (hasListeners(this, "directory")) {
26323
- this.emit("directory", res, path13);
26323
+ this.emit("directory", res, path16);
26324
26324
  return;
26325
26325
  }
26326
26326
  if (this.hasTrailingSlash()) {
@@ -26340,42 +26340,42 @@ var require_send = __commonJS({
26340
26340
  SendStream.prototype.pipe = function pipe2(res) {
26341
26341
  var root = this._root;
26342
26342
  this.res = res;
26343
- var path13 = decode3(this.path);
26344
- if (path13 === -1) {
26343
+ var path16 = decode3(this.path);
26344
+ if (path16 === -1) {
26345
26345
  this.error(400);
26346
26346
  return res;
26347
26347
  }
26348
- if (~path13.indexOf("\0")) {
26348
+ if (~path16.indexOf("\0")) {
26349
26349
  this.error(400);
26350
26350
  return res;
26351
26351
  }
26352
26352
  var parts;
26353
26353
  if (root !== null) {
26354
- if (path13) {
26355
- path13 = normalize("." + sep + path13);
26354
+ if (path16) {
26355
+ path16 = normalize("." + sep + path16);
26356
26356
  }
26357
- if (UP_PATH_REGEXP.test(path13)) {
26358
- debug('malicious path "%s"', path13);
26357
+ if (UP_PATH_REGEXP.test(path16)) {
26358
+ debug('malicious path "%s"', path16);
26359
26359
  this.error(403);
26360
26360
  return res;
26361
26361
  }
26362
- parts = path13.split(sep);
26363
- path13 = normalize(join2(root, path13));
26362
+ parts = path16.split(sep);
26363
+ path16 = normalize(join2(root, path16));
26364
26364
  } else {
26365
- if (UP_PATH_REGEXP.test(path13)) {
26366
- debug('malicious path "%s"', path13);
26365
+ if (UP_PATH_REGEXP.test(path16)) {
26366
+ debug('malicious path "%s"', path16);
26367
26367
  this.error(403);
26368
26368
  return res;
26369
26369
  }
26370
- parts = normalize(path13).split(sep);
26371
- path13 = resolve(path13);
26370
+ parts = normalize(path16).split(sep);
26371
+ path16 = resolve(path16);
26372
26372
  }
26373
26373
  if (containsDotFile(parts)) {
26374
26374
  var access2 = this._dotfiles;
26375
26375
  if (access2 === void 0) {
26376
26376
  access2 = parts[parts.length - 1][0] === "." ? this._hidden ? "allow" : "ignore" : "allow";
26377
26377
  }
26378
- debug('%s dotfile "%s"', access2, path13);
26378
+ debug('%s dotfile "%s"', access2, path16);
26379
26379
  switch (access2) {
26380
26380
  case "allow":
26381
26381
  break;
@@ -26389,13 +26389,13 @@ var require_send = __commonJS({
26389
26389
  }
26390
26390
  }
26391
26391
  if (this._index.length && this.hasTrailingSlash()) {
26392
- this.sendIndex(path13);
26392
+ this.sendIndex(path16);
26393
26393
  return res;
26394
26394
  }
26395
- this.sendFile(path13);
26395
+ this.sendFile(path16);
26396
26396
  return res;
26397
26397
  };
26398
- SendStream.prototype.send = function send3(path13, stat) {
26398
+ SendStream.prototype.send = function send3(path16, stat) {
26399
26399
  var len = stat.size;
26400
26400
  var options = this.options;
26401
26401
  var opts = {};
@@ -26407,9 +26407,9 @@ var require_send = __commonJS({
26407
26407
  this.headersAlreadySent();
26408
26408
  return;
26409
26409
  }
26410
- debug('pipe "%s"', path13);
26411
- this.setHeader(path13, stat);
26412
- this.type(path13);
26410
+ debug('pipe "%s"', path16);
26411
+ this.setHeader(path16, stat);
26412
+ this.type(path16);
26413
26413
  if (this.isConditionalGET()) {
26414
26414
  if (this.isPreconditionFailure()) {
26415
26415
  this.error(412);
@@ -26458,26 +26458,26 @@ var require_send = __commonJS({
26458
26458
  res.end();
26459
26459
  return;
26460
26460
  }
26461
- this.stream(path13, opts);
26461
+ this.stream(path16, opts);
26462
26462
  };
26463
- SendStream.prototype.sendFile = function sendFile(path13) {
26463
+ SendStream.prototype.sendFile = function sendFile(path16) {
26464
26464
  var i = 0;
26465
26465
  var self2 = this;
26466
- debug('stat "%s"', path13);
26467
- fs4.stat(path13, function onstat(err, stat) {
26468
- if (err && err.code === "ENOENT" && !extname(path13) && path13[path13.length - 1] !== sep) {
26466
+ debug('stat "%s"', path16);
26467
+ fs4.stat(path16, function onstat(err, stat) {
26468
+ if (err && err.code === "ENOENT" && !extname(path16) && path16[path16.length - 1] !== sep) {
26469
26469
  return next(err);
26470
26470
  }
26471
26471
  if (err) return self2.onStatError(err);
26472
- if (stat.isDirectory()) return self2.redirect(path13);
26473
- self2.emit("file", path13, stat);
26474
- self2.send(path13, stat);
26472
+ if (stat.isDirectory()) return self2.redirect(path16);
26473
+ self2.emit("file", path16, stat);
26474
+ self2.send(path16, stat);
26475
26475
  });
26476
26476
  function next(err) {
26477
26477
  if (self2._extensions.length <= i) {
26478
26478
  return err ? self2.onStatError(err) : self2.error(404);
26479
26479
  }
26480
- var p = path13 + "." + self2._extensions[i++];
26480
+ var p = path16 + "." + self2._extensions[i++];
26481
26481
  debug('stat "%s"', p);
26482
26482
  fs4.stat(p, function(err2, stat) {
26483
26483
  if (err2) return next(err2);
@@ -26487,7 +26487,7 @@ var require_send = __commonJS({
26487
26487
  });
26488
26488
  }
26489
26489
  };
26490
- SendStream.prototype.sendIndex = function sendIndex(path13) {
26490
+ SendStream.prototype.sendIndex = function sendIndex(path16) {
26491
26491
  var i = -1;
26492
26492
  var self2 = this;
26493
26493
  function next(err) {
@@ -26495,7 +26495,7 @@ var require_send = __commonJS({
26495
26495
  if (err) return self2.onStatError(err);
26496
26496
  return self2.error(404);
26497
26497
  }
26498
- var p = join2(path13, self2._index[i]);
26498
+ var p = join2(path16, self2._index[i]);
26499
26499
  debug('stat "%s"', p);
26500
26500
  fs4.stat(p, function(err2, stat) {
26501
26501
  if (err2) return next(err2);
@@ -26506,10 +26506,10 @@ var require_send = __commonJS({
26506
26506
  }
26507
26507
  next();
26508
26508
  };
26509
- SendStream.prototype.stream = function stream(path13, options) {
26509
+ SendStream.prototype.stream = function stream(path16, options) {
26510
26510
  var self2 = this;
26511
26511
  var res = this.res;
26512
- var stream2 = fs4.createReadStream(path13, options);
26512
+ var stream2 = fs4.createReadStream(path16, options);
26513
26513
  this.emit("stream", stream2);
26514
26514
  stream2.pipe(res);
26515
26515
  function cleanup() {
@@ -26524,10 +26524,10 @@ var require_send = __commonJS({
26524
26524
  self2.emit("end");
26525
26525
  });
26526
26526
  };
26527
- SendStream.prototype.type = function type(path13) {
26527
+ SendStream.prototype.type = function type(path16) {
26528
26528
  var res = this.res;
26529
26529
  if (res.getHeader("Content-Type")) return;
26530
- var type2 = mime.lookup(path13);
26530
+ var type2 = mime.lookup(path16);
26531
26531
  if (!type2) {
26532
26532
  debug("no content-type");
26533
26533
  return;
@@ -26536,9 +26536,9 @@ var require_send = __commonJS({
26536
26536
  debug("content-type %s", type2);
26537
26537
  res.setHeader("Content-Type", type2 + (charset ? "; charset=" + charset : ""));
26538
26538
  };
26539
- SendStream.prototype.setHeader = function setHeader(path13, stat) {
26539
+ SendStream.prototype.setHeader = function setHeader(path16, stat) {
26540
26540
  var res = this.res;
26541
- this.emit("headers", res, path13, stat);
26541
+ this.emit("headers", res, path16, stat);
26542
26542
  if (this._acceptRanges && !res.getHeader("Accept-Ranges")) {
26543
26543
  debug("accept ranges");
26544
26544
  res.setHeader("Accept-Ranges", "bytes");
@@ -26597,9 +26597,9 @@ var require_send = __commonJS({
26597
26597
  }
26598
26598
  return err instanceof Error ? createError(status, err, { expose: false }) : createError(status, err);
26599
26599
  }
26600
- function decode3(path13) {
26600
+ function decode3(path16) {
26601
26601
  try {
26602
- return decodeURIComponent(path13);
26602
+ return decodeURIComponent(path16);
26603
26603
  } catch (err) {
26604
26604
  return -1;
26605
26605
  }
@@ -27508,10 +27508,10 @@ var require_utils2 = __commonJS({
27508
27508
  var querystring = require("querystring");
27509
27509
  exports2.etag = createETagGenerator({ weak: false });
27510
27510
  exports2.wetag = createETagGenerator({ weak: true });
27511
- exports2.isAbsolute = function(path12) {
27512
- if ("/" === path12[0]) return true;
27513
- if (":" === path12[1] && ("\\" === path12[2] || "/" === path12[2])) return true;
27514
- if ("\\\\" === path12.substring(0, 2)) return true;
27511
+ exports2.isAbsolute = function(path15) {
27512
+ if ("/" === path15[0]) return true;
27513
+ if (":" === path15[1] && ("\\" === path15[2] || "/" === path15[2])) return true;
27514
+ if ("\\\\" === path15.substring(0, 2)) return true;
27515
27515
  };
27516
27516
  exports2.flatten = deprecate.function(
27517
27517
  flatten,
@@ -27722,7 +27722,7 @@ var require_application = __commonJS({
27722
27722
  };
27723
27723
  app.use = function use(fn) {
27724
27724
  var offset = 0;
27725
- var path12 = "/";
27725
+ var path15 = "/";
27726
27726
  if (typeof fn !== "function") {
27727
27727
  var arg = fn;
27728
27728
  while (Array.isArray(arg) && arg.length !== 0) {
@@ -27730,7 +27730,7 @@ var require_application = __commonJS({
27730
27730
  }
27731
27731
  if (typeof arg !== "function") {
27732
27732
  offset = 1;
27733
- path12 = fn;
27733
+ path15 = fn;
27734
27734
  }
27735
27735
  }
27736
27736
  var fns = flatten(slice.call(arguments, offset));
@@ -27741,12 +27741,12 @@ var require_application = __commonJS({
27741
27741
  var router = this._router;
27742
27742
  fns.forEach(function(fn2) {
27743
27743
  if (!fn2 || !fn2.handle || !fn2.set) {
27744
- return router.use(path12, fn2);
27744
+ return router.use(path15, fn2);
27745
27745
  }
27746
- debug(".use app under %s", path12);
27747
- fn2.mountpath = path12;
27746
+ debug(".use app under %s", path15);
27747
+ fn2.mountpath = path15;
27748
27748
  fn2.parent = this;
27749
- router.use(path12, function mounted_app(req, res, next) {
27749
+ router.use(path15, function mounted_app(req, res, next) {
27750
27750
  var orig = req.app;
27751
27751
  fn2.handle(req, res, function(err) {
27752
27752
  setPrototypeOf(req, orig.request);
@@ -27758,9 +27758,9 @@ var require_application = __commonJS({
27758
27758
  }, this);
27759
27759
  return this;
27760
27760
  };
27761
- app.route = function route(path12) {
27761
+ app.route = function route(path15) {
27762
27762
  this.lazyrouter();
27763
- return this._router.route(path12);
27763
+ return this._router.route(path15);
27764
27764
  };
27765
27765
  app.engine = function engine(ext, fn) {
27766
27766
  if (typeof fn !== "function") {
@@ -27811,7 +27811,7 @@ var require_application = __commonJS({
27811
27811
  }
27812
27812
  return this;
27813
27813
  };
27814
- app.path = function path12() {
27814
+ app.path = function path15() {
27815
27815
  return this.parent ? this.parent.path() + this.mountpath : "";
27816
27816
  };
27817
27817
  app.enabled = function enabled(setting) {
@@ -27827,19 +27827,19 @@ var require_application = __commonJS({
27827
27827
  return this.set(setting, false);
27828
27828
  };
27829
27829
  methods.forEach(function(method) {
27830
- app[method] = function(path12) {
27830
+ app[method] = function(path15) {
27831
27831
  if (method === "get" && arguments.length === 1) {
27832
- return this.set(path12);
27832
+ return this.set(path15);
27833
27833
  }
27834
27834
  this.lazyrouter();
27835
- var route = this._router.route(path12);
27835
+ var route = this._router.route(path15);
27836
27836
  route[method].apply(route, slice.call(arguments, 1));
27837
27837
  return this;
27838
27838
  };
27839
27839
  });
27840
- app.all = function all(path12) {
27840
+ app.all = function all(path15) {
27841
27841
  this.lazyrouter();
27842
- var route = this._router.route(path12);
27842
+ var route = this._router.route(path15);
27843
27843
  var args = slice.call(arguments, 1);
27844
27844
  for (var i = 0; i < methods.length; i++) {
27845
27845
  route[methods[i]].apply(route, args);
@@ -28489,7 +28489,7 @@ var require_request = __commonJS({
28489
28489
  "use strict";
28490
28490
  var accepts = require_accepts();
28491
28491
  var deprecate = require_depd()("express");
28492
- var isIP = require("net").isIP;
28492
+ var isIP2 = require("net").isIP;
28493
28493
  var typeis = require_type_is();
28494
28494
  var http2 = require("http");
28495
28495
  var fresh = require_fresh();
@@ -28595,10 +28595,10 @@ var require_request = __commonJS({
28595
28595
  var hostname3 = this.hostname;
28596
28596
  if (!hostname3) return [];
28597
28597
  var offset = this.app.get("subdomain offset");
28598
- var subdomains2 = !isIP(hostname3) ? hostname3.split(".").reverse() : [hostname3];
28598
+ var subdomains2 = !isIP2(hostname3) ? hostname3.split(".").reverse() : [hostname3];
28599
28599
  return subdomains2.slice(offset);
28600
28600
  });
28601
- defineGetter(req, "path", function path12() {
28601
+ defineGetter(req, "path", function path15() {
28602
28602
  return parse3(this).pathname;
28603
28603
  });
28604
28604
  defineGetter(req, "hostname", function hostname3() {
@@ -28920,7 +28920,7 @@ var require_response = __commonJS({
28920
28920
  var http2 = require("http");
28921
28921
  var isAbsolute = require_utils2().isAbsolute;
28922
28922
  var onFinished = require_on_finished();
28923
- var path12 = require("path");
28923
+ var path15 = require("path");
28924
28924
  var statuses = require_statuses();
28925
28925
  var merge2 = require_utils_merge();
28926
28926
  var sign = require_cookie_signature().sign;
@@ -28929,9 +28929,9 @@ var require_response = __commonJS({
28929
28929
  var setCharset = require_utils2().setCharset;
28930
28930
  var cookie = require_cookie();
28931
28931
  var send2 = require_send();
28932
- var extname = path12.extname;
28932
+ var extname = path15.extname;
28933
28933
  var mime = send2.mime;
28934
- var resolve = path12.resolve;
28934
+ var resolve = path15.resolve;
28935
28935
  var vary = require_vary();
28936
28936
  var res = Object.create(http2.ServerResponse.prototype);
28937
28937
  module2.exports = res;
@@ -29108,26 +29108,26 @@ var require_response = __commonJS({
29108
29108
  this.type("txt");
29109
29109
  return this.send(body);
29110
29110
  };
29111
- res.sendFile = function sendFile(path13, options, callback) {
29111
+ res.sendFile = function sendFile(path16, options, callback) {
29112
29112
  var done = callback;
29113
29113
  var req = this.req;
29114
29114
  var res2 = this;
29115
29115
  var next = req.next;
29116
29116
  var opts = options || {};
29117
- if (!path13) {
29117
+ if (!path16) {
29118
29118
  throw new TypeError("path argument is required to res.sendFile");
29119
29119
  }
29120
- if (typeof path13 !== "string") {
29120
+ if (typeof path16 !== "string") {
29121
29121
  throw new TypeError("path must be a string to res.sendFile");
29122
29122
  }
29123
29123
  if (typeof options === "function") {
29124
29124
  done = options;
29125
29125
  opts = {};
29126
29126
  }
29127
- if (!opts.root && !isAbsolute(path13)) {
29127
+ if (!opts.root && !isAbsolute(path16)) {
29128
29128
  throw new TypeError("path must be absolute or specify root to res.sendFile");
29129
29129
  }
29130
- var pathname = encodeURI(path13);
29130
+ var pathname = encodeURI(path16);
29131
29131
  var file2 = send2(req, pathname, opts);
29132
29132
  sendfile(res2, file2, opts, function(err) {
29133
29133
  if (done) return done(err);
@@ -29137,7 +29137,7 @@ var require_response = __commonJS({
29137
29137
  }
29138
29138
  });
29139
29139
  };
29140
- res.sendfile = function(path13, options, callback) {
29140
+ res.sendfile = function(path16, options, callback) {
29141
29141
  var done = callback;
29142
29142
  var req = this.req;
29143
29143
  var res2 = this;
@@ -29147,7 +29147,7 @@ var require_response = __commonJS({
29147
29147
  done = options;
29148
29148
  opts = {};
29149
29149
  }
29150
- var file2 = send2(req, path13, opts);
29150
+ var file2 = send2(req, path16, opts);
29151
29151
  sendfile(res2, file2, opts, function(err) {
29152
29152
  if (done) return done(err);
29153
29153
  if (err && err.code === "EISDIR") return next();
@@ -29160,7 +29160,7 @@ var require_response = __commonJS({
29160
29160
  res.sendfile,
29161
29161
  "res.sendfile: Use res.sendFile instead"
29162
29162
  );
29163
- res.download = function download(path13, filename, options, callback) {
29163
+ res.download = function download(path16, filename, options, callback) {
29164
29164
  var done = callback;
29165
29165
  var name = filename;
29166
29166
  var opts = options || null;
@@ -29177,7 +29177,7 @@ var require_response = __commonJS({
29177
29177
  opts = filename;
29178
29178
  }
29179
29179
  var headers = {
29180
- "Content-Disposition": contentDisposition(name || path13)
29180
+ "Content-Disposition": contentDisposition(name || path16)
29181
29181
  };
29182
29182
  if (opts && opts.headers) {
29183
29183
  var keys = Object.keys(opts.headers);
@@ -29190,7 +29190,7 @@ var require_response = __commonJS({
29190
29190
  }
29191
29191
  opts = Object.create(opts);
29192
29192
  opts.headers = headers;
29193
- var fullPath = !opts.root ? resolve(path13) : path13;
29193
+ var fullPath = !opts.root ? resolve(path16) : path16;
29194
29194
  return this.sendFile(fullPath, opts, done);
29195
29195
  };
29196
29196
  res.contentType = res.type = function contentType(type) {
@@ -29491,11 +29491,11 @@ var require_serve_static = __commonJS({
29491
29491
  }
29492
29492
  var forwardError = !fallthrough;
29493
29493
  var originalUrl = parseUrl.original(req);
29494
- var path12 = parseUrl(req).pathname;
29495
- if (path12 === "/" && originalUrl.pathname.substr(-1) !== "/") {
29496
- path12 = "";
29494
+ var path15 = parseUrl(req).pathname;
29495
+ if (path15 === "/" && originalUrl.pathname.substr(-1) !== "/") {
29496
+ path15 = "";
29497
29497
  }
29498
- var stream = send2(req, path12, opts);
29498
+ var stream = send2(req, path15, opts);
29499
29499
  stream.on("directory", onDirectory);
29500
29500
  if (setHeaders) {
29501
29501
  stream.on("headers", setHeaders);
@@ -31834,7 +31834,7 @@ var require_websocket = __commonJS({
31834
31834
  var http2 = require("http");
31835
31835
  var net = require("net");
31836
31836
  var tls = require("tls");
31837
- var { randomBytes: randomBytes2, createHash: createHash3 } = require("crypto");
31837
+ var { randomBytes: randomBytes3, createHash: createHash3 } = require("crypto");
31838
31838
  var { Duplex, Readable } = require("stream");
31839
31839
  var { URL: URL2 } = require("url");
31840
31840
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -32364,7 +32364,7 @@ var require_websocket = __commonJS({
32364
32364
  }
32365
32365
  }
32366
32366
  const defaultPort = isSecure ? 443 : 80;
32367
- const key = randomBytes2(16).toString("base64");
32367
+ const key = randomBytes3(16).toString("base64");
32368
32368
  const request = isSecure ? https.request : http2.request;
32369
32369
  const protocolSet = /* @__PURE__ */ new Set();
32370
32370
  let perMessageDeflate;
@@ -33250,6 +33250,7 @@ var require_websocket_server = __commonJS({
33250
33250
  // src/index.ts
33251
33251
  var index_exports = {};
33252
33252
  __export(index_exports, {
33253
+ inspectTelemetryBuildConfig: () => inspectTelemetryBuildConfig,
33253
33254
  listVisibleCLICommandNames: () => listVisibleCLICommandNames,
33254
33255
  resolveBundledSkillsRoot: () => resolveBundledSkillsRoot,
33255
33256
  resolveBundledViewsPath: () => resolveBundledViewsPath,
@@ -33260,10 +33261,11 @@ __export(index_exports, {
33260
33261
  });
33261
33262
  module.exports = __toCommonJS(index_exports);
33262
33263
  var import_node_child_process3 = require("node:child_process");
33263
- var import_node_fs10 = require("node:fs");
33264
- var import_node_path12 = __toESM(require("node:path"), 1);
33264
+ var import_node_fs12 = require("node:fs");
33265
+ var import_node_os5 = __toESM(require("node:os"), 1);
33266
+ var import_node_path15 = __toESM(require("node:path"), 1);
33265
33267
  var import_node_module = require("node:module");
33266
- var import_node_url2 = require("node:url");
33268
+ var import_node_url3 = require("node:url");
33267
33269
 
33268
33270
  // ../../node_modules/commander/esm.mjs
33269
33271
  var import_index = __toESM(require_commander(), 1);
@@ -33414,22 +33416,22 @@ var Daemon = class {
33414
33416
  }
33415
33417
  async install() {
33416
33418
  if (this.platform === "darwin") {
33417
- const path12 = plistPath(this.home, this.name);
33418
- if ((0, import_node_fs.existsSync)(path12)) {
33419
- await this.exec("launchctl", ["unload", "-w", path12]).catch(() => void 0);
33419
+ const path15 = plistPath(this.home, this.name);
33420
+ if ((0, import_node_fs.existsSync)(path15)) {
33421
+ await this.exec("launchctl", ["unload", "-w", path15]).catch(() => void 0);
33420
33422
  }
33421
33423
  await (0, import_promises.mkdir)((0, import_node_path.join)(this.home, "Library", "LaunchAgents"), { recursive: true });
33422
- await (0, import_promises.writeFile)(path12, renderPlist(this.name, this.programArgs, this.env), "utf8");
33423
- await this.exec("launchctl", ["load", "-w", path12]);
33424
+ await (0, import_promises.writeFile)(path15, renderPlist(this.name, this.programArgs, this.env), "utf8");
33425
+ await this.exec("launchctl", ["load", "-w", path15]);
33424
33426
  return;
33425
33427
  }
33426
33428
  if (this.platform === "linux") {
33427
- const path12 = unitPath(this.home, this.name);
33428
- if ((0, import_node_fs.existsSync)(path12)) {
33429
+ const path15 = unitPath(this.home, this.name);
33430
+ if ((0, import_node_fs.existsSync)(path15)) {
33429
33431
  await this.exec("systemctl", ["--user", "disable", "--now", `${this.name}.service`]).catch(() => void 0);
33430
33432
  }
33431
33433
  await (0, import_promises.mkdir)((0, import_node_path.join)(this.home, ".config", "systemd", "user"), { recursive: true });
33432
- await (0, import_promises.writeFile)(path12, renderUnit(this.description, this.programArgs, this.env), "utf8");
33434
+ await (0, import_promises.writeFile)(path15, renderUnit(this.description, this.programArgs, this.env), "utf8");
33433
33435
  await this.exec("systemctl", ["--user", "daemon-reload"]);
33434
33436
  await this.exec("systemctl", ["--user", "enable", "--now", `${this.name}.service`]);
33435
33437
  return;
@@ -33438,17 +33440,17 @@ var Daemon = class {
33438
33440
  }
33439
33441
  async uninstall() {
33440
33442
  if (this.platform === "darwin") {
33441
- const path12 = plistPath(this.home, this.name);
33442
- if ((0, import_node_fs.existsSync)(path12)) {
33443
- await this.exec("launchctl", ["unload", "-w", path12]).catch(() => void 0);
33444
- await (0, import_promises.rm)(path12, { force: true });
33443
+ const path15 = plistPath(this.home, this.name);
33444
+ if ((0, import_node_fs.existsSync)(path15)) {
33445
+ await this.exec("launchctl", ["unload", "-w", path15]).catch(() => void 0);
33446
+ await (0, import_promises.rm)(path15, { force: true });
33445
33447
  }
33446
33448
  return;
33447
33449
  }
33448
33450
  if (this.platform === "linux") {
33449
- const path12 = unitPath(this.home, this.name);
33451
+ const path15 = unitPath(this.home, this.name);
33450
33452
  await this.exec("systemctl", ["--user", "disable", "--now", `${this.name}.service`]).catch(() => void 0);
33451
- await (0, import_promises.rm)(path12, { force: true });
33453
+ await (0, import_promises.rm)(path15, { force: true });
33452
33454
  await this.exec("systemctl", ["--user", "daemon-reload"]);
33453
33455
  return;
33454
33456
  }
@@ -33456,8 +33458,8 @@ var Daemon = class {
33456
33458
  }
33457
33459
  async status() {
33458
33460
  if (this.platform === "darwin") {
33459
- const path12 = plistPath(this.home, this.name);
33460
- if (!(0, import_node_fs.existsSync)(path12))
33461
+ const path15 = plistPath(this.home, this.name);
33462
+ if (!(0, import_node_fs.existsSync)(path15))
33461
33463
  return { installed: false, running: false };
33462
33464
  try {
33463
33465
  await this.exec("launchctl", ["list", this.name]);
@@ -33467,8 +33469,8 @@ var Daemon = class {
33467
33469
  }
33468
33470
  }
33469
33471
  if (this.platform === "linux") {
33470
- const path12 = unitPath(this.home, this.name);
33471
- if (!(0, import_node_fs.existsSync)(path12))
33472
+ const path15 = unitPath(this.home, this.name);
33473
+ if (!(0, import_node_fs.existsSync)(path15))
33472
33474
  return { installed: false, running: false };
33473
33475
  try {
33474
33476
  const result = await this.exec("systemctl", [
@@ -33742,6 +33744,8 @@ function cloneStackChild(node) {
33742
33744
  }
33743
33745
 
33744
33746
  // ../shared/src/types.ts
33747
+ var TELEVISION_CLIENT_META_HEADER = "X-Television-Client-Meta";
33748
+ var TELEMETRY_ACTIVITY_MESSAGE_TYPE = "telemetry-activity";
33745
33749
  function createCardNode(artifactID, overrides = {}) {
33746
33750
  return {
33747
33751
  type: "card",
@@ -33876,10 +33880,12 @@ var HttpRequester = class {
33876
33880
  serverURL;
33877
33881
  token;
33878
33882
  onUnauthorized;
33883
+ telemetryMeta;
33879
33884
  constructor(serverURL, options) {
33880
33885
  this.serverURL = serverURL.replace(/\/$/, "");
33881
33886
  this.token = options.token;
33882
33887
  this.onUnauthorized = options.onUnauthorized;
33888
+ this.telemetryMeta = options.telemetryMeta;
33883
33889
  }
33884
33890
  async requestJSON(method, pathname, body) {
33885
33891
  const response = await this.request(
@@ -33958,6 +33964,9 @@ var HttpRequester = class {
33958
33964
  if (this.token) {
33959
33965
  headers.Authorization = `Bearer ${this.token}`;
33960
33966
  }
33967
+ if (this.telemetryMeta) {
33968
+ headers[TELEVISION_CLIENT_META_HEADER] = JSON.stringify(this.telemetryMeta);
33969
+ }
33961
33970
  return Object.keys(headers).length > 0 ? headers : void 0;
33962
33971
  }
33963
33972
  };
@@ -34113,6 +34122,21 @@ var MarkdownClient = class {
34113
34122
  );
34114
34123
  }
34115
34124
  };
34125
+ var TelemetryControlClient = class {
34126
+ #http;
34127
+ constructor(http2) {
34128
+ this.#http = http2;
34129
+ }
34130
+ status() {
34131
+ return this.#http.requestJSON("GET", "/telemetry");
34132
+ }
34133
+ enable() {
34134
+ return this.#http.requestJSON("POST", "/telemetry/enable");
34135
+ }
34136
+ disable() {
34137
+ return this.#http.requestJSON("POST", "/telemetry/disable");
34138
+ }
34139
+ };
34116
34140
  var DisplayClient = class {
34117
34141
  #http;
34118
34142
  constructor(http2) {
@@ -34136,6 +34160,7 @@ var TelevisionClient = class {
34136
34160
  artifacts;
34137
34161
  display;
34138
34162
  markdown;
34163
+ telemetry;
34139
34164
  #http;
34140
34165
  constructor(serverURL, options = {}) {
34141
34166
  this.#http = new HttpRequester(serverURL, options);
@@ -34143,6 +34168,7 @@ var TelevisionClient = class {
34143
34168
  this.artifacts = new ArtifactClient(this.#http);
34144
34169
  this.display = new DisplayClient(this.#http);
34145
34170
  this.markdown = new MarkdownClient(this.#http);
34171
+ this.telemetry = new TelemetryControlClient(this.#http);
34146
34172
  }
34147
34173
  health() {
34148
34174
  return this.#http.requestJSON("GET", "/health");
@@ -34161,7 +34187,10 @@ function buildConnectURL(serverURL, token) {
34161
34187
 
34162
34188
  // ../server/src/server.ts
34163
34189
  var import_express2 = __toESM(require_express2(), 1);
34190
+ var import_node_fs9 = require("node:fs");
34164
34191
  var import_node_http = __toESM(require("node:http"), 1);
34192
+ var import_node_path11 = __toESM(require("node:path"), 1);
34193
+ var import_node_url = require("node:url");
34165
34194
 
34166
34195
  // ../server/src/config.ts
34167
34196
  var import_node_fs2 = require("node:fs");
@@ -34172,6 +34201,13 @@ var APP_HIDDEN_DIRECTORY = ".television";
34172
34201
  var TELEVISION_STORAGE_PATH_ENV = "TELEVISION_STORAGE_PATH";
34173
34202
  var TELEVISION_PORT_ENV = "TELEVISION_PORT";
34174
34203
  var TELEVISION_ACP_AGENT_ENV = "TELEVISION_ACP_AGENT";
34204
+ var TELEVISION_DEVELOPER_HOME_ENV = "TELEVISION_DEVELOPER_HOME";
34205
+ var TELEMETRY_CONTROL_ENV_VARS = [
34206
+ "DO_NOT_TRACK",
34207
+ "CI",
34208
+ "TV_TELEMETRY_DEV",
34209
+ "TELEVISION_TELEMETRY_BUILD"
34210
+ ];
34175
34211
  var ACP_AGENT_PROFILES = {
34176
34212
  openclaw: {
34177
34213
  agent: "openclaw",
@@ -34194,8 +34230,11 @@ var DEFAULT_SERVER_URL = buildServerURL(DEFAULT_SERVER_HOST, DEFAULT_SERVER_PORT
34194
34230
  function buildServerURL(host, port) {
34195
34231
  return `http://${host}:${port}`;
34196
34232
  }
34233
+ function getDefaultTelevisionStoragePath() {
34234
+ return import_node_path2.default.join(import_node_os2.default.homedir(), APP_HIDDEN_DIRECTORY);
34235
+ }
34197
34236
  function getTelevisionStoragePath() {
34198
- return process.env[TELEVISION_STORAGE_PATH_ENV] ?? import_node_path2.default.join(import_node_os2.default.homedir(), APP_HIDDEN_DIRECTORY);
34237
+ return process.env[TELEVISION_STORAGE_PATH_ENV] ?? getDefaultTelevisionStoragePath();
34199
34238
  }
34200
34239
  function getTelevisionPortEnv() {
34201
34240
  const rawPort = process.env[TELEVISION_PORT_ENV];
@@ -34218,19 +34257,20 @@ function resolveACPAgentProfile(env = process.env) {
34218
34257
  `Unsupported TELEVISION_ACP_AGENT "${rawAgent}". Supported values: openclaw, hermes.`
34219
34258
  );
34220
34259
  }
34221
- function buildPersistedACPEnvironment(env) {
34260
+ function buildPersistedACPEnvironment(env, options = {}) {
34222
34261
  const pathValue = env.PATH;
34223
34262
  if (pathValue === void 0) {
34224
34263
  throw new Error("PATH is required to build the persisted ACP environment.");
34225
34264
  }
34265
+ const snapshot = { PATH: pathValue };
34266
+ const developerHome = options.developerHome ?? import_node_os2.default.homedir();
34267
+ if (developerHome !== "") snapshot[TELEVISION_DEVELOPER_HOME_ENV] = developerHome;
34268
+ copyTelemetryControlEnvironment(env, snapshot);
34226
34269
  const profile = resolveACPAgentProfile(env);
34227
34270
  if (!profile) {
34228
- return { PATH: pathValue };
34271
+ return snapshot;
34229
34272
  }
34230
- const snapshot = {
34231
- PATH: pathValue,
34232
- [TELEVISION_ACP_AGENT_ENV]: profile.agent
34233
- };
34273
+ snapshot[TELEVISION_ACP_AGENT_ENV] = profile.agent;
34234
34274
  for (const [key, value] of Object.entries(env)) {
34235
34275
  if (key.startsWith(profile.envPrefix) && value !== void 0) {
34236
34276
  snapshot[key] = value;
@@ -34238,6 +34278,12 @@ function buildPersistedACPEnvironment(env) {
34238
34278
  }
34239
34279
  return snapshot;
34240
34280
  }
34281
+ function copyTelemetryControlEnvironment(env, snapshot) {
34282
+ for (const key of TELEMETRY_CONTROL_ENV_VARS) {
34283
+ const value = env[key];
34284
+ if (value !== void 0 && value !== "") snapshot[key] = value;
34285
+ }
34286
+ }
34241
34287
  function canExecuteFile(filePath) {
34242
34288
  try {
34243
34289
  return (0, import_node_fs2.statSync)(filePath).isFile() && (0, import_node_fs2.accessSync)(filePath, import_node_fs2.constants.X_OK) === void 0;
@@ -35026,10 +35072,10 @@ function mergeDefs(...defs) {
35026
35072
  function cloneDef(schema) {
35027
35073
  return mergeDefs(schema._zod.def);
35028
35074
  }
35029
- function getElementAtPath(obj, path12) {
35030
- if (!path12)
35075
+ function getElementAtPath(obj, path15) {
35076
+ if (!path15)
35031
35077
  return obj;
35032
- return path12.reduce((acc, key) => acc?.[key], obj);
35078
+ return path15.reduce((acc, key) => acc?.[key], obj);
35033
35079
  }
35034
35080
  function promiseAllObject(promisesObj) {
35035
35081
  const keys = Object.keys(promisesObj);
@@ -35412,11 +35458,11 @@ function aborted(x2, startIndex = 0) {
35412
35458
  }
35413
35459
  return false;
35414
35460
  }
35415
- function prefixIssues(path12, issues) {
35461
+ function prefixIssues(path15, issues) {
35416
35462
  return issues.map((iss) => {
35417
35463
  var _a2;
35418
35464
  (_a2 = iss).path ?? (_a2.path = []);
35419
- iss.path.unshift(path12);
35465
+ iss.path.unshift(path15);
35420
35466
  return iss;
35421
35467
  });
35422
35468
  }
@@ -35599,7 +35645,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
35599
35645
  }
35600
35646
  function treeifyError(error48, mapper = (issue2) => issue2.message) {
35601
35647
  const result = { errors: [] };
35602
- const processError = (error49, path12 = []) => {
35648
+ const processError = (error49, path15 = []) => {
35603
35649
  var _a2, _b;
35604
35650
  for (const issue2 of error49.issues) {
35605
35651
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -35609,7 +35655,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
35609
35655
  } else if (issue2.code === "invalid_element") {
35610
35656
  processError({ issues: issue2.issues }, issue2.path);
35611
35657
  } else {
35612
- const fullpath = [...path12, ...issue2.path];
35658
+ const fullpath = [...path15, ...issue2.path];
35613
35659
  if (fullpath.length === 0) {
35614
35660
  result.errors.push(mapper(issue2));
35615
35661
  continue;
@@ -35641,8 +35687,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
35641
35687
  }
35642
35688
  function toDotPath(_path) {
35643
35689
  const segs = [];
35644
- const path12 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
35645
- for (const seg of path12) {
35690
+ const path15 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
35691
+ for (const seg of path15) {
35646
35692
  if (typeof seg === "number")
35647
35693
  segs.push(`[${seg}]`);
35648
35694
  else if (typeof seg === "symbol")
@@ -47619,13 +47665,13 @@ function resolveRef(ref, ctx) {
47619
47665
  if (!ref.startsWith("#")) {
47620
47666
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
47621
47667
  }
47622
- const path12 = ref.slice(1).split("/").filter(Boolean);
47623
- if (path12.length === 0) {
47668
+ const path15 = ref.slice(1).split("/").filter(Boolean);
47669
+ if (path15.length === 0) {
47624
47670
  return ctx.rootSchema;
47625
47671
  }
47626
47672
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
47627
- if (path12[0] === defsKey) {
47628
- const key = path12[1];
47673
+ if (path15[0] === defsKey) {
47674
+ const key = path15[1];
47629
47675
  if (!key || !ctx.defs[key]) {
47630
47676
  throw new Error(`Reference not found: ${ref}`);
47631
47677
  }
@@ -48027,6 +48073,417 @@ function date4(params) {
48027
48073
  // ../../node_modules/zod/v4/classic/external.js
48028
48074
  config(en_default());
48029
48075
 
48076
+ // ../server/src/telemetry/derivation.ts
48077
+ var import_node_net = require("node:net");
48078
+
48079
+ // ../../node_modules/ulid/dist/node/index.js
48080
+ var import_node_crypto = __toESM(require("node:crypto"), 1);
48081
+ var ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
48082
+ var ENCODING_LEN = 32;
48083
+ var RANDOM_LEN = 16;
48084
+ var TIME_LEN = 10;
48085
+ var TIME_MAX = 281474976710655;
48086
+ var ULIDErrorCode;
48087
+ (function(ULIDErrorCode2) {
48088
+ ULIDErrorCode2["Base32IncorrectEncoding"] = "B32_ENC_INVALID";
48089
+ ULIDErrorCode2["DecodeTimeInvalidCharacter"] = "DEC_TIME_CHAR";
48090
+ ULIDErrorCode2["DecodeTimeValueMalformed"] = "DEC_TIME_MALFORMED";
48091
+ ULIDErrorCode2["EncodeTimeNegative"] = "ENC_TIME_NEG";
48092
+ ULIDErrorCode2["EncodeTimeSizeExceeded"] = "ENC_TIME_SIZE_EXCEED";
48093
+ ULIDErrorCode2["EncodeTimeValueMalformed"] = "ENC_TIME_MALFORMED";
48094
+ ULIDErrorCode2["PRNGDetectFailure"] = "PRNG_DETECT";
48095
+ ULIDErrorCode2["ULIDInvalid"] = "ULID_INVALID";
48096
+ ULIDErrorCode2["Unexpected"] = "UNEXPECTED";
48097
+ ULIDErrorCode2["UUIDInvalid"] = "UUID_INVALID";
48098
+ })(ULIDErrorCode || (ULIDErrorCode = {}));
48099
+ var ULIDError = class extends Error {
48100
+ constructor(errorCode, message) {
48101
+ super(`${message} (${errorCode})`);
48102
+ this.name = "ULIDError";
48103
+ this.code = errorCode;
48104
+ }
48105
+ };
48106
+ function randomChar(prng) {
48107
+ const randomPosition = Math.floor(prng() * ENCODING_LEN) % ENCODING_LEN;
48108
+ return ENCODING.charAt(randomPosition);
48109
+ }
48110
+ function detectPRNG(root) {
48111
+ const rootLookup = detectRoot();
48112
+ const globalCrypto = rootLookup && (rootLookup.crypto || rootLookup.msCrypto) || (typeof import_node_crypto.default !== "undefined" ? import_node_crypto.default : null);
48113
+ if (typeof globalCrypto?.getRandomValues === "function") {
48114
+ return () => {
48115
+ const buffer = new Uint8Array(1);
48116
+ globalCrypto.getRandomValues(buffer);
48117
+ return buffer[0] / 256;
48118
+ };
48119
+ } else if (typeof globalCrypto?.randomBytes === "function") {
48120
+ return () => globalCrypto.randomBytes(1).readUInt8() / 256;
48121
+ } else if (import_node_crypto.default?.randomBytes) {
48122
+ return () => import_node_crypto.default.randomBytes(1).readUInt8() / 256;
48123
+ }
48124
+ throw new ULIDError(ULIDErrorCode.PRNGDetectFailure, "Failed to find a reliable PRNG");
48125
+ }
48126
+ function detectRoot() {
48127
+ if (inWebWorker())
48128
+ return self;
48129
+ if (typeof window !== "undefined") {
48130
+ return window;
48131
+ }
48132
+ if (typeof global !== "undefined") {
48133
+ return global;
48134
+ }
48135
+ if (typeof globalThis !== "undefined") {
48136
+ return globalThis;
48137
+ }
48138
+ return null;
48139
+ }
48140
+ function encodeRandom(len, prng) {
48141
+ let str = "";
48142
+ for (; len > 0; len--) {
48143
+ str = randomChar(prng) + str;
48144
+ }
48145
+ return str;
48146
+ }
48147
+ function encodeTime(now, len = TIME_LEN) {
48148
+ if (isNaN(now)) {
48149
+ throw new ULIDError(ULIDErrorCode.EncodeTimeValueMalformed, `Time must be a number: ${now}`);
48150
+ } else if (now > TIME_MAX) {
48151
+ throw new ULIDError(ULIDErrorCode.EncodeTimeSizeExceeded, `Cannot encode a time larger than ${TIME_MAX}: ${now}`);
48152
+ } else if (now < 0) {
48153
+ throw new ULIDError(ULIDErrorCode.EncodeTimeNegative, `Time must be positive: ${now}`);
48154
+ } else if (Number.isInteger(now) === false) {
48155
+ throw new ULIDError(ULIDErrorCode.EncodeTimeValueMalformed, `Time must be an integer: ${now}`);
48156
+ }
48157
+ let mod, str = "";
48158
+ for (let currentLen = len; currentLen > 0; currentLen--) {
48159
+ mod = now % ENCODING_LEN;
48160
+ str = ENCODING.charAt(mod) + str;
48161
+ now = (now - mod) / ENCODING_LEN;
48162
+ }
48163
+ return str;
48164
+ }
48165
+ function inWebWorker() {
48166
+ return typeof WorkerGlobalScope !== "undefined" && self instanceof WorkerGlobalScope;
48167
+ }
48168
+ function ulid3(seedTime, prng) {
48169
+ const currentPRNG = prng || detectPRNG();
48170
+ const seed = !seedTime || isNaN(seedTime) ? Date.now() : seedTime;
48171
+ return encodeTime(seed, TIME_LEN) + encodeRandom(RANDOM_LEN, currentPRNG);
48172
+ }
48173
+
48174
+ // ../artifact/src/model.ts
48175
+ var ARTIFACT_PATH_EXTENSIONS = [".md", ".markdown", ".htm", ".html"];
48176
+ var MARKDOWN_PATH_EXTENSIONS = [".md", ".markdown"];
48177
+ var HTML_PATH_EXTENSIONS = [".htm", ".html"];
48178
+ function hasTrailingSeparator(value) {
48179
+ if (value.length === 0) return false;
48180
+ const last = value.at(-1);
48181
+ return last === "/" || last === "\\";
48182
+ }
48183
+ function stripTrailingSeparators(value) {
48184
+ let end = value.length;
48185
+ while (end > 1 && (value[end - 1] === "/" || value[end - 1] === "\\")) {
48186
+ end -= 1;
48187
+ }
48188
+ if (end === 2 && end < value.length && /^[A-Za-z]:$/.test(value.slice(0, 2))) {
48189
+ end += 1;
48190
+ }
48191
+ return value.slice(0, end);
48192
+ }
48193
+ function artifactBasename(value) {
48194
+ const slash = value.lastIndexOf("/");
48195
+ const backslash = value.lastIndexOf("\\");
48196
+ return value.slice(Math.max(slash, backslash) + 1);
48197
+ }
48198
+ function lowerArtifactBasename(value) {
48199
+ return artifactBasename(value).toLowerCase();
48200
+ }
48201
+ function basenameHasExtension(value, extensions) {
48202
+ const basename = lowerArtifactBasename(value);
48203
+ return extensions.some((extension2) => basename.endsWith(extension2));
48204
+ }
48205
+ function isMarkdownPath(value) {
48206
+ return !hasTrailingSeparator(value) && basenameHasExtension(value, MARKDOWN_PATH_EXTENSIONS);
48207
+ }
48208
+ function isHtmlPath(value) {
48209
+ return !hasTrailingSeparator(value) && basenameHasExtension(value, HTML_PATH_EXTENSIONS);
48210
+ }
48211
+ function isAllowedArtifactFilePath(value) {
48212
+ return !hasTrailingSeparator(value) && basenameHasExtension(value, ARTIFACT_PATH_EXTENSIONS);
48213
+ }
48214
+ function isExternalArtifactURL(value) {
48215
+ let parsed;
48216
+ try {
48217
+ parsed = new URL(value);
48218
+ } catch {
48219
+ return false;
48220
+ }
48221
+ return parsed.protocol === "http:" || parsed.protocol === "https:";
48222
+ }
48223
+ function isTvArtifact(url2) {
48224
+ try {
48225
+ const { pathname } = new URL(url2);
48226
+ return /^\/artifact\/[0-9A-Za-z]{26}(\/|$)/.test(pathname);
48227
+ } catch {
48228
+ return false;
48229
+ }
48230
+ }
48231
+ var PathArtifactSchema = external_exports.object({
48232
+ id: external_exports.string().min(1),
48233
+ kind: external_exports.literal("path"),
48234
+ title: external_exports.string(),
48235
+ path: external_exports.string()
48236
+ }).strict();
48237
+ var UrlArtifactSchema = external_exports.object({
48238
+ id: external_exports.string().min(1),
48239
+ kind: external_exports.literal("url"),
48240
+ title: external_exports.string(),
48241
+ url: external_exports.string().refine(isExternalArtifactURL, { message: "url must be an http(s) URL" })
48242
+ }).strict();
48243
+ var ArtifactSchema = external_exports.discriminatedUnion("kind", [PathArtifactSchema, UrlArtifactSchema]);
48244
+ function createArtifact(input) {
48245
+ return ArtifactSchema.parse({ id: input.id ?? ulid3(), ...input });
48246
+ }
48247
+
48248
+ // ../server/src/telemetry/types.ts
48249
+ var telemetryVersionBrand = Symbol("telemetryVersion");
48250
+ function telemetryVersion(value) {
48251
+ return value;
48252
+ }
48253
+ var AGENT_TYPES = [
48254
+ "pi",
48255
+ "opencode",
48256
+ "claude",
48257
+ "codex",
48258
+ "hermes",
48259
+ "openclaw",
48260
+ "cursor",
48261
+ "dot-agents",
48262
+ "interactive-install",
48263
+ "other"
48264
+ ];
48265
+
48266
+ // ../server/src/telemetry/derivation.ts
48267
+ function deriveArtifactProperties(artifact) {
48268
+ if (artifact.kind === "path") {
48269
+ if (hasTrailingSeparator(artifact.path)) {
48270
+ return { artifact_kind: "path", path_kind: "folder" };
48271
+ }
48272
+ return {
48273
+ artifact_kind: "path",
48274
+ path_kind: "file",
48275
+ path_file_type: isHtmlPath(artifact.path) ? "html" : isMarkdownPath(artifact.path) ? "markdown" : "other"
48276
+ };
48277
+ }
48278
+ return {
48279
+ artifact_kind: "url",
48280
+ url_host: classifyUrlHost(artifact.url),
48281
+ url_is_artifact_proxy: isTvArtifact(artifact.url)
48282
+ };
48283
+ }
48284
+ function deriveThemeProperties(input) {
48285
+ return {
48286
+ theme_state: input.activeThemeName === null ? "default" : "custom",
48287
+ theme_count: input.themeCount
48288
+ };
48289
+ }
48290
+ var KNOWN_AGENT_TYPES = AGENT_TYPES.filter((agentType) => agentType !== "dot-agents" && agentType !== "interactive-install" && agentType !== "other");
48291
+ var IPV4_VERSION = 4;
48292
+ var TAILNET_FIRST_OCTET = 100;
48293
+ var TAILNET_MIN_SECOND_OCTET = 64;
48294
+ var TAILNET_MAX_SECOND_OCTET = 127;
48295
+ function deriveAgentTypeFromPath(targetPath) {
48296
+ const tokens = pathTokens(targetPath);
48297
+ const known = KNOWN_AGENT_TYPES.find((agentType) => tokens.includes(agentType));
48298
+ if (known) return { agent_type: known };
48299
+ if (targetPath.split(/[\\/]+/).some((part) => part.toLowerCase() === ".agents")) return { agent_type: "dot-agents" };
48300
+ return { agent_type: "other" };
48301
+ }
48302
+ function normalizeInstalledByAgent(value) {
48303
+ const normalized = value?.trim().toLowerCase() ?? "";
48304
+ return normalized.length === 0 ? {} : { installed_by_agent: normalized };
48305
+ }
48306
+ function deriveServerConfigProperties(input) {
48307
+ return {
48308
+ port: input.port === DEFAULT_SERVER_PORT ? "default" : "custom",
48309
+ storage_path: input.storagePath === (input.defaultStoragePath ?? getDefaultTelevisionStoragePath()) ? "default" : "custom",
48310
+ auth_mode: input.authMode === "auth" ? "auth" : "no-auth",
48311
+ launch_mode: input.launchMode
48312
+ };
48313
+ }
48314
+ function deriveUserAgentProperties(userAgent) {
48315
+ const ua = userAgent ?? "";
48316
+ const browser = parseBrowser(ua);
48317
+ return {
48318
+ client_platform: parsePlatform(ua),
48319
+ browser_vendor: browser.vendor,
48320
+ ...browser.major === void 0 ? {} : { browser_major_version: browser.major }
48321
+ };
48322
+ }
48323
+ function deriveClientProperties(input) {
48324
+ return {
48325
+ client_app: input.clientApp,
48326
+ ...deriveUserAgentProperties(input.userAgent),
48327
+ ...input.desktopAppVersion === void 0 ? {} : { desktop_app_version: input.desktopAppVersion }
48328
+ };
48329
+ }
48330
+ function deriveBindingProperties(addresses) {
48331
+ return {
48332
+ binds_loopback: addresses.some(isLoopbackAddress),
48333
+ binds_all_interfaces: addresses.includes("0.0.0.0"),
48334
+ binds_tailnet: addresses.some(isTailnetIPv4),
48335
+ binds_other_specific: addresses.some((address) => !isLoopbackAddress(address) && address !== "0.0.0.0" && !isTailnetIPv4(address))
48336
+ };
48337
+ }
48338
+ function deriveLayoutChangeProperties(previousLayout, nextLayout) {
48339
+ if (!sameArtifactSet(previousLayout, nextLayout)) return null;
48340
+ const structureChanged = structureSignature(previousLayout) !== structureSignature(nextLayout);
48341
+ if (structureChanged) return { change_type: "move" };
48342
+ const geometryChanged = geometrySignature(previousLayout) !== geometrySignature(nextLayout);
48343
+ if (geometryChanged) return { change_type: "resize" };
48344
+ return null;
48345
+ }
48346
+ function classifyUrlHost(url2) {
48347
+ let parsed;
48348
+ try {
48349
+ parsed = new URL(url2);
48350
+ } catch {
48351
+ return "third-party";
48352
+ }
48353
+ const hostname3 = parsed.hostname.toLowerCase();
48354
+ if (hostname3 === "localhost" || hostname3 === "::1" || hostname3 === "[::1]" || hostname3.startsWith("127.")) {
48355
+ return "localhost";
48356
+ }
48357
+ if (isTailnetIPv4(hostname3)) return "tailnet";
48358
+ return "third-party";
48359
+ }
48360
+ function pathTokens(targetPath) {
48361
+ return targetPath.toLowerCase().split(/[^a-z0-9]+/).filter((token) => token.length > 0);
48362
+ }
48363
+ function parsePlatform(userAgent) {
48364
+ const ua = userAgent.toLowerCase();
48365
+ if (/iphone|ipad|ipod/.test(ua)) return "ios";
48366
+ if (ua.includes("android")) return "android";
48367
+ if (ua.includes("windows nt")) return "windows";
48368
+ if (ua.includes("macintosh") || ua.includes("mac os x")) return "macos";
48369
+ if (ua.includes("linux") || ua.includes("x11")) return "linux";
48370
+ return "other";
48371
+ }
48372
+ function parseBrowser(userAgent) {
48373
+ const edge = parseMajor(userAgent, /\bEdg\/(\d+)/);
48374
+ if (edge !== void 0) return { vendor: "edge", major: edge };
48375
+ const firefox = parseMajor(userAgent, /\bFirefox\/(\d+)/);
48376
+ if (firefox !== void 0) return { vendor: "firefox", major: firefox };
48377
+ const chrome2 = parseMajor(userAgent, /\b(?:HeadlessChrome|Chrome|CriOS)\/(\d+)/);
48378
+ if (chrome2 !== void 0) return { vendor: "chrome", major: chrome2 };
48379
+ const safari = parseMajor(userAgent, /\bVersion\/(\d+)(?:\.\d+)?[^)]*\bSafari\//);
48380
+ if (safari !== void 0) return { vendor: "safari", major: safari };
48381
+ return { vendor: "other" };
48382
+ }
48383
+ function parseMajor(userAgent, pattern) {
48384
+ const match = pattern.exec(userAgent);
48385
+ if (!match) return void 0;
48386
+ const value = Number.parseInt(match[1], 10);
48387
+ return Number.isInteger(value) ? value : void 0;
48388
+ }
48389
+ function sameArtifactSet(previousLayout, nextLayout) {
48390
+ const previous = collectArtifactIDs2(previousLayout).sort();
48391
+ const next = collectArtifactIDs2(nextLayout).sort();
48392
+ return previous.length === next.length && previous.every((artifactID, index) => artifactID === next[index]);
48393
+ }
48394
+ function collectArtifactIDs2(nodes) {
48395
+ return nodes.flatMap((node) => {
48396
+ switch (node.type) {
48397
+ case "card":
48398
+ return [node.artifactID];
48399
+ case "row":
48400
+ return node.children.map((child) => child.artifactID);
48401
+ case "stack":
48402
+ return collectArtifactIDs2(node.children);
48403
+ }
48404
+ });
48405
+ }
48406
+ function structureSignature(nodes) {
48407
+ return JSON.stringify(nodes.map(structureNode));
48408
+ }
48409
+ function structureNode(node) {
48410
+ switch (node.type) {
48411
+ case "card":
48412
+ return { type: "card", artifactID: node.artifactID };
48413
+ case "row":
48414
+ return { type: "row", children: node.children.map(structureNode) };
48415
+ case "stack":
48416
+ return { type: "stack", children: node.children.map(structureNode) };
48417
+ }
48418
+ }
48419
+ function geometrySignature(nodes) {
48420
+ return JSON.stringify(nodes.map(geometryNode));
48421
+ }
48422
+ function geometryNode(node) {
48423
+ switch (node.type) {
48424
+ case "card":
48425
+ return { type: "card", artifactID: node.artifactID, width: node.width, height: node.height };
48426
+ case "row":
48427
+ return { type: "row", height: node.height, children: node.children.map(geometryNode) };
48428
+ case "stack":
48429
+ return { type: "stack", children: node.children.map(geometryNode) };
48430
+ }
48431
+ }
48432
+ function isLoopbackAddress(address) {
48433
+ const normalized = address.toLowerCase();
48434
+ return normalized === "localhost" || normalized === "::1" || normalized === "[::1]" || normalized.startsWith("127.");
48435
+ }
48436
+ function isTailnetIPv4(hostname3) {
48437
+ if ((0, import_node_net.isIP)(hostname3) !== IPV4_VERSION) return false;
48438
+ const [a, b2] = hostname3.split(".").map((part) => Number.parseInt(part, 10));
48439
+ return a === TAILNET_FIRST_OCTET && b2 !== void 0 && b2 >= TAILNET_MIN_SECOND_OCTET && b2 <= TAILNET_MAX_SECOND_OCTET;
48440
+ }
48441
+
48442
+ // ../server/src/telemetry/client-meta.ts
48443
+ function parseClientTelemetryMetaHeader(value) {
48444
+ if (!value) return null;
48445
+ try {
48446
+ return telemetryContextFromMeta(JSON.parse(value));
48447
+ } catch {
48448
+ return null;
48449
+ }
48450
+ }
48451
+ function parseClientTelemetryMetaFromRequest(request) {
48452
+ const parsed = new URL(request.url ?? "/", "http://127.0.0.1");
48453
+ return telemetryContextFromMeta({
48454
+ clientId: parsed.searchParams.get("clientId"),
48455
+ userAgent: parsed.searchParams.get("userAgent"),
48456
+ clientApp: parsed.searchParams.get("clientApp"),
48457
+ desktopAppVersion: parsed.searchParams.get("desktopAppVersion") ?? void 0
48458
+ });
48459
+ }
48460
+ function deriveSessionActivityClientProperties(context) {
48461
+ return deriveClientProperties({
48462
+ clientApp: context.meta.clientApp,
48463
+ userAgent: context.meta.userAgent,
48464
+ ...context.meta.desktopAppVersion ? { desktopAppVersion: telemetryVersion(context.meta.desktopAppVersion) } : {}
48465
+ });
48466
+ }
48467
+ function telemetryContextFromMeta(value) {
48468
+ if (!value || typeof value !== "object") return null;
48469
+ const record2 = value;
48470
+ if (typeof record2.clientId !== "string") return null;
48471
+ const clientId = record2.clientId.trim();
48472
+ if (!clientId) return null;
48473
+ if (record2.clientApp !== "browser" && record2.clientApp !== "desktop") return null;
48474
+ const userAgent = typeof record2.userAgent === "string" ? record2.userAgent : "";
48475
+ const desktopAppVersion = typeof record2.desktopAppVersion === "string" && record2.desktopAppVersion.length > 0 ? record2.desktopAppVersion : void 0;
48476
+ return {
48477
+ clientId,
48478
+ meta: {
48479
+ clientId,
48480
+ userAgent,
48481
+ clientApp: record2.clientApp,
48482
+ ...desktopAppVersion === void 0 ? {} : { desktopAppVersion }
48483
+ }
48484
+ };
48485
+ }
48486
+
48030
48487
  // ../server/src/artifact-proxy.ts
48031
48488
  var import_node_crypto2 = require("node:crypto");
48032
48489
  var import_promises2 = require("node:fs/promises");
@@ -49242,167 +49699,6 @@ var Kt = g.parseInline;
49242
49699
  var Xt = b.parse;
49243
49700
  var Jt = x.lex;
49244
49701
 
49245
- // ../../node_modules/ulid/dist/node/index.js
49246
- var import_node_crypto = __toESM(require("node:crypto"), 1);
49247
- var ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
49248
- var ENCODING_LEN = 32;
49249
- var RANDOM_LEN = 16;
49250
- var TIME_LEN = 10;
49251
- var TIME_MAX = 281474976710655;
49252
- var ULIDErrorCode;
49253
- (function(ULIDErrorCode2) {
49254
- ULIDErrorCode2["Base32IncorrectEncoding"] = "B32_ENC_INVALID";
49255
- ULIDErrorCode2["DecodeTimeInvalidCharacter"] = "DEC_TIME_CHAR";
49256
- ULIDErrorCode2["DecodeTimeValueMalformed"] = "DEC_TIME_MALFORMED";
49257
- ULIDErrorCode2["EncodeTimeNegative"] = "ENC_TIME_NEG";
49258
- ULIDErrorCode2["EncodeTimeSizeExceeded"] = "ENC_TIME_SIZE_EXCEED";
49259
- ULIDErrorCode2["EncodeTimeValueMalformed"] = "ENC_TIME_MALFORMED";
49260
- ULIDErrorCode2["PRNGDetectFailure"] = "PRNG_DETECT";
49261
- ULIDErrorCode2["ULIDInvalid"] = "ULID_INVALID";
49262
- ULIDErrorCode2["Unexpected"] = "UNEXPECTED";
49263
- ULIDErrorCode2["UUIDInvalid"] = "UUID_INVALID";
49264
- })(ULIDErrorCode || (ULIDErrorCode = {}));
49265
- var ULIDError = class extends Error {
49266
- constructor(errorCode, message) {
49267
- super(`${message} (${errorCode})`);
49268
- this.name = "ULIDError";
49269
- this.code = errorCode;
49270
- }
49271
- };
49272
- function randomChar(prng) {
49273
- const randomPosition = Math.floor(prng() * ENCODING_LEN) % ENCODING_LEN;
49274
- return ENCODING.charAt(randomPosition);
49275
- }
49276
- function detectPRNG(root) {
49277
- const rootLookup = detectRoot();
49278
- const globalCrypto = rootLookup && (rootLookup.crypto || rootLookup.msCrypto) || (typeof import_node_crypto.default !== "undefined" ? import_node_crypto.default : null);
49279
- if (typeof globalCrypto?.getRandomValues === "function") {
49280
- return () => {
49281
- const buffer = new Uint8Array(1);
49282
- globalCrypto.getRandomValues(buffer);
49283
- return buffer[0] / 256;
49284
- };
49285
- } else if (typeof globalCrypto?.randomBytes === "function") {
49286
- return () => globalCrypto.randomBytes(1).readUInt8() / 256;
49287
- } else if (import_node_crypto.default?.randomBytes) {
49288
- return () => import_node_crypto.default.randomBytes(1).readUInt8() / 256;
49289
- }
49290
- throw new ULIDError(ULIDErrorCode.PRNGDetectFailure, "Failed to find a reliable PRNG");
49291
- }
49292
- function detectRoot() {
49293
- if (inWebWorker())
49294
- return self;
49295
- if (typeof window !== "undefined") {
49296
- return window;
49297
- }
49298
- if (typeof global !== "undefined") {
49299
- return global;
49300
- }
49301
- if (typeof globalThis !== "undefined") {
49302
- return globalThis;
49303
- }
49304
- return null;
49305
- }
49306
- function encodeRandom(len, prng) {
49307
- let str = "";
49308
- for (; len > 0; len--) {
49309
- str = randomChar(prng) + str;
49310
- }
49311
- return str;
49312
- }
49313
- function encodeTime(now, len = TIME_LEN) {
49314
- if (isNaN(now)) {
49315
- throw new ULIDError(ULIDErrorCode.EncodeTimeValueMalformed, `Time must be a number: ${now}`);
49316
- } else if (now > TIME_MAX) {
49317
- throw new ULIDError(ULIDErrorCode.EncodeTimeSizeExceeded, `Cannot encode a time larger than ${TIME_MAX}: ${now}`);
49318
- } else if (now < 0) {
49319
- throw new ULIDError(ULIDErrorCode.EncodeTimeNegative, `Time must be positive: ${now}`);
49320
- } else if (Number.isInteger(now) === false) {
49321
- throw new ULIDError(ULIDErrorCode.EncodeTimeValueMalformed, `Time must be an integer: ${now}`);
49322
- }
49323
- let mod, str = "";
49324
- for (let currentLen = len; currentLen > 0; currentLen--) {
49325
- mod = now % ENCODING_LEN;
49326
- str = ENCODING.charAt(mod) + str;
49327
- now = (now - mod) / ENCODING_LEN;
49328
- }
49329
- return str;
49330
- }
49331
- function inWebWorker() {
49332
- return typeof WorkerGlobalScope !== "undefined" && self instanceof WorkerGlobalScope;
49333
- }
49334
- function ulid3(seedTime, prng) {
49335
- const currentPRNG = prng || detectPRNG();
49336
- const seed = !seedTime || isNaN(seedTime) ? Date.now() : seedTime;
49337
- return encodeTime(seed, TIME_LEN) + encodeRandom(RANDOM_LEN, currentPRNG);
49338
- }
49339
-
49340
- // ../artifact/src/model.ts
49341
- var ARTIFACT_PATH_EXTENSIONS = [".md", ".markdown", ".htm", ".html"];
49342
- var MARKDOWN_PATH_EXTENSIONS = [".md", ".markdown"];
49343
- var HTML_PATH_EXTENSIONS = [".htm", ".html"];
49344
- function hasTrailingSeparator(value) {
49345
- if (value.length === 0) return false;
49346
- const last = value.at(-1);
49347
- return last === "/" || last === "\\";
49348
- }
49349
- function stripTrailingSeparators(value) {
49350
- let end = value.length;
49351
- while (end > 1 && (value[end - 1] === "/" || value[end - 1] === "\\")) {
49352
- end -= 1;
49353
- }
49354
- if (end === 2 && end < value.length && /^[A-Za-z]:$/.test(value.slice(0, 2))) {
49355
- end += 1;
49356
- }
49357
- return value.slice(0, end);
49358
- }
49359
- function artifactBasename(value) {
49360
- const slash = value.lastIndexOf("/");
49361
- const backslash = value.lastIndexOf("\\");
49362
- return value.slice(Math.max(slash, backslash) + 1);
49363
- }
49364
- function lowerArtifactBasename(value) {
49365
- return artifactBasename(value).toLowerCase();
49366
- }
49367
- function basenameHasExtension(value, extensions) {
49368
- const basename = lowerArtifactBasename(value);
49369
- return extensions.some((extension2) => basename.endsWith(extension2));
49370
- }
49371
- function isMarkdownPath(value) {
49372
- return !hasTrailingSeparator(value) && basenameHasExtension(value, MARKDOWN_PATH_EXTENSIONS);
49373
- }
49374
- function isHtmlPath(value) {
49375
- return !hasTrailingSeparator(value) && basenameHasExtension(value, HTML_PATH_EXTENSIONS);
49376
- }
49377
- function isAllowedArtifactFilePath(value) {
49378
- return !hasTrailingSeparator(value) && basenameHasExtension(value, ARTIFACT_PATH_EXTENSIONS);
49379
- }
49380
- function isExternalArtifactURL(value) {
49381
- let parsed;
49382
- try {
49383
- parsed = new URL(value);
49384
- } catch {
49385
- return false;
49386
- }
49387
- return parsed.protocol === "http:" || parsed.protocol === "https:";
49388
- }
49389
- var PathArtifactSchema = external_exports.object({
49390
- id: external_exports.string().min(1),
49391
- kind: external_exports.literal("path"),
49392
- title: external_exports.string(),
49393
- path: external_exports.string()
49394
- }).strict();
49395
- var UrlArtifactSchema = external_exports.object({
49396
- id: external_exports.string().min(1),
49397
- kind: external_exports.literal("url"),
49398
- title: external_exports.string(),
49399
- url: external_exports.string().refine(isExternalArtifactURL, { message: "url must be an http(s) URL" })
49400
- }).strict();
49401
- var ArtifactSchema = external_exports.discriminatedUnion("kind", [PathArtifactSchema, UrlArtifactSchema]);
49402
- function createArtifact(input) {
49403
- return ArtifactSchema.parse({ id: input.id ?? ulid3(), ...input });
49404
- }
49405
-
49406
49702
  // ../disposable/src/index.ts
49407
49703
  function wrapDispose(target, isDisposed, setDisposed) {
49408
49704
  const disposeImpl = target.dispose.bind(target);
@@ -49445,14 +49741,41 @@ var DisposableArtifactContextEventTarget = withDisposable(
49445
49741
 
49446
49742
  // ../artifact/src/browser/artifact-bridge.ts
49447
49743
  function installBridge(win = window, options = {}) {
49448
- if (win.parent === win) {
49449
- return;
49450
- }
49451
49744
  const bridgeWindow = win;
49452
49745
  if (bridgeWindow.__televisionArtifactBridgeInstalled === true) {
49453
49746
  return;
49454
49747
  }
49455
49748
  bridgeWindow.__televisionArtifactBridgeInstalled = true;
49749
+ if (win.parent === win) {
49750
+ return;
49751
+ }
49752
+ const makeBridgeGuid = () => {
49753
+ const GUID_RADIX = 36;
49754
+ const GUID_WORD_COUNT = 4;
49755
+ const now = Date.now().toString(GUID_RADIX);
49756
+ try {
49757
+ const cryptoLike = win.crypto;
49758
+ if (cryptoLike && typeof cryptoLike.getRandomValues === "function") {
49759
+ const values = new Uint32Array(GUID_WORD_COUNT);
49760
+ cryptoLike.getRandomValues(values);
49761
+ return `tvb-${now}-${Array.from(values, (value) => value.toString(GUID_RADIX)).join("-")}`;
49762
+ }
49763
+ } catch {
49764
+ }
49765
+ return `tvb-${now}-${Math.random().toString(GUID_RADIX).slice(2)}-${Math.random().toString(GUID_RADIX).slice(2)}`;
49766
+ };
49767
+ const documentGuid = makeBridgeGuid();
49768
+ const postBridgeReady = () => {
49769
+ win.parent.postMessage({ type: "bridge-ready", url: win.location.href, guid: documentGuid }, "*");
49770
+ };
49771
+ win.addEventListener("pagehide", () => {
49772
+ win.parent.postMessage({ type: "leaving", guid: documentGuid }, "*");
49773
+ });
49774
+ win.addEventListener("pageshow", (event) => {
49775
+ if (event.persisted === true) {
49776
+ postBridgeReady();
49777
+ }
49778
+ });
49456
49779
  const capturedURL = win.location.href;
49457
49780
  const isTvArtifactURL = (url2) => {
49458
49781
  try {
@@ -49775,6 +50098,7 @@ function installBridge(win = window, options = {}) {
49775
50098
  }
49776
50099
  win.parent.postMessage({ type: "swipe-end", velocityX: 0 }, "*");
49777
50100
  });
50101
+ postBridgeReady();
49778
50102
  }
49779
50103
  function bridgeScriptSource() {
49780
50104
  return `(function(){const __name=(target)=>target;(${installBridge.toString()})(window);})();`;
@@ -50339,6 +50663,19 @@ function themeExists(storagePath, name) {
50339
50663
  return false;
50340
50664
  }
50341
50665
  }
50666
+ function listThemeNames(storagePath) {
50667
+ const themesDir = getThemesDir(storagePath);
50668
+ if (!(0, import_node_fs5.existsSync)(themesDir)) {
50669
+ return [];
50670
+ }
50671
+ let entries;
50672
+ try {
50673
+ entries = (0, import_node_fs5.readdirSync)(themesDir);
50674
+ } catch {
50675
+ return [];
50676
+ }
50677
+ return entries.filter((name) => themeExists(storagePath, name)).sort((left, right) => left.localeCompare(right));
50678
+ }
50342
50679
  function rewriteThemeURLs(css, themeName) {
50343
50680
  return css.replace(URL_RE, (whole, quote, url2) => {
50344
50681
  if (/^(data:|https?:)/.test(url2) || url2.startsWith("/")) {
@@ -50438,7 +50775,7 @@ var HTTP_CONFLICT = 409;
50438
50775
  var CORS_HEADERS = {
50439
50776
  "Access-Control-Allow-Origin": "*",
50440
50777
  "Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
50441
- "Access-Control-Allow-Headers": "Authorization, Content-Type"
50778
+ "Access-Control-Allow-Headers": `Authorization, Content-Type, ${TELEVISION_CLIENT_META_HEADER}`
50442
50779
  };
50443
50780
  function applyCorsHeaders(res) {
50444
50781
  for (const [name, value] of Object.entries(CORS_HEADERS)) {
@@ -50470,11 +50807,20 @@ function handleStoreError(res, error48, fallback) {
50470
50807
  function registerRoutes(app, store, options) {
50471
50808
  const auth = options.requireAuth ? [options.requireAuth] : [];
50472
50809
  const bearerAuth = options.requireBearerAuth ? [options.requireBearerAuth] : [];
50473
- app.use("/screens", applyCorsMiddleware);
50474
- app.use("/artifacts", applyCorsMiddleware);
50475
- app.use("/display", applyCorsMiddleware);
50476
- app.use("/themes", applyCorsMiddleware);
50477
- app.use("/markdown", applyCorsMiddleware);
50810
+ const telemetryContexts = /* @__PURE__ */ new WeakMap();
50811
+ const telemetryMiddleware = (req, _res, next) => {
50812
+ const clientContext = parseClientTelemetryMetaHeader(req.header(TELEVISION_CLIENT_META_HEADER));
50813
+ telemetryContexts.set(req, clientContext);
50814
+ options.observeTelemetryClientRequest?.(clientContext);
50815
+ next();
50816
+ };
50817
+ const telemetryContext = (req) => telemetryContexts.get(req) ?? null;
50818
+ app.use("/screens", applyCorsMiddleware, telemetryMiddleware);
50819
+ app.use("/artifacts", applyCorsMiddleware, telemetryMiddleware);
50820
+ app.use("/display", applyCorsMiddleware, telemetryMiddleware);
50821
+ app.use("/themes", applyCorsMiddleware, telemetryMiddleware);
50822
+ app.use("/markdown", applyCorsMiddleware, telemetryMiddleware);
50823
+ app.use("/telemetry", applyCorsMiddleware);
50478
50824
  app.all("/artifact/:id", serveArtifactProxy(store));
50479
50825
  app.all("/artifact/:id/*", serveArtifactProxy(store));
50480
50826
  const markdownContent = serveMarkdownContent(store);
@@ -50489,6 +50835,18 @@ function registerRoutes(app, store, options) {
50489
50835
  app.options("/themes/:name/theme.css", (_req, res) => res.status(HTTP_NO_CONTENT2).end());
50490
50836
  app.options("/themes/:name/*", (_req, res) => res.status(HTTP_NO_CONTENT2).end());
50491
50837
  app.options("/markdown/:id", (_req, res) => res.status(HTTP_NO_CONTENT2).end());
50838
+ app.options("/telemetry", (_req, res) => res.status(HTTP_NO_CONTENT2).end());
50839
+ app.options("/telemetry/enable", (_req, res) => res.status(HTTP_NO_CONTENT2).end());
50840
+ app.options("/telemetry/disable", (_req, res) => res.status(HTTP_NO_CONTENT2).end());
50841
+ app.get("/telemetry", ...auth, (_req, res) => {
50842
+ res.json(options.getTelemetryStatus?.() ?? { state: "unavailable", reason: null, guidPresent: false, region: "us" });
50843
+ });
50844
+ app.post("/telemetry/enable", ...auth, async (_req, res) => {
50845
+ res.json(await options.enableTelemetry?.() ?? { state: "unavailable", reason: null, guidPresent: false, region: "us" });
50846
+ });
50847
+ app.post("/telemetry/disable", ...auth, async (_req, res) => {
50848
+ res.json(await options.disableTelemetry?.() ?? { state: "unavailable", reason: null, guidPresent: false, region: "us" });
50849
+ });
50492
50850
  app.get("/screens", ...auth, (_req, res) => {
50493
50851
  res.json({ screens: store.listScreens() });
50494
50852
  });
@@ -50502,7 +50860,7 @@ function registerRoutes(app, store, options) {
50502
50860
  const screen = store.createScreen({
50503
50861
  name: parsed.data.name,
50504
50862
  ...parsed.data.id !== void 0 ? { id: parsed.data.id } : {}
50505
- });
50863
+ }, telemetryContext(req));
50506
50864
  res.status(HTTP_CREATED).json({ screen });
50507
50865
  } catch (error48) {
50508
50866
  sendError(res, HTTP_BAD_REQUEST, error48 instanceof Error ? error48.message : "Failed to create screen");
@@ -50518,7 +50876,7 @@ function registerRoutes(app, store, options) {
50518
50876
  });
50519
50877
  app.delete("/screens/:id", ...auth, (req, res) => {
50520
50878
  try {
50521
- const result = store.removeScreen(req.params.id);
50879
+ const result = store.removeScreen(req.params.id, telemetryContext(req));
50522
50880
  res.json(result);
50523
50881
  } catch (error48) {
50524
50882
  handleStoreError(res, error48, "Failed to delete screen");
@@ -50541,7 +50899,7 @@ function registerRoutes(app, store, options) {
50541
50899
  const screen = store.updateScreen({
50542
50900
  screenID: req.params.id,
50543
50901
  fields: { ...parsed.data, layout: parsed.data.layout }
50544
- });
50902
+ }, telemetryContext(req));
50545
50903
  res.json({ screen });
50546
50904
  } catch (error48) {
50547
50905
  handleStoreError(res, error48, "Failed to update screen");
@@ -50568,7 +50926,7 @@ function registerRoutes(app, store, options) {
50568
50926
  return;
50569
50927
  }
50570
50928
  try {
50571
- const artifact = store.createArtifact(parsed.data);
50929
+ const artifact = store.createArtifact(parsed.data, telemetryContext(req));
50572
50930
  res.status(HTTP_CREATED).json({ artifact, screenID: parsed.data.screenID });
50573
50931
  } catch (error48) {
50574
50932
  handleStoreError(res, error48, "Failed to create artifact");
@@ -50576,7 +50934,7 @@ function registerRoutes(app, store, options) {
50576
50934
  });
50577
50935
  app.delete("/artifacts/:id", ...auth, (req, res) => {
50578
50936
  try {
50579
- const result = store.deleteArtifact(req.params.id);
50937
+ const result = store.deleteArtifact(req.params.id, telemetryContext(req));
50580
50938
  res.json(result);
50581
50939
  } catch (error48) {
50582
50940
  handleStoreError(res, error48, "Failed to delete artifact");
@@ -50589,7 +50947,7 @@ function registerRoutes(app, store, options) {
50589
50947
  return;
50590
50948
  }
50591
50949
  try {
50592
- const artifact = store.updateArtifact({ artifactID: req.params.id, fields: parsed.data });
50950
+ const artifact = store.updateArtifact({ artifactID: req.params.id, fields: parsed.data }, telemetryContext(req));
50593
50951
  res.json({ artifact });
50594
50952
  } catch (error48) {
50595
50953
  handleStoreError(res, error48, "Failed to update artifact");
@@ -50613,7 +50971,7 @@ function registerRoutes(app, store, options) {
50613
50971
  return;
50614
50972
  }
50615
50973
  try {
50616
- store.patchDisplay(parsed.data);
50974
+ store.patchDisplay(parsed.data, telemetryContext(req));
50617
50975
  res.status(HTTP_NO_CONTENT2).end();
50618
50976
  } catch (error48) {
50619
50977
  handleStoreError(res, error48, "Failed to patch display");
@@ -50672,18 +51030,23 @@ var EventStreamServer = class extends withDisposable(class {
50672
51030
  wsServer;
50673
51031
  store;
50674
51032
  authRequired;
51033
+ recordTelemetryActivity;
50675
51034
  unsubscribe = [];
50676
51035
  constructor(options) {
50677
51036
  super();
50678
51037
  this.store = options.store;
50679
51038
  this.authRequired = options.authRequired;
51039
+ this.recordTelemetryActivity = options.recordTelemetryActivity;
50680
51040
  this.wsServer = new import_websocket_server.default({ noServer: true });
50681
51041
  this.wsServer.on("connection", (socket, request) => {
50682
51042
  if (this.authRequired && !isAuthorizedQueryToken(request.url, this.store.authToken)) {
50683
51043
  socket.close(AUTH_FAILED_CLOSE_CODE, "Authentication failed");
50684
51044
  return;
50685
51045
  }
50686
- socket.on("message", (_data) => {
51046
+ const clientContext = parseClientTelemetryMetaFromRequest(request);
51047
+ socket.on("message", (data) => {
51048
+ if (!isTelemetryActivityMessage(data, clientContext?.clientId ?? null)) return;
51049
+ if (clientContext) this.recordTelemetryActivity?.(clientContext);
50687
51050
  });
50688
51051
  });
50689
51052
  this.subscribeStore();
@@ -50781,6 +51144,18 @@ var EventStreamServer = class extends withDisposable(class {
50781
51144
  }
50782
51145
  }
50783
51146
  };
51147
+ function isTelemetryActivityMessage(data, expectedClientId) {
51148
+ if (!expectedClientId) return false;
51149
+ let parsed;
51150
+ try {
51151
+ parsed = JSON.parse(data.toString());
51152
+ } catch {
51153
+ return false;
51154
+ }
51155
+ if (!parsed || typeof parsed !== "object") return false;
51156
+ const record2 = parsed;
51157
+ return record2.type === TELEMETRY_ACTIVITY_MESSAGE_TYPE && record2.clientId === expectedClientId && Object.keys(record2).length === 2;
51158
+ }
50784
51159
 
50785
51160
  // ../server/src/acp-bridge.ts
50786
51161
  var import_node_child_process2 = require("node:child_process");
@@ -51063,13 +51438,13 @@ var ACPServer = class extends withDisposable(class {
51063
51438
  };
51064
51439
 
51065
51440
  // ../server/src/bind-addresses.ts
51066
- var import_node_net = require("node:net");
51441
+ var import_node_net2 = require("node:net");
51067
51442
  var LOCALHOST_IPV4 = "127.0.0.1";
51068
51443
  var ANY_IPV4 = "0.0.0.0";
51069
51444
  function resolveBindAddresses(listenValues = []) {
51070
51445
  const addresses = [LOCALHOST_IPV4];
51071
51446
  for (const address of splitListenValues(listenValues)) {
51072
- if (!(0, import_node_net.isIPv4)(address)) {
51447
+ if (!(0, import_node_net2.isIPv4)(address)) {
51073
51448
  throw new Error(`Invalid --listen address \`${address}\`. Use an IPv4 address.`);
51074
51449
  }
51075
51450
  addresses.push(address);
@@ -51313,7 +51688,715 @@ function pad2(value) {
51313
51688
  return String(value).padStart(2, "0");
51314
51689
  }
51315
51690
 
51691
+ // ../server/src/telemetry/emitters.ts
51692
+ var MEDIAN_PAIR_DIVISOR = 2;
51693
+ function createServerStoreTelemetryHooks(store, capture2) {
51694
+ return {
51695
+ artifactCreated(artifact, clientContext) {
51696
+ safeEmit(() => {
51697
+ const totals = deriveContentTotalsProperties(store);
51698
+ capture2({
51699
+ name: "artifact_created",
51700
+ properties: { ...deriveArtifactProperties(artifact), ...totals },
51701
+ personProperties: totals
51702
+ }, clientContext);
51703
+ });
51704
+ },
51705
+ artifactUpdated(artifact, clientContext) {
51706
+ safeEmit(() => capture2({ name: "artifact_updated", properties: deriveArtifactProperties(artifact) }, clientContext));
51707
+ },
51708
+ artifactDeleted(artifact, clientContext) {
51709
+ safeEmit(() => {
51710
+ const totals = deriveContentTotalsProperties(store);
51711
+ capture2({
51712
+ name: "artifact_deleted",
51713
+ properties: { ...deriveArtifactProperties(artifact), ...totals },
51714
+ personProperties: totals
51715
+ }, clientContext);
51716
+ });
51717
+ },
51718
+ screenCreated(_screen, clientContext) {
51719
+ safeEmit(() => {
51720
+ const totals = deriveContentTotalsProperties(store);
51721
+ capture2({ name: "screen_created", properties: totals, personProperties: totals }, clientContext);
51722
+ });
51723
+ },
51724
+ screenUpdated(_screen, clientContext) {
51725
+ safeEmit(() => capture2({ name: "screen_updated" }, clientContext));
51726
+ },
51727
+ screenDeleted(_screen, clientContext) {
51728
+ safeEmit(() => {
51729
+ const totals = deriveContentTotalsProperties(store);
51730
+ capture2({ name: "screen_deleted", properties: totals, personProperties: totals }, clientContext);
51731
+ });
51732
+ },
51733
+ screenLayoutChanged(previousLayout, nextLayout, clientContext) {
51734
+ safeEmit(() => {
51735
+ const properties = deriveLayoutChangeProperties(previousLayout, nextLayout);
51736
+ if (properties) capture2({ name: "layout_changed", properties }, clientContext);
51737
+ });
51738
+ },
51739
+ themeChanged(clientContext) {
51740
+ safeEmit(() => {
51741
+ capture2({
51742
+ name: "theme_changed",
51743
+ properties: deriveThemeProperties({
51744
+ activeThemeName: store.getActiveThemeName(),
51745
+ themeCount: listThemeNames(store.storagePath).length
51746
+ })
51747
+ }, clientContext);
51748
+ });
51749
+ }
51750
+ };
51751
+ }
51752
+ function deriveContentTotalsProperties(store) {
51753
+ const screens = store.listScreens();
51754
+ const totalScreens = screens.length;
51755
+ const totalArtifacts = store.listArtifacts().length;
51756
+ const artifactCounts = screens.map((screen) => getScreenArtifactIDs(screen).length);
51757
+ return {
51758
+ total_screens: totalScreens,
51759
+ total_artifacts: totalArtifacts,
51760
+ median_artifacts_per_screen: median(artifactCounts),
51761
+ average_artifacts_per_screen: totalScreens === 0 ? 0 : totalArtifacts / totalScreens
51762
+ };
51763
+ }
51764
+ function deriveServerConfigSnapshotProperties(input) {
51765
+ return {
51766
+ server_version: telemetryVersion(input.version),
51767
+ ...deriveServerConfigProperties({
51768
+ port: input.port,
51769
+ storagePath: input.storagePath,
51770
+ authMode: input.authMode,
51771
+ launchMode: input.launchMode,
51772
+ ...input.defaultStoragePath === void 0 ? {} : { defaultStoragePath: input.defaultStoragePath }
51773
+ }),
51774
+ ...deriveBindingProperties(input.bindAddresses),
51775
+ ...normalizeInstalledByAgent(input.installedByAgent)
51776
+ };
51777
+ }
51778
+ function emitServerBootTelemetry(capture2, events, serverConfig, telemetryPreference) {
51779
+ safeEmit(() => {
51780
+ for (const event of events) {
51781
+ if (event.name === "server_started") {
51782
+ capture2({
51783
+ name: "server_started",
51784
+ properties: serverConfig,
51785
+ personProperties: { ...serverConfig, ...telemetryPreference }
51786
+ });
51787
+ continue;
51788
+ }
51789
+ capture2(event);
51790
+ }
51791
+ });
51792
+ }
51793
+ function median(values) {
51794
+ if (values.length === 0) return 0;
51795
+ const sorted = [...values].sort((left, right) => left - right);
51796
+ const middle = Math.floor(sorted.length / MEDIAN_PAIR_DIVISOR);
51797
+ if (sorted.length % MEDIAN_PAIR_DIVISOR === 1) return sorted[middle];
51798
+ return (sorted[middle - 1] + sorted[middle]) / MEDIAN_PAIR_DIVISOR;
51799
+ }
51800
+ function safeEmit(callback) {
51801
+ try {
51802
+ callback();
51803
+ } catch {
51804
+ }
51805
+ }
51806
+
51807
+ // ../server/src/telemetry/identity.ts
51808
+ var import_node_crypto5 = require("node:crypto");
51809
+ var import_promises4 = require("node:fs/promises");
51810
+ var import_node_path9 = __toESM(require("node:path"), 1);
51811
+
51812
+ // ../server/src/artifact-paths.ts
51813
+ var import_node_path8 = __toESM(require("node:path"), 1);
51814
+ function getStateDir(storagePath) {
51815
+ return import_node_path8.default.join(storagePath, "state");
51816
+ }
51817
+ function getScreensDir(storagePath) {
51818
+ return import_node_path8.default.join(getStateDir(storagePath), "screens");
51819
+ }
51820
+ function getArtifactsMetadataDir(storagePath) {
51821
+ return import_node_path8.default.join(getStateDir(storagePath), "artifacts");
51822
+ }
51823
+ function getDisplayStatePath(storagePath) {
51824
+ return import_node_path8.default.join(getStateDir(storagePath), "display.json");
51825
+ }
51826
+ function getTelemetryStatePath(storagePath) {
51827
+ return import_node_path8.default.join(getStateDir(storagePath), "telemetry.json");
51828
+ }
51829
+ function getTokenPath(storagePath) {
51830
+ return import_node_path8.default.join(getStateDir(storagePath), "token");
51831
+ }
51832
+ function getOnboardingArtifactSentinelPath(storagePath) {
51833
+ return import_node_path8.default.join(getStateDir(storagePath), "onboarding-artifact.json");
51834
+ }
51835
+ function getAgentArtifactsDir(storagePath) {
51836
+ return import_node_path8.default.join(...[storagePath, "artifacts"]);
51837
+ }
51838
+ function getArtifactLiveMetadataPath(storagePath, artifactID) {
51839
+ return import_node_path8.default.join(getArtifactsMetadataDir(storagePath), `${artifactID}.json`);
51840
+ }
51841
+
51842
+ // ../server/src/telemetry/identity.ts
51843
+ var TELEMETRY_STATE_SCHEMA_VERSION = 1;
51844
+ var SEMVER_MAJOR_CAPTURE_INDEX = 1;
51845
+ var SEMVER_MINOR_CAPTURE_INDEX = 2;
51846
+ var SEMVER_PATCH_CAPTURE_INDEX = 3;
51847
+ var SEMVER_PRERELEASE_CAPTURE_INDEX = 4;
51848
+ async function readTelemetryState(storagePath) {
51849
+ try {
51850
+ return normalizeTelemetryState(JSON.parse(await (0, import_promises4.readFile)(getTelemetryStatePath(storagePath), "utf8")));
51851
+ } catch (error48) {
51852
+ if (isNodeError(error48) && error48.code === "ENOENT") return null;
51853
+ if (error48 instanceof SyntaxError || error48 instanceof InvalidTelemetryStateError) return null;
51854
+ throw error48;
51855
+ }
51856
+ }
51857
+ async function writeTelemetryState(storagePath, state) {
51858
+ const statePath = getTelemetryStatePath(storagePath);
51859
+ await (0, import_promises4.mkdir)(import_node_path9.default.dirname(statePath), { recursive: true });
51860
+ const tempPath = `${statePath}.${process.pid}.${Date.now()}.tmp`;
51861
+ await (0, import_promises4.writeFile)(tempPath, `${JSON.stringify(state, null, 2)}
51862
+ `, "utf8");
51863
+ await (0, import_promises4.rename)(tempPath, statePath);
51864
+ }
51865
+ async function loadOrMintTelemetryState(storagePath, options = {}) {
51866
+ const existing = await readTelemetryState(storagePath);
51867
+ if (existing) return { state: existing, created: false };
51868
+ const state = {
51869
+ schemaVersion: TELEMETRY_STATE_SCHEMA_VERSION,
51870
+ userId: options.userIdFactory?.() ?? (0, import_node_crypto5.randomUUID)(),
51871
+ optedOut: false,
51872
+ lastVersion: options.lastVersion ?? ""
51873
+ };
51874
+ await writeTelemetryState(storagePath, state);
51875
+ return { state, created: true };
51876
+ }
51877
+ async function deriveBootTelemetry(storagePath, runningVersion, options) {
51878
+ const loaded = await loadOrMintTelemetryState(storagePath, {
51879
+ lastVersion: "",
51880
+ userIdFactory: options.userIdFactory
51881
+ });
51882
+ const previousVersion = loaded.state.lastVersion.trim() || null;
51883
+ const installed = options.dataDirCreated;
51884
+ const upgraded = !installed && (previousVersion === null || isTelemetryVersionOlder(previousVersion, runningVersion));
51885
+ const events = [];
51886
+ if (installed) events.push({ name: "server_installed", personProperties: { pre_telemetry: false } });
51887
+ if (upgraded) {
51888
+ const preTelemetryAdoption = previousVersion === null;
51889
+ events.push({
51890
+ name: "server_upgraded",
51891
+ properties: {
51892
+ ...preTelemetryAdoption ? { pre_telemetry: true } : { old_version: telemetryVersion(previousVersion) },
51893
+ new_version: telemetryVersion(runningVersion)
51894
+ },
51895
+ ...preTelemetryAdoption ? { personProperties: { pre_telemetry: true } } : {}
51896
+ });
51897
+ }
51898
+ events.push({ name: "server_started" });
51899
+ const nextState = { ...loaded.state, lastVersion: runningVersion };
51900
+ if (nextState.lastVersion !== loaded.state.lastVersion) {
51901
+ await writeTelemetryState(storagePath, nextState);
51902
+ }
51903
+ return {
51904
+ state: nextState,
51905
+ events,
51906
+ installed,
51907
+ upgraded,
51908
+ previousVersion
51909
+ };
51910
+ }
51911
+ async function setTelemetryOptedOut(storagePath, state, optedOut) {
51912
+ const nextState = { ...state, optedOut };
51913
+ await writeTelemetryState(storagePath, nextState);
51914
+ return nextState;
51915
+ }
51916
+ function telemetryEnabled(env, state) {
51917
+ if (state.optedOut) return false;
51918
+ return telemetryEnvironmentSuppressionReason(env) === null;
51919
+ }
51920
+ function telemetryEnvironmentSuppressionReason(env) {
51921
+ if (isEnabledEnvFlag(env.DO_NOT_TRACK)) return "do-not-track";
51922
+ if (isEnabledEnvFlag(env.CI)) return "ci";
51923
+ if (!isProductionTelemetryBuild(env) && !isTelemetryDevMode(env)) return "development";
51924
+ return null;
51925
+ }
51926
+ function telemetryStatus(env, state) {
51927
+ const reason = telemetryEnvironmentSuppressionReason(env);
51928
+ if (reason) return { state: "suppressed", reason, guidPresent: state !== null, region: "us" };
51929
+ if (state?.optedOut) return { state: "opted-out", reason: null, guidPresent: true, region: "us" };
51930
+ if (state) return { state: "active", reason: null, guidPresent: true, region: "us" };
51931
+ return { state: "unavailable", reason: null, guidPresent: false, region: "us" };
51932
+ }
51933
+ function isTelemetryDevMode(env) {
51934
+ return isEnabledEnvFlag(env.TV_TELEMETRY_DEV);
51935
+ }
51936
+ function telemetryBuildMarker(env) {
51937
+ const explicitBuild = env.TELEVISION_TELEMETRY_BUILD?.trim().toLowerCase();
51938
+ if (explicitBuild) return explicitBuild;
51939
+ const bundledBuild = bundledTelemetryBuildMarker()?.trim().toLowerCase();
51940
+ if (bundledBuild) return bundledBuild;
51941
+ if (env.NODE_ENV === "production") return "production";
51942
+ return null;
51943
+ }
51944
+ function isProductionTelemetryBuild(env) {
51945
+ return telemetryBuildMarker(env) === "production";
51946
+ }
51947
+ function isTelemetryVersionOlder(previousVersion, runningVersion) {
51948
+ const previous = parseSemanticVersion(previousVersion);
51949
+ const running = parseSemanticVersion(runningVersion);
51950
+ if (!previous || !running) return false;
51951
+ return compareSemanticVersions(previous, running) < 0;
51952
+ }
51953
+ function parseSemanticVersion(value) {
51954
+ const match = value.trim().match(/^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/);
51955
+ if (!match) return null;
51956
+ return {
51957
+ major: Number(match[SEMVER_MAJOR_CAPTURE_INDEX]),
51958
+ minor: Number(match[SEMVER_MINOR_CAPTURE_INDEX]),
51959
+ patch: Number(match[SEMVER_PATCH_CAPTURE_INDEX]),
51960
+ prerelease: match[SEMVER_PRERELEASE_CAPTURE_INDEX]?.split(".") ?? []
51961
+ };
51962
+ }
51963
+ function compareSemanticVersions(left, right) {
51964
+ const core = compareNumbers(left.major, right.major) || compareNumbers(left.minor, right.minor) || compareNumbers(left.patch, right.patch);
51965
+ if (core !== 0) return core;
51966
+ return comparePrerelease(left.prerelease, right.prerelease);
51967
+ }
51968
+ function comparePrerelease(left, right) {
51969
+ if (left.length === 0 && right.length === 0) return 0;
51970
+ if (left.length === 0) return 1;
51971
+ if (right.length === 0) return -1;
51972
+ for (let index = 0; index < Math.max(left.length, right.length); index += 1) {
51973
+ const leftIdentifier = left[index];
51974
+ const rightIdentifier = right[index];
51975
+ if (leftIdentifier === void 0) return -1;
51976
+ if (rightIdentifier === void 0) return 1;
51977
+ const comparison = comparePrereleaseIdentifier(leftIdentifier, rightIdentifier);
51978
+ if (comparison !== 0) return comparison;
51979
+ }
51980
+ return 0;
51981
+ }
51982
+ function comparePrereleaseIdentifier(left, right) {
51983
+ const leftNumeric = /^\d+$/.test(left);
51984
+ const rightNumeric = /^\d+$/.test(right);
51985
+ if (leftNumeric && rightNumeric) return compareNumbers(Number(left), Number(right));
51986
+ if (leftNumeric) return -1;
51987
+ if (rightNumeric) return 1;
51988
+ return left < right ? -1 : left > right ? 1 : 0;
51989
+ }
51990
+ function compareNumbers(left, right) {
51991
+ return left < right ? -1 : left > right ? 1 : 0;
51992
+ }
51993
+ function bundledTelemetryBuildMarker() {
51994
+ return true ? "production" : void 0;
51995
+ }
51996
+ function isEnabledEnvFlag(value) {
51997
+ if (value === void 0) return false;
51998
+ const normalized = value.trim().toLowerCase();
51999
+ if (normalized === "") return false;
52000
+ return normalized === "1" || normalized === "true" || normalized === "yes";
52001
+ }
52002
+ function normalizeTelemetryState(value) {
52003
+ if (!value || typeof value !== "object") throw new InvalidTelemetryStateError("Invalid telemetry state file.");
52004
+ const record2 = value;
52005
+ if (record2.schemaVersion !== TELEMETRY_STATE_SCHEMA_VERSION) throw new InvalidTelemetryStateError("Unsupported telemetry state schema version.");
52006
+ if (typeof record2.userId !== "string" || record2.userId.length === 0) throw new InvalidTelemetryStateError("Telemetry state is missing userId.");
52007
+ return {
52008
+ schemaVersion: TELEMETRY_STATE_SCHEMA_VERSION,
52009
+ userId: record2.userId,
52010
+ optedOut: record2.optedOut === true,
52011
+ lastVersion: typeof record2.lastVersion === "string" ? record2.lastVersion : ""
52012
+ };
52013
+ }
52014
+ var InvalidTelemetryStateError = class extends Error {
52015
+ };
52016
+ function isNodeError(error48) {
52017
+ return error48 instanceof Error && "code" in error48;
52018
+ }
52019
+
52020
+ // ../server/src/telemetry/capture.ts
52021
+ function capture(event, context) {
52022
+ if (!telemetryEnabled(context.env, context.state)) return;
52023
+ try {
52024
+ context.sink.enqueue(buildTelemetryEvent(event, context));
52025
+ } catch {
52026
+ }
52027
+ }
52028
+ function buildTelemetryEvent(event, context) {
52029
+ const properties = {
52030
+ distinct_id: context.state.userId,
52031
+ ...event.properties ?? {}
52032
+ };
52033
+ if (context.sessionId) properties.$session_id = context.sessionId;
52034
+ if (event.personProperties && Object.keys(event.personProperties).length > 0) properties.$set = event.personProperties;
52035
+ return {
52036
+ name: event.name,
52037
+ distinctId: context.state.userId,
52038
+ properties
52039
+ };
52040
+ }
52041
+
52042
+ // ../server/src/telemetry/posthog-config.ts
52043
+ var import_node_fs8 = require("node:fs");
52044
+ var import_node_os4 = __toESM(require("node:os"), 1);
52045
+ var import_node_path10 = __toESM(require("node:path"), 1);
52046
+ var POSTHOG_US_INGESTION_HOST = "https://us.i.posthog.com";
52047
+ var POSTHOG_US_API_HOST = "https://us.posthog.com";
52048
+ var POSTHOG_PRODUCTION_PROJECT_ID = 482022;
52049
+ var POSTHOG_TEST_PROJECT_ID = 484904;
52050
+ var POSTHOG_PRODUCTION_PROJECT_TOKEN = "phc_qASjRhbnr7AA9ak5YeQtWtHdGY5P9TM9Q2k86G34LoYP";
52051
+ var POSTHOG_TEST_PROJECT_TOKEN = "phc_roRM2of2chrstmcQAokxucoYa4KBUatW9bTjLKeBcgi4";
52052
+ var POSTHOG_PRODUCTION_PROJECT = {
52053
+ projectId: POSTHOG_PRODUCTION_PROJECT_ID,
52054
+ projectToken: POSTHOG_PRODUCTION_PROJECT_TOKEN,
52055
+ ingestionHost: POSTHOG_US_INGESTION_HOST,
52056
+ apiHost: POSTHOG_US_API_HOST
52057
+ };
52058
+ var POSTHOG_TEST_PROJECT = {
52059
+ projectId: POSTHOG_TEST_PROJECT_ID,
52060
+ projectToken: POSTHOG_TEST_PROJECT_TOKEN,
52061
+ ingestionHost: POSTHOG_US_INGESTION_HOST,
52062
+ apiHost: POSTHOG_US_API_HOST
52063
+ };
52064
+ function resolvePostHogProject(env, options = {}) {
52065
+ return isTelemetryDevMode(env) || options.developerHost === true ? POSTHOG_TEST_PROJECT : POSTHOG_PRODUCTION_PROJECT;
52066
+ }
52067
+ function resolveTelemetryDeveloperHome(env = process.env) {
52068
+ const capturedHome = env.TELEVISION_DEVELOPER_HOME;
52069
+ return capturedHome && capturedHome.length > 0 ? capturedHome : import_node_os4.default.homedir();
52070
+ }
52071
+ function detectTelemetryDeveloperHost(homeDir = import_node_os4.default.homedir()) {
52072
+ try {
52073
+ return (0, import_node_fs8.existsSync)(import_node_path10.default.join(homeDir, ".tv-developer"));
52074
+ } catch {
52075
+ return false;
52076
+ }
52077
+ }
52078
+
52079
+ // ../server/src/telemetry/sessions.ts
52080
+ var import_node_crypto6 = require("node:crypto");
52081
+ var IDLE_TIMEOUT_MINUTES = 30;
52082
+ var MAX_SESSION_HOURS = 24;
52083
+ var SECONDS_PER_MINUTE2 = 60;
52084
+ var MINUTES_PER_HOUR2 = 60;
52085
+ var MILLISECONDS_PER_SECOND = 1e3;
52086
+ var SESSION_IDLE_TIMEOUT_MS = IDLE_TIMEOUT_MINUTES * SECONDS_PER_MINUTE2 * MILLISECONDS_PER_SECOND;
52087
+ var MAX_SESSION_DURATION_MS = MAX_SESSION_HOURS * MINUTES_PER_HOUR2 * SECONDS_PER_MINUTE2 * MILLISECONDS_PER_SECOND;
52088
+ var BYTE_HEX_RADIX = 16;
52089
+ var UUID_BYTE_COUNT = 16;
52090
+ var UUID_VERSION_BYTE_INDEX = 6;
52091
+ var UUID_VARIANT_BYTE_INDEX = 8;
52092
+ var UUID_TIMESTAMP_LAST_BYTE_INDEX = 5;
52093
+ var UUID_VERSION_7_HIGH_BITS = 112;
52094
+ var UUID_VARIANT_RFC_9562_HIGH_BITS = 128;
52095
+ var UUID_VERSION_LOW_MASK = 15;
52096
+ var UUID_VARIANT_LOW_MASK = 63;
52097
+ var BYTE_MASK = 255;
52098
+ var BYTE_SHIFT = 8;
52099
+ var UUID_GROUP_ONE_END = 8;
52100
+ var UUID_GROUP_TWO_END = 12;
52101
+ var UUID_GROUP_THREE_END = 16;
52102
+ var UUID_GROUP_FOUR_END = 20;
52103
+ function createTelemetrySessionManager() {
52104
+ return new InMemoryTelemetrySessionManager();
52105
+ }
52106
+ function createUUIDv7(timestampMs) {
52107
+ const bytes = (0, import_node_crypto6.randomBytes)(UUID_BYTE_COUNT);
52108
+ writeTimestamp(bytes, timestampMs);
52109
+ bytes[UUID_VERSION_BYTE_INDEX] = UUID_VERSION_7_HIGH_BITS | bytes[UUID_VERSION_BYTE_INDEX] & UUID_VERSION_LOW_MASK;
52110
+ bytes[UUID_VARIANT_BYTE_INDEX] = UUID_VARIANT_RFC_9562_HIGH_BITS | bytes[UUID_VARIANT_BYTE_INDEX] & UUID_VARIANT_LOW_MASK;
52111
+ return formatUUID(bytes);
52112
+ }
52113
+ var InMemoryTelemetrySessionManager = class {
52114
+ #sessions = /* @__PURE__ */ new Map();
52115
+ sessionIdFor(clientId, nowMs) {
52116
+ if (!clientId) return null;
52117
+ const existing = this.#sessions.get(clientId);
52118
+ if (!existing || shouldRotate(existing, nowMs)) {
52119
+ const next = mintSession(clientId, nowMs);
52120
+ this.#sessions.set(clientId, next);
52121
+ return next.sessionId;
52122
+ }
52123
+ const updated = { ...existing, lastActivityMs: nowMs };
52124
+ this.#sessions.set(clientId, updated);
52125
+ return existing.sessionId;
52126
+ }
52127
+ get(clientId) {
52128
+ return this.#sessions.get(clientId) ?? null;
52129
+ }
52130
+ };
52131
+ function mintSession(clientId, nowMs) {
52132
+ return {
52133
+ clientId,
52134
+ sessionId: createUUIDv7(nowMs),
52135
+ sessionStartMs: nowMs,
52136
+ lastActivityMs: nowMs
52137
+ };
52138
+ }
52139
+ function shouldRotate(session, nowMs) {
52140
+ return nowMs - session.lastActivityMs > SESSION_IDLE_TIMEOUT_MS || nowMs - session.sessionStartMs >= MAX_SESSION_DURATION_MS;
52141
+ }
52142
+ function writeTimestamp(bytes, timestampMs) {
52143
+ if (!Number.isSafeInteger(timestampMs) || timestampMs < 0) throw new Error(`Invalid UUIDv7 timestamp: ${timestampMs}`);
52144
+ let remaining = timestampMs;
52145
+ for (let index = UUID_TIMESTAMP_LAST_BYTE_INDEX; index >= 0; index -= 1) {
52146
+ bytes[index] = remaining & BYTE_MASK;
52147
+ remaining = Math.floor(remaining / 2 ** BYTE_SHIFT);
52148
+ }
52149
+ }
52150
+ function formatUUID(bytes) {
52151
+ const hex3 = [...bytes].map((byte) => byte.toString(BYTE_HEX_RADIX).padStart(2, "0")).join("");
52152
+ const first = hex3.slice(0, UUID_GROUP_ONE_END);
52153
+ const second = hex3.slice(UUID_GROUP_ONE_END, UUID_GROUP_TWO_END);
52154
+ const third = hex3.slice(UUID_GROUP_TWO_END, UUID_GROUP_THREE_END);
52155
+ const fourth = hex3.slice(UUID_GROUP_THREE_END, UUID_GROUP_FOUR_END);
52156
+ const fifth = hex3.slice(UUID_GROUP_FOUR_END);
52157
+ return `${first}-${second}-${third}-${fourth}-${fifth}`;
52158
+ }
52159
+
52160
+ // ../server/src/telemetry/sink.ts
52161
+ var DEFAULT_MAX_BUFFER_SIZE = 1e3;
52162
+ var DEFAULT_POSTHOG_TIMEOUT_MS = 1e4;
52163
+ function createTelemetrySink(options = {}) {
52164
+ return new BufferedTelemetrySink(
52165
+ options.transport ?? createPostHogTransport({ project: options.project }),
52166
+ options.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE,
52167
+ options.autoFlush ?? true
52168
+ );
52169
+ }
52170
+ function createPostHogTransport(options = {}) {
52171
+ const project = options.project ?? POSTHOG_PRODUCTION_PROJECT;
52172
+ const fetchImpl = options.fetchImpl ?? fetch;
52173
+ const timeoutMs = options.timeoutMs ?? DEFAULT_POSTHOG_TIMEOUT_MS;
52174
+ const captureUrl = new URL("/capture/", project.ingestionHost).toString();
52175
+ return {
52176
+ async send(event) {
52177
+ const controller = new AbortController();
52178
+ const timeout = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : null;
52179
+ try {
52180
+ const response = await fetchImpl(captureUrl, {
52181
+ method: "POST",
52182
+ headers: { "content-type": "application/json" },
52183
+ body: JSON.stringify({
52184
+ api_key: project.projectToken,
52185
+ event: event.name,
52186
+ distinct_id: event.distinctId,
52187
+ properties: event.properties
52188
+ }),
52189
+ signal: controller.signal
52190
+ });
52191
+ if (!response.ok) throw new Error(`PostHog capture failed with HTTP ${response.status}`);
52192
+ } catch (error48) {
52193
+ if (controller.signal.aborted) throw new Error(`PostHog capture timed out after ${timeoutMs}ms`);
52194
+ throw error48;
52195
+ } finally {
52196
+ if (timeout) clearTimeout(timeout);
52197
+ }
52198
+ }
52199
+ };
52200
+ }
52201
+ var BufferedTelemetrySink = class {
52202
+ transport;
52203
+ maxBufferSize;
52204
+ autoFlush;
52205
+ buffer = [];
52206
+ flushing = false;
52207
+ flushScheduled = false;
52208
+ constructor(transport, maxBufferSize, autoFlush) {
52209
+ this.transport = transport;
52210
+ this.maxBufferSize = Math.max(1, maxBufferSize);
52211
+ this.autoFlush = autoFlush;
52212
+ }
52213
+ enqueue(event) {
52214
+ try {
52215
+ if (this.buffer.length >= this.maxBufferSize) this.buffer.shift();
52216
+ this.buffer.push(event);
52217
+ if (this.autoFlush) this.scheduleFlush();
52218
+ } catch {
52219
+ }
52220
+ }
52221
+ async flush() {
52222
+ if (this.flushing) return;
52223
+ this.flushing = true;
52224
+ try {
52225
+ while (this.buffer.length > 0) {
52226
+ const next = this.buffer[0];
52227
+ try {
52228
+ await this.transport.send(next);
52229
+ this.buffer.shift();
52230
+ } catch {
52231
+ break;
52232
+ }
52233
+ }
52234
+ } finally {
52235
+ this.flushing = false;
52236
+ }
52237
+ }
52238
+ async shutdown() {
52239
+ await this.flush();
52240
+ try {
52241
+ await this.transport.shutdown?.();
52242
+ } catch {
52243
+ }
52244
+ }
52245
+ pendingCount() {
52246
+ return this.buffer.length;
52247
+ }
52248
+ scheduleFlush() {
52249
+ if (this.flushScheduled) return;
52250
+ this.flushScheduled = true;
52251
+ queueMicrotask(() => {
52252
+ this.flushScheduled = false;
52253
+ void this.flush();
52254
+ });
52255
+ }
52256
+ };
52257
+
52258
+ // ../server/src/telemetry/runtime.ts
52259
+ var SKILL_INSTALL_TELEMETRY_TIMEOUT_MS = 500;
52260
+ async function emitSkillInstalledTelemetry(options) {
52261
+ const env = options.env ?? process.env;
52262
+ const developerHost = options.developerHost ?? detectTelemetryDeveloperHost(resolveTelemetryDeveloperHome(env));
52263
+ const sink = options.sink ?? createTelemetrySink({
52264
+ transport: createPostHogTransport({ project: resolvePostHogProject(env, { developerHost }), timeoutMs: SKILL_INSTALL_TELEMETRY_TIMEOUT_MS })
52265
+ });
52266
+ try {
52267
+ const loaded = await loadOrMintTelemetryState(options.storagePath, { lastVersion: "" });
52268
+ capture({
52269
+ name: "skill_installed",
52270
+ properties: {
52271
+ server_version: options.version,
52272
+ agent_type: options.agentType,
52273
+ ...normalizeInstalledByAgent(options.installedByAgent)
52274
+ }
52275
+ }, { state: loaded.state, env, sink });
52276
+ } catch {
52277
+ } finally {
52278
+ await bestEffortWithinTimeout(sink.shutdown?.(), SKILL_INSTALL_TELEMETRY_TIMEOUT_MS);
52279
+ }
52280
+ }
52281
+ async function bestEffortWithinTimeout(promise2, timeoutMs) {
52282
+ if (!promise2) return;
52283
+ void promise2.catch(() => {
52284
+ });
52285
+ await new Promise((resolve) => {
52286
+ const timeout = setTimeout(resolve, timeoutMs);
52287
+ promise2.then(
52288
+ () => {
52289
+ clearTimeout(timeout);
52290
+ resolve();
52291
+ },
52292
+ () => {
52293
+ clearTimeout(timeout);
52294
+ resolve();
52295
+ }
52296
+ );
52297
+ });
52298
+ }
52299
+ async function createTelemetryRuntime(options) {
52300
+ try {
52301
+ const boot = await deriveBootTelemetry(options.storagePath, options.version, { dataDirCreated: options.dataDirCreated });
52302
+ const env = options.env ?? process.env;
52303
+ const developerHost = options.developerHost ?? detectTelemetryDeveloperHost(resolveTelemetryDeveloperHome(env));
52304
+ const sink = options.sink ?? createTelemetrySink({ project: resolvePostHogProject(env, { developerHost }) });
52305
+ const sessions = options.sessions ?? createTelemetrySessionManager();
52306
+ const nowMs = options.nowMs ?? Date.now;
52307
+ let currentState = boot.state;
52308
+ let pendingPersonProperties = null;
52309
+ const sessionIdFor = (clientContext) => {
52310
+ return sessions.sessionIdFor(clientContext?.clientId ?? null, nowMs());
52311
+ };
52312
+ const captureWithPendingPersonProperties = (event, sessionId) => {
52313
+ const shouldAttachPendingProperties = pendingPersonProperties !== null && telemetryEnabled(env, currentState);
52314
+ capture(shouldAttachPendingProperties ? { ...event, personProperties: { ...event.personProperties ?? {}, ...pendingPersonProperties } } : event, { state: currentState, env, sink, sessionId });
52315
+ if (shouldAttachPendingProperties) pendingPersonProperties = null;
52316
+ };
52317
+ return {
52318
+ boot,
52319
+ get state() {
52320
+ return currentState;
52321
+ },
52322
+ enabled: true,
52323
+ status() {
52324
+ return telemetryStatus(env, currentState);
52325
+ },
52326
+ async disable() {
52327
+ if (!currentState.optedOut) {
52328
+ capture({
52329
+ name: "telemetry_opted_out",
52330
+ personProperties: { telemetry_opted_out: true }
52331
+ }, { state: currentState, env, sink });
52332
+ currentState = await setTelemetryOptedOut(options.storagePath, currentState, true);
52333
+ }
52334
+ return telemetryStatus(env, currentState);
52335
+ },
52336
+ async enable() {
52337
+ if (currentState.optedOut) {
52338
+ currentState = await setTelemetryOptedOut(options.storagePath, currentState, false);
52339
+ pendingPersonProperties = { telemetry_opted_out: false };
52340
+ }
52341
+ return telemetryStatus(env, currentState);
52342
+ },
52343
+ capture(event, clientContext) {
52344
+ captureWithPendingPersonProperties(event, sessionIdFor(clientContext));
52345
+ },
52346
+ observeClientRequest(clientContext) {
52347
+ return sessionIdFor(clientContext);
52348
+ },
52349
+ recordClientActivity(clientContext) {
52350
+ if (!clientContext) return;
52351
+ const sessionId = sessionIdFor(clientContext);
52352
+ if (!sessionId) return;
52353
+ captureWithPendingPersonProperties({
52354
+ name: "session_activity",
52355
+ properties: {
52356
+ server_version: options.version,
52357
+ ...deriveSessionActivityClientProperties(clientContext)
52358
+ }
52359
+ }, sessionId);
52360
+ },
52361
+ async shutdown() {
52362
+ try {
52363
+ await sink.shutdown?.();
52364
+ } catch {
52365
+ }
52366
+ }
52367
+ };
52368
+ } catch {
52369
+ return disabledTelemetryRuntime();
52370
+ }
52371
+ }
52372
+ function disabledTelemetryRuntime() {
52373
+ return {
52374
+ boot: null,
52375
+ state: null,
52376
+ enabled: false,
52377
+ status() {
52378
+ return telemetryStatus(process.env, null);
52379
+ },
52380
+ async disable() {
52381
+ return telemetryStatus(process.env, null);
52382
+ },
52383
+ async enable() {
52384
+ return telemetryStatus(process.env, null);
52385
+ },
52386
+ capture() {
52387
+ },
52388
+ observeClientRequest() {
52389
+ return null;
52390
+ },
52391
+ recordClientActivity() {
52392
+ },
52393
+ async shutdown() {
52394
+ }
52395
+ };
52396
+ }
52397
+
51316
52398
  // ../server/src/server.ts
52399
+ var import_meta = {};
51317
52400
  var HTTP_UNAUTHORIZED_STATUS = 401;
51318
52401
  var LOOPBACK_IPV4 = "127.0.0.1";
51319
52402
  var Server = class {
@@ -51327,7 +52410,9 @@ var Server = class {
51327
52410
  authRequired;
51328
52411
  authMode;
51329
52412
  bindAddresses;
52413
+ telemetryOptions;
51330
52414
  bindFailures = [];
52415
+ telemetryRuntime = null;
51331
52416
  listeningPort;
51332
52417
  baseURLs;
51333
52418
  disposed = false;
@@ -51337,6 +52422,7 @@ var Server = class {
51337
52422
  this.authRequired = options.auth ?? false;
51338
52423
  this.authMode = options.auth === true ? "auth" : options.auth === false ? "no-auth" : "none";
51339
52424
  this.bindAddresses = resolveBindAddresses(options.host ? [options.host] : options.listen);
52425
+ this.telemetryOptions = options.telemetry ?? {};
51340
52426
  this.listeningPort = this.port;
51341
52427
  this.baseURLs = [];
51342
52428
  this.app = (0, import_express2.default)();
@@ -51352,7 +52438,8 @@ var Server = class {
51352
52438
  this.app.use(import_express2.default.json());
51353
52439
  this.events = new EventStreamServer({
51354
52440
  store: this.store,
51355
- authRequired: this.authRequired
52441
+ authRequired: this.authRequired,
52442
+ recordTelemetryActivity: (clientContext) => this.telemetryRuntime?.recordClientActivity(clientContext)
51356
52443
  });
51357
52444
  this.acp = options.acpProfile ? new ACPServer({
51358
52445
  authToken: this.store.authToken,
@@ -51362,7 +52449,13 @@ var Server = class {
51362
52449
  registerRoutes(this.app, this.store, {
51363
52450
  requireAuth: this.requireAuthorization,
51364
52451
  requireBearerAuth: this.requireBearerAuthorization,
51365
- acpEnabled: this.acp !== null
52452
+ acpEnabled: this.acp !== null,
52453
+ observeTelemetryClientRequest: (clientContext) => {
52454
+ this.telemetryRuntime?.observeClientRequest(clientContext);
52455
+ },
52456
+ getTelemetryStatus: () => this.telemetryRuntime?.status() ?? { state: "unavailable", reason: null, guidPresent: false, region: "us" },
52457
+ enableTelemetry: async () => this.telemetryRuntime?.enable() ?? { state: "unavailable", reason: null, guidPresent: false, region: "us" },
52458
+ disableTelemetry: async () => this.telemetryRuntime?.disable() ?? { state: "unavailable", reason: null, guidPresent: false, region: "us" }
51366
52459
  });
51367
52460
  if (options.canonicalDir) {
51368
52461
  this.app.use("/canonical/v1", (_req, res, next) => {
@@ -51428,6 +52521,7 @@ var Server = class {
51428
52521
  log(this.store.storagePath, message, { reason: "all bind addresses failed", snapshot: this.configurationSnapshot() });
51429
52522
  throw new Error(message);
51430
52523
  }
52524
+ await this.startTelemetry();
51431
52525
  log(this.store.storagePath, "server started", { snapshot: this.configurationSnapshot() });
51432
52526
  if (!this.authRequired) {
51433
52527
  log(this.store.storagePath, "server running without bearer-token enforcement", { authMode: this.authMode });
@@ -51473,7 +52567,8 @@ var Server = class {
51473
52567
  await Promise.all([
51474
52568
  this.events.dispose(),
51475
52569
  this.acp?.dispose() ?? Promise.resolve(),
51476
- Promise.resolve(this.store.dispose())
52570
+ Promise.resolve(this.store.dispose()),
52571
+ this.telemetryRuntime?.shutdown() ?? Promise.resolve()
51477
52572
  ]);
51478
52573
  await Promise.all(this.httpServers.map((server) => this.closeServer(server)));
51479
52574
  } catch (error48) {
@@ -51523,6 +52618,35 @@ var Server = class {
51523
52618
  getNonLoopbackBoundAddresses() {
51524
52619
  return this.baseURLs.map((url2) => new URL(url2).hostname).filter((address) => address !== LOOPBACK_IPV4);
51525
52620
  }
52621
+ async startTelemetry() {
52622
+ const version2 = this.telemetryOptions.version ?? readServerPackageVersion();
52623
+ const launchMode = this.telemetryOptions.launchMode ?? "cli";
52624
+ const runtime = await createTelemetryRuntime({
52625
+ storagePath: this.store.storagePath,
52626
+ version: version2,
52627
+ dataDirCreated: this.store.dataDirCreated,
52628
+ ...this.telemetryOptions.env === void 0 ? {} : { env: this.telemetryOptions.env },
52629
+ ...this.telemetryOptions.sink === void 0 ? {} : { sink: this.telemetryOptions.sink },
52630
+ ...this.telemetryOptions.developerHost === void 0 ? {} : { developerHost: this.telemetryOptions.developerHost }
52631
+ });
52632
+ this.telemetryRuntime = runtime;
52633
+ this.store.setTelemetryHooks(createServerStoreTelemetryHooks(this.store, runtime.capture));
52634
+ if (!runtime.boot) return;
52635
+ emitServerBootTelemetry(
52636
+ runtime.capture,
52637
+ runtime.boot.events,
52638
+ deriveServerConfigSnapshotProperties({
52639
+ version: version2,
52640
+ storagePath: this.store.storagePath,
52641
+ port: this.port,
52642
+ bindAddresses: this.bindAddresses,
52643
+ authMode: this.authMode,
52644
+ launchMode,
52645
+ installedByAgent: this.telemetryOptions.installedByAgent ?? null
52646
+ }),
52647
+ { telemetry_opted_out: runtime.boot.state.optedOut }
52648
+ );
52649
+ }
51526
52650
  configurationSnapshot() {
51527
52651
  return {
51528
52652
  storagePath: this.store.storagePath,
@@ -51570,15 +52694,23 @@ var Server = class {
51570
52694
  res.status(HTTP_UNAUTHORIZED_STATUS).json({ error: "Unauthorized" });
51571
52695
  };
51572
52696
  };
52697
+ function readServerPackageVersion() {
52698
+ if ("0.1.171".length > 0) {
52699
+ return telemetryVersion("0.1.171");
52700
+ }
52701
+ const packageJsonPath = import_node_path11.default.resolve(import_node_path11.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url)), "..", "package.json");
52702
+ if (!(0, import_node_fs9.existsSync)(packageJsonPath)) return telemetryVersion("0.0.0");
52703
+ return telemetryVersion(JSON.parse((0, import_node_fs9.readFileSync)(packageJsonPath, "utf8")).version);
52704
+ }
51573
52705
 
51574
52706
  // ../server/src/server-store.ts
51575
- var import_node_fs9 = require("node:fs");
51576
- var import_node_path11 = __toESM(require("node:path"), 1);
52707
+ var import_node_fs11 = require("node:fs");
52708
+ var import_node_path14 = __toESM(require("node:path"), 1);
51577
52709
 
51578
52710
  // ../server/src/file-watcher.ts
51579
52711
  var import_node_events = require("node:events");
51580
52712
  var fs3 = __toESM(require("node:fs"), 1);
51581
- var import_node_path8 = __toESM(require("node:path"), 1);
52713
+ var import_node_path12 = __toESM(require("node:path"), 1);
51582
52714
  var DEFAULT_REARM_INTERVAL_MS = 250;
51583
52715
  function isMissingWatchRootError(error48) {
51584
52716
  return typeof error48 === "object" && error48 !== null && "code" in error48 && error48.code === "ENOENT";
@@ -51597,9 +52729,9 @@ var ReArmingContentWatcher = class extends import_node_events.EventEmitter {
51597
52729
  #rootEventImmediate = null;
51598
52730
  constructor(filePath, onChange, basenames, options = {}) {
51599
52731
  super();
51600
- this.#dir = basenames === void 0 ? import_node_path8.default.dirname(filePath) : filePath;
51601
- this.#watchedBasenames = new Set(basenames ?? [import_node_path8.default.basename(filePath)]);
51602
- this.#watchRootBasename = import_node_path8.default.basename(import_node_path8.default.normalize(this.#dir));
52732
+ this.#dir = basenames === void 0 ? import_node_path12.default.dirname(filePath) : filePath;
52733
+ this.#watchedBasenames = new Set(basenames ?? [import_node_path12.default.basename(filePath)]);
52734
+ this.#watchRootBasename = import_node_path12.default.basename(import_node_path12.default.normalize(this.#dir));
51603
52735
  this.#onChange = onChange;
51604
52736
  this.#options = options;
51605
52737
  try {
@@ -51643,7 +52775,7 @@ var ReArmingContentWatcher = class extends import_node_events.EventEmitter {
51643
52775
  });
51644
52776
  const ancestorWatchers = [];
51645
52777
  for (const ancestorDir of this.#ancestorDirs()) {
51646
- const ancestorBasename = import_node_path8.default.basename(import_node_path8.default.normalize(ancestorDir));
52778
+ const ancestorBasename = import_node_path12.default.basename(import_node_path12.default.normalize(ancestorDir));
51647
52779
  try {
51648
52780
  const ancestorWatcher = fs3.watch(ancestorDir, (_event, filename) => {
51649
52781
  const basename = filename?.toString();
@@ -51689,10 +52821,10 @@ var ReArmingContentWatcher = class extends import_node_events.EventEmitter {
51689
52821
  }
51690
52822
  #ancestorDirs() {
51691
52823
  const ancestors = [];
51692
- let current = import_node_path8.default.dirname(this.#dir);
51693
- while (current !== import_node_path8.default.dirname(current)) {
52824
+ let current = import_node_path12.default.dirname(this.#dir);
52825
+ while (current !== import_node_path12.default.dirname(current)) {
51694
52826
  ancestors.push(current);
51695
- current = import_node_path8.default.dirname(current);
52827
+ current = import_node_path12.default.dirname(current);
51696
52828
  }
51697
52829
  return ancestors;
51698
52830
  }
@@ -51748,54 +52880,27 @@ var defaultWatchContentFile = (filePath, onChange, basenames, options) => {
51748
52880
  return new ReArmingContentWatcher(filePath, onChange, basenames, options);
51749
52881
  };
51750
52882
 
51751
- // ../server/src/artifact-paths.ts
51752
- var import_node_path9 = __toESM(require("node:path"), 1);
51753
- function getStateDir(storagePath) {
51754
- return import_node_path9.default.join(storagePath, "state");
51755
- }
51756
- function getScreensDir(storagePath) {
51757
- return import_node_path9.default.join(getStateDir(storagePath), "screens");
51758
- }
51759
- function getArtifactsMetadataDir(storagePath) {
51760
- return import_node_path9.default.join(getStateDir(storagePath), "artifacts");
51761
- }
51762
- function getDisplayStatePath(storagePath) {
51763
- return import_node_path9.default.join(getStateDir(storagePath), "display.json");
51764
- }
51765
- function getTokenPath(storagePath) {
51766
- return import_node_path9.default.join(getStateDir(storagePath), "token");
51767
- }
51768
- function getOnboardingArtifactSentinelPath(storagePath) {
51769
- return import_node_path9.default.join(getStateDir(storagePath), "onboarding-artifact.json");
51770
- }
51771
- function getAgentArtifactsDir(storagePath) {
51772
- return import_node_path9.default.join(...[storagePath, "artifacts"]);
51773
- }
51774
- function getArtifactLiveMetadataPath(storagePath, artifactID) {
51775
- return import_node_path9.default.join(getArtifactsMetadataDir(storagePath), `${artifactID}.json`);
51776
- }
51777
-
51778
52883
  // ../server/src/onboarding.ts
51779
- var import_node_fs8 = require("node:fs");
51780
- var import_node_path10 = __toESM(require("node:path"), 1);
51781
- var import_node_url = require("node:url");
51782
- var import_meta = {};
52884
+ var import_node_fs10 = require("node:fs");
52885
+ var import_node_path13 = __toESM(require("node:path"), 1);
52886
+ var import_node_url2 = require("node:url");
52887
+ var import_meta2 = {};
51783
52888
  var ONBOARDING_ARTIFACT_ID = "television-onboarding";
51784
52889
  var ONBOARDING_SCREEN_NAME = "TV Guide";
51785
52890
  var ONBOARDING_ARTIFACT_TITLE = "Welcome to Television";
51786
52891
  var ONBOARDING_ARTIFACT_DIRNAME = "television-onboarding";
51787
52892
  var ONBOARDING_ARTIFACT_SENTINEL_VERSION = 1;
51788
52893
  function getDefaultOnboardingArtifactSourcePath() {
51789
- const moduleURL = import_meta.url;
52894
+ const moduleURL = import_meta2.url;
51790
52895
  if (typeof moduleURL !== "string") {
51791
52896
  return void 0;
51792
52897
  }
51793
- const sourcePath = import_node_path10.default.resolve(
51794
- import_node_path10.default.dirname((0, import_node_url.fileURLToPath)(moduleURL)),
52898
+ const sourcePath = import_node_path13.default.resolve(
52899
+ import_node_path13.default.dirname((0, import_node_url2.fileURLToPath)(moduleURL)),
51795
52900
  "../assets",
51796
52901
  ONBOARDING_ARTIFACT_DIRNAME
51797
52902
  );
51798
- return (0, import_node_fs8.existsSync)(sourcePath) ? sourcePath : void 0;
52903
+ return (0, import_node_fs10.existsSync)(sourcePath) ? sourcePath : void 0;
51799
52904
  }
51800
52905
 
51801
52906
  // ../server/src/server-store.ts
@@ -51807,6 +52912,17 @@ var BUNDLED_VIEW_IDS = /* @__PURE__ */ new Set(["artifact-missing", "markdown"])
51807
52912
  function isBundledViewID(id) {
51808
52913
  return BUNDLED_VIEW_IDS.has(id);
51809
52914
  }
52915
+ function hasExistingTelevisionDataStructure(storagePath) {
52916
+ return [
52917
+ getDisplayStatePath(storagePath),
52918
+ getTokenPath(storagePath),
52919
+ getOnboardingArtifactSentinelPath(storagePath),
52920
+ getScreensDir(storagePath),
52921
+ getArtifactsMetadataDir(storagePath),
52922
+ getThemesDir(storagePath),
52923
+ getAgentArtifactsDir(storagePath)
52924
+ ].some((markerPath) => (0, import_node_fs11.existsSync)(markerPath));
52925
+ }
51810
52926
  function artifactWatchTarget(artifact) {
51811
52927
  if (artifact.kind === "url") {
51812
52928
  return null;
@@ -51822,6 +52938,7 @@ function artifactWatchTarget(artifact) {
51822
52938
  var ServerStore = class extends EventTarget {
51823
52939
  storagePath;
51824
52940
  authToken;
52941
+ dataDirCreated;
51825
52942
  screens = /* @__PURE__ */ new Map();
51826
52943
  activeScreenID = null;
51827
52944
  activeThemeName = null;
@@ -51835,9 +52952,11 @@ var ServerStore = class extends EventTarget {
51835
52952
  watchContentFile;
51836
52953
  bundledViewsPath;
51837
52954
  onboardingArtifactSourcePath;
52955
+ telemetryHooks = null;
51838
52956
  constructor(options) {
51839
52957
  super();
51840
52958
  this.storagePath = options.storagePath;
52959
+ this.dataDirCreated = !hasExistingTelevisionDataStructure(options.storagePath);
51841
52960
  this.watchContentFile = options.watchContentFile ?? defaultWatchContentFile;
51842
52961
  this.bundledViewsPath = options.bundledViewsPath;
51843
52962
  this.onboardingArtifactSourcePath = options.onboardingArtifactSourcePath ?? getDefaultOnboardingArtifactSourcePath();
@@ -51859,6 +52978,9 @@ var ServerStore = class extends EventTarget {
51859
52978
  }
51860
52979
  this.startWatchingActiveTheme();
51861
52980
  }
52981
+ setTelemetryHooks(hooks) {
52982
+ this.telemetryHooks = hooks;
52983
+ }
51862
52984
  getViews() {
51863
52985
  return [];
51864
52986
  }
@@ -51866,8 +52988,8 @@ var ServerStore = class extends EventTarget {
51866
52988
  if (!isBundledViewID(id) || this.bundledViewsPath === void 0) {
51867
52989
  return null;
51868
52990
  }
51869
- const viewPath = import_node_path11.default.join(this.bundledViewsPath, id);
51870
- return (0, import_node_fs9.existsSync)(import_node_path11.default.join(viewPath, "index.html")) ? viewPath : null;
52991
+ const viewPath = import_node_path14.default.join(this.bundledViewsPath, id);
52992
+ return (0, import_node_fs11.existsSync)(import_node_path14.default.join(viewPath, "index.html")) ? viewPath : null;
51871
52993
  }
51872
52994
  getScreen(id) {
51873
52995
  const screen = this.screens.get(id);
@@ -51889,7 +53011,7 @@ var ServerStore = class extends EventTarget {
51889
53011
  return [...this._artifacts.values()];
51890
53012
  }
51891
53013
  /** Create a new artifact and append its card to the owning screen. */
51892
- createArtifact(input) {
53014
+ createArtifact(input, telemetryContext) {
51893
53015
  const screen = this.requireScreen(input.screenID);
51894
53016
  const artifact = this.createKindArtifact(input);
51895
53017
  const previousLayout = screen.layout;
@@ -51899,16 +53021,17 @@ var ServerStore = class extends EventTarget {
51899
53021
  this.persistScreen(screen);
51900
53022
  } catch (error48) {
51901
53023
  screen.layout = previousLayout;
51902
- (0, import_node_fs9.rmSync)(getArtifactLiveMetadataPath(this.storagePath, artifact.id), { force: true });
53024
+ (0, import_node_fs11.rmSync)(getArtifactLiveMetadataPath(this.storagePath, artifact.id), { force: true });
51903
53025
  throw error48;
51904
53026
  }
51905
53027
  this._artifacts.set(artifact.id, artifact);
51906
53028
  this.artifactScreens.set(artifact.id, screen.id);
51907
53029
  this.startWatchingArtifactContent(artifact);
51908
53030
  this.dispatchEvent(new ArtifactCreatedEvent("artifact-created", { screenID: screen.id, artifact }));
53031
+ this.emitTelemetry((hooks) => hooks.artifactCreated(artifact, telemetryContext));
51909
53032
  return artifact;
51910
53033
  }
51911
- updateArtifact(input) {
53034
+ updateArtifact(input, telemetryContext) {
51912
53035
  const artifact = this._artifacts.get(input.artifactID);
51913
53036
  if (!artifact) {
51914
53037
  throw new NotFoundError(`Artifact not found: ${input.artifactID}`, { entityType: "artifact", entityID: input.artifactID });
@@ -51950,6 +53073,7 @@ var ServerStore = class extends EventTarget {
51950
53073
  this.scheduleArtifactContentChangedEvent(updated.id);
51951
53074
  }
51952
53075
  this.dispatchEvent(new ArtifactUpdatedEvent("artifact-updated", { artifact: updated }));
53076
+ this.emitTelemetry((hooks) => hooks.artifactUpdated(updated, telemetryContext));
51953
53077
  return updated;
51954
53078
  }
51955
53079
  /**
@@ -51958,7 +53082,7 @@ var ServerStore = class extends EventTarget {
51958
53082
  *
51959
53083
  * Throws `NotFoundError` when the artifact does not exist.
51960
53084
  */
51961
- deleteArtifact(artifactID) {
53085
+ deleteArtifact(artifactID, telemetryContext) {
51962
53086
  const artifact = this._artifacts.get(artifactID);
51963
53087
  if (!artifact) {
51964
53088
  throw new NotFoundError(`Artifact not found: ${artifactID}`, { entityType: "artifact", entityID: artifactID });
@@ -51978,13 +53102,14 @@ var ServerStore = class extends EventTarget {
51978
53102
  }
51979
53103
  this.stopWatchingArtifactContent(artifactID);
51980
53104
  this._artifacts.delete(artifactID);
51981
- (0, import_node_fs9.rmSync)(getArtifactLiveMetadataPath(this.storagePath, artifactID), { force: true });
53105
+ (0, import_node_fs11.rmSync)(getArtifactLiveMetadataPath(this.storagePath, artifactID), { force: true });
51982
53106
  if (screenID !== void 0) {
51983
53107
  this.dispatchEvent(new ArtifactRemovedEvent("artifact-removed", { artifactID, screenID }));
51984
53108
  }
53109
+ this.emitTelemetry((hooks) => hooks.artifactDeleted(artifact, telemetryContext));
51985
53110
  return artifact.kind === "path" ? { outcome: "deleted", kind: "path", artifactID, path: artifact.path } : { outcome: "deleted", kind: "url", artifactID, url: artifact.url };
51986
53111
  }
51987
- createScreen(input) {
53112
+ createScreen(input, telemetryContext) {
51988
53113
  const screen = {
51989
53114
  id: input.id ?? ulid3(),
51990
53115
  name: input.name,
@@ -51993,9 +53118,10 @@ var ServerStore = class extends EventTarget {
51993
53118
  this.screens.set(screen.id, screen);
51994
53119
  this.persistScreen(screen);
51995
53120
  this.dispatchEvent(new ScreenCreatedEvent("screen-created", { screen }));
53121
+ this.emitTelemetry((hooks) => hooks.screenCreated(screen, telemetryContext));
51996
53122
  return screen;
51997
53123
  }
51998
- updateScreen(input) {
53124
+ updateScreen(input, telemetryContext) {
51999
53125
  const screen = this.requireScreen(input.screenID);
52000
53126
  if (typeof input.fields.name === "string") {
52001
53127
  screen.name = input.fields.name;
@@ -52013,10 +53139,12 @@ var ServerStore = class extends EventTarget {
52013
53139
  }
52014
53140
  this.rebuildArtifactScreensForScreen(screen);
52015
53141
  this.dispatchEvent(new ScreenUpdatedEvent("screen-updated", { screen }));
53142
+ this.emitTelemetry((hooks) => hooks.screenLayoutChanged(previousLayout, screen.layout, telemetryContext));
52016
53143
  return screen;
52017
53144
  }
52018
53145
  this.persistScreen(screen);
52019
53146
  this.dispatchEvent(new ScreenUpdatedEvent("screen-updated", { screen }));
53147
+ this.emitTelemetry((hooks) => hooks.screenUpdated(screen, telemetryContext));
52020
53148
  return screen;
52021
53149
  }
52022
53150
  /** The screen that Television's GUI is currently focused on. */
@@ -52032,7 +53160,7 @@ var ServerStore = class extends EventTarget {
52032
53160
  activeThemeName: this.activeThemeName
52033
53161
  };
52034
53162
  }
52035
- patchDisplay(input) {
53163
+ patchDisplay(input, telemetryContext) {
52036
53164
  const currentActiveScreenID = this.getActiveScreenID();
52037
53165
  let nextActiveScreenID = this.activeScreenID;
52038
53166
  let nextActiveThemeName = this.activeThemeName;
@@ -52076,6 +53204,7 @@ var ServerStore = class extends EventTarget {
52076
53204
  this.dispatchEvent(
52077
53205
  new ThemeChangedEvent("theme-changed", { themeName: this.activeThemeName })
52078
53206
  );
53207
+ this.emitTelemetry((hooks) => hooks.themeChanged(telemetryContext));
52079
53208
  }
52080
53209
  }
52081
53210
  /**
@@ -52105,15 +53234,16 @@ var ServerStore = class extends EventTarget {
52105
53234
  );
52106
53235
  return { screenID: target, artifactID: input.artifactID };
52107
53236
  }
52108
- removeScreen(screenID) {
53237
+ removeScreen(screenID, telemetryContext) {
52109
53238
  const screen = this.requireScreen(screenID);
52110
53239
  const previousActiveScreenID = this.getActiveScreenID();
52111
53240
  const artifactIDs = [...new Set(getScreenArtifactIDs(screen))];
52112
- const artifactResults = artifactIDs.map((artifactID) => this.deleteArtifact(artifactID));
52113
- const metadataPath = import_node_path11.default.join(this.screensDir, `${screen.id}.json`);
52114
- (0, import_node_fs9.rmSync)(metadataPath, { force: true });
53241
+ const artifactResults = artifactIDs.map((artifactID) => this.deleteArtifact(artifactID, telemetryContext));
53242
+ const metadataPath = import_node_path14.default.join(this.screensDir, `${screen.id}.json`);
53243
+ (0, import_node_fs11.rmSync)(metadataPath, { force: true });
52115
53244
  this.screens.delete(screen.id);
52116
53245
  this.dispatchEvent(new ScreenRemovedEvent("screen-removed", { screenID }));
53246
+ this.emitTelemetry((hooks) => hooks.screenDeleted(screen, telemetryContext));
52117
53247
  const nextActiveScreenID = this.getActiveScreenID();
52118
53248
  if (previousActiveScreenID !== nextActiveScreenID) {
52119
53249
  this.dispatchEvent(
@@ -52129,14 +53259,21 @@ var ServerStore = class extends EventTarget {
52129
53259
  [Symbol.dispose]() {
52130
53260
  this.dispose();
52131
53261
  }
53262
+ emitTelemetry(callback) {
53263
+ if (!this.telemetryHooks) return;
53264
+ try {
53265
+ callback(this.telemetryHooks);
53266
+ } catch {
53267
+ }
53268
+ }
52132
53269
  load() {
52133
- if ((0, import_node_fs9.existsSync)(this.screensDir)) {
52134
- for (const file2 of (0, import_node_fs9.readdirSync)(this.screensDir)) {
53270
+ if ((0, import_node_fs11.existsSync)(this.screensDir)) {
53271
+ for (const file2 of (0, import_node_fs11.readdirSync)(this.screensDir)) {
52135
53272
  if (!file2.endsWith(JSON_FILE_SUFFIX)) continue;
52136
- const filePath = import_node_path11.default.join(this.screensDir, file2);
53273
+ const filePath = import_node_path14.default.join(this.screensDir, file2);
52137
53274
  let raw;
52138
53275
  try {
52139
- raw = JSON.parse((0, import_node_fs9.readFileSync)(filePath, "utf8"));
53276
+ raw = JSON.parse((0, import_node_fs11.readFileSync)(filePath, "utf8"));
52140
53277
  } catch (error48) {
52141
53278
  console.warn(`Skipping malformed JSON file: ${filePath}`, error48);
52142
53279
  continue;
@@ -52152,15 +53289,15 @@ var ServerStore = class extends EventTarget {
52152
53289
  });
52153
53290
  }
52154
53291
  }
52155
- if (!(0, import_node_fs9.existsSync)(this.artifactsDir)) {
53292
+ if (!(0, import_node_fs11.existsSync)(this.artifactsDir)) {
52156
53293
  return;
52157
53294
  }
52158
- for (const file2 of (0, import_node_fs9.readdirSync)(this.artifactsDir)) {
53295
+ for (const file2 of (0, import_node_fs11.readdirSync)(this.artifactsDir)) {
52159
53296
  if (!file2.endsWith(JSON_FILE_SUFFIX)) {
52160
53297
  continue;
52161
53298
  }
52162
53299
  const id = file2.slice(0, -JSON_FILE_SUFFIX.length);
52163
- const metadataPath = import_node_path11.default.join(this.artifactsDir, file2);
53300
+ const metadataPath = import_node_path14.default.join(this.artifactsDir, file2);
52164
53301
  const metadata = this.readArtifactFile(metadataPath, id);
52165
53302
  this._artifacts.set(id, metadata);
52166
53303
  this.startWatchingArtifactContent(metadata);
@@ -52329,20 +53466,20 @@ var ServerStore = class extends EventTarget {
52329
53466
  * without statting.
52330
53467
  */
52331
53468
  normalizeArtifactPath(artifactPath) {
52332
- if (!import_node_path11.default.isAbsolute(artifactPath)) {
53469
+ if (!import_node_path14.default.isAbsolute(artifactPath)) {
52333
53470
  throw new InvalidRequestError("path must be absolute");
52334
53471
  }
52335
53472
  const stripped = stripTrailingSeparators(artifactPath);
52336
53473
  let stat;
52337
53474
  try {
52338
- (0, import_node_fs9.accessSync)(stripped, import_node_fs9.constants.R_OK);
52339
- stat = (0, import_node_fs9.statSync)(stripped);
53475
+ (0, import_node_fs11.accessSync)(stripped, import_node_fs11.constants.R_OK);
53476
+ stat = (0, import_node_fs11.statSync)(stripped);
52340
53477
  } catch {
52341
53478
  throw new InvalidRequestError(`path does not exist or is not readable: ${artifactPath}`);
52342
53479
  }
52343
53480
  if (stat.isDirectory()) {
52344
- const canonical = hasTrailingSeparator(stripped) ? stripped : `${stripped}${import_node_path11.default.sep}`;
52345
- if (!DIRECTORY_INDEX_BASENAMES.some((basename) => (0, import_node_fs9.existsSync)(import_node_path11.default.join(canonical, basename)))) {
53481
+ const canonical = hasTrailingSeparator(stripped) ? stripped : `${stripped}${import_node_path14.default.sep}`;
53482
+ if (!DIRECTORY_INDEX_BASENAMES.some((basename) => (0, import_node_fs11.existsSync)(import_node_path14.default.join(canonical, basename)))) {
52346
53483
  throw new InvalidRequestError(`directory artifact must contain index.html or index.htm: ${canonical}`);
52347
53484
  }
52348
53485
  return canonical;
@@ -52356,11 +53493,11 @@ var ServerStore = class extends EventTarget {
52356
53493
  return stripped;
52357
53494
  }
52358
53495
  canInstallOnboardingArtifact() {
52359
- return !(0, import_node_fs9.existsSync)(getOnboardingArtifactSentinelPath(this.storagePath)) && !this._artifacts.has(ONBOARDING_ARTIFACT_ID) && this.onboardingArtifactSourcePath !== void 0;
53496
+ return !(0, import_node_fs11.existsSync)(getOnboardingArtifactSentinelPath(this.storagePath)) && !this._artifacts.has(ONBOARDING_ARTIFACT_ID) && this.onboardingArtifactSourcePath !== void 0;
52360
53497
  }
52361
53498
  installOnboardingArtifactIfNeeded() {
52362
53499
  try {
52363
- if ((0, import_node_fs9.existsSync)(getOnboardingArtifactSentinelPath(this.storagePath))) {
53500
+ if ((0, import_node_fs11.existsSync)(getOnboardingArtifactSentinelPath(this.storagePath))) {
52364
53501
  return;
52365
53502
  }
52366
53503
  if (this._artifacts.has(ONBOARDING_ARTIFACT_ID)) {
@@ -52372,9 +53509,9 @@ var ServerStore = class extends EventTarget {
52372
53509
  return;
52373
53510
  }
52374
53511
  const screenID = this.resolveActiveScreenID(this.activeScreenID) ?? this.pickPreferredScreenID();
52375
- const onboardingPath = import_node_path11.default.join(getAgentArtifactsDir(this.storagePath), ONBOARDING_ARTIFACT_DIRNAME) + import_node_path11.default.sep;
52376
- if (!(0, import_node_fs9.existsSync)(onboardingPath)) {
52377
- (0, import_node_fs9.cpSync)(this.onboardingArtifactSourcePath, onboardingPath, { recursive: true });
53512
+ const onboardingPath = import_node_path14.default.join(getAgentArtifactsDir(this.storagePath), ONBOARDING_ARTIFACT_DIRNAME) + import_node_path14.default.sep;
53513
+ if (!(0, import_node_fs11.existsSync)(onboardingPath)) {
53514
+ (0, import_node_fs11.cpSync)(this.onboardingArtifactSourcePath, onboardingPath, { recursive: true });
52378
53515
  }
52379
53516
  this.createArtifact({
52380
53517
  id: ONBOARDING_ARTIFACT_ID,
@@ -52390,7 +53527,7 @@ var ServerStore = class extends EventTarget {
52390
53527
  }
52391
53528
  }
52392
53529
  writeOnboardingArtifactSentinel() {
52393
- (0, import_node_fs9.writeFileSync)(
53530
+ (0, import_node_fs11.writeFileSync)(
52394
53531
  getOnboardingArtifactSentinelPath(this.storagePath),
52395
53532
  JSON.stringify({
52396
53533
  version: ONBOARDING_ARTIFACT_SENTINEL_VERSION,
@@ -52408,11 +53545,11 @@ var ServerStore = class extends EventTarget {
52408
53545
  this.persistDisplayState();
52409
53546
  }
52410
53547
  ensureDirectories() {
52411
- (0, import_node_fs9.mkdirSync)(import_node_path11.default.join(this.storagePath, "state"), { recursive: true });
52412
- (0, import_node_fs9.mkdirSync)(this.screensDir, { recursive: true });
52413
- (0, import_node_fs9.mkdirSync)(this.artifactsDir, { recursive: true });
52414
- (0, import_node_fs9.mkdirSync)(getThemesDir(this.storagePath), { recursive: true });
52415
- (0, import_node_fs9.mkdirSync)(getAgentArtifactsDir(this.storagePath), { recursive: true });
53548
+ (0, import_node_fs11.mkdirSync)(import_node_path14.default.join(this.storagePath, "state"), { recursive: true });
53549
+ (0, import_node_fs11.mkdirSync)(this.screensDir, { recursive: true });
53550
+ (0, import_node_fs11.mkdirSync)(this.artifactsDir, { recursive: true });
53551
+ (0, import_node_fs11.mkdirSync)(getThemesDir(this.storagePath), { recursive: true });
53552
+ (0, import_node_fs11.mkdirSync)(getAgentArtifactsDir(this.storagePath), { recursive: true });
52416
53553
  }
52417
53554
  rebuildArtifactScreens() {
52418
53555
  this.artifactScreens.clear();
@@ -52431,12 +53568,12 @@ var ServerStore = class extends EventTarget {
52431
53568
  }
52432
53569
  }
52433
53570
  loadDisplayState() {
52434
- if (!(0, import_node_fs9.existsSync)(this.displayStatePath)) {
53571
+ if (!(0, import_node_fs11.existsSync)(this.displayStatePath)) {
52435
53572
  return false;
52436
53573
  }
52437
53574
  let raw;
52438
53575
  try {
52439
- raw = (0, import_node_fs9.readFileSync)(this.displayStatePath, "utf8");
53576
+ raw = (0, import_node_fs11.readFileSync)(this.displayStatePath, "utf8");
52440
53577
  } catch {
52441
53578
  return false;
52442
53579
  }
@@ -52454,7 +53591,7 @@ var ServerStore = class extends EventTarget {
52454
53591
  return false;
52455
53592
  }
52456
53593
  persistDisplayState() {
52457
- (0, import_node_fs9.writeFileSync)(
53594
+ (0, import_node_fs11.writeFileSync)(
52458
53595
  this.displayStatePath,
52459
53596
  JSON.stringify(this.getDisplayState(), null, JSON_INDENT_SPACES)
52460
53597
  );
@@ -52476,11 +53613,11 @@ var ServerStore = class extends EventTarget {
52476
53613
  return firstScreen.id;
52477
53614
  }
52478
53615
  loadOrCreateAuthToken() {
52479
- if ((0, import_node_fs9.existsSync)(this.tokenPath)) {
52480
- return (0, import_node_fs9.readFileSync)(this.tokenPath, "utf8").trim();
53616
+ if ((0, import_node_fs11.existsSync)(this.tokenPath)) {
53617
+ return (0, import_node_fs11.readFileSync)(this.tokenPath, "utf8").trim();
52481
53618
  }
52482
53619
  const token = createToken();
52483
- (0, import_node_fs9.writeFileSync)(this.tokenPath, `${token}
53620
+ (0, import_node_fs11.writeFileSync)(this.tokenPath, `${token}
52484
53621
  `);
52485
53622
  return token;
52486
53623
  }
@@ -52488,12 +53625,12 @@ var ServerStore = class extends EventTarget {
52488
53625
  if (!this.screens.has(screen.id)) {
52489
53626
  throw new Error(`Cannot persist screen ${screen.id}: not in live map`);
52490
53627
  }
52491
- (0, import_node_fs9.writeFileSync)(import_node_path11.default.join(this.screensDir, `${screen.id}.json`), JSON.stringify(screen, null, JSON_INDENT_SPACES));
53628
+ (0, import_node_fs11.writeFileSync)(import_node_path14.default.join(this.screensDir, `${screen.id}.json`), JSON.stringify(screen, null, JSON_INDENT_SPACES));
52492
53629
  }
52493
53630
  readArtifactFile(filePath, expectedID) {
52494
53631
  let raw;
52495
53632
  try {
52496
- raw = (0, import_node_fs9.readFileSync)(filePath, "utf8");
53633
+ raw = (0, import_node_fs11.readFileSync)(filePath, "utf8");
52497
53634
  } catch (error48) {
52498
53635
  throw this.invalidMetadataFile(filePath, "unreadable", error48);
52499
53636
  }
@@ -52515,7 +53652,7 @@ var ServerStore = class extends EventTarget {
52515
53652
  `id ${result.data.id} does not match filename ${expectedID}`
52516
53653
  );
52517
53654
  }
52518
- if (result.data.kind === "path" && !import_node_path11.default.isAbsolute(result.data.path)) {
53655
+ if (result.data.kind === "path" && !import_node_path14.default.isAbsolute(result.data.path)) {
52519
53656
  throw this.invalidMetadataFile(filePath, "path must be absolute");
52520
53657
  }
52521
53658
  return result.data;
@@ -52532,7 +53669,7 @@ Review docs/storage.md for the current schema, and either update the file to mat
52532
53669
  return cause !== void 0 ? new Error(message, { cause }) : new Error(message);
52533
53670
  }
52534
53671
  writeArtifact(artifact) {
52535
- (0, import_node_fs9.writeFileSync)(getArtifactLiveMetadataPath(this.storagePath, artifact.id), JSON.stringify(artifact, null, JSON_INDENT_SPACES));
53672
+ (0, import_node_fs11.writeFileSync)(getArtifactLiveMetadataPath(this.storagePath, artifact.id), JSON.stringify(artifact, null, JSON_INDENT_SPACES));
52536
53673
  }
52537
53674
  get screensDir() {
52538
53675
  return getScreensDir(this.storagePath);
@@ -52568,8 +53705,10 @@ function collectLayoutArtifactIDs(node) {
52568
53705
  }
52569
53706
 
52570
53707
  // src/index.ts
52571
- var import_meta2 = {};
53708
+ var import_meta3 = {};
52572
53709
  var DAEMON_NAME = "com.television.server";
53710
+ var TELEMETRY_LAUNCH_MODE_ENV = "TELEVISION_LAUNCH_MODE";
53711
+ var SKILL_INSTALL_TELEMETRY_TIMEOUT_MS2 = 1e3;
52573
53712
  var MAX_PORT = 65535;
52574
53713
  var HTTP_UNAUTHORIZED_STATUS2 = 401;
52575
53714
  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`.";
@@ -52595,6 +53734,23 @@ function writeConnectURLs(output, urls, options = {}) {
52595
53734
  writeLine(output, ` ${terminalHyperlink(connectURL)}`);
52596
53735
  }
52597
53736
  }
53737
+ async function bestEffortWithinTimeout2(operation, timeoutMs) {
53738
+ void operation.catch(() => {
53739
+ });
53740
+ return await new Promise((resolve) => {
53741
+ const timeout = setTimeout(() => resolve(null), timeoutMs);
53742
+ operation.then(
53743
+ (value) => {
53744
+ clearTimeout(timeout);
53745
+ resolve(value);
53746
+ },
53747
+ () => {
53748
+ clearTimeout(timeout);
53749
+ resolve(null);
53750
+ }
53751
+ );
53752
+ });
53753
+ }
52598
53754
  function ensureHelpPointer(message) {
52599
53755
  return message.includes(HELP_POINTER) ? message : `${message}
52600
53756
  ${HELP_POINTER}`;
@@ -52603,24 +53759,36 @@ function createDirectiveError(message) {
52603
53759
  return new CLIDirectiveError(ensureHelpPointer(message));
52604
53760
  }
52605
53761
  function getDevPackageDir() {
52606
- return import_node_path12.default.resolve(import_node_path12.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url)), "..");
53762
+ return import_node_path15.default.resolve(import_node_path15.default.dirname((0, import_node_url3.fileURLToPath)(import_meta3.url)), "..");
52607
53763
  }
52608
53764
  function resolveVercelSkillsInstallerBin() {
52609
53765
  if (typeof require === "function" && typeof require.resolve === "function") {
52610
53766
  return require.resolve("skills/bin/cli.mjs");
52611
53767
  }
52612
- const localRequire = (0, import_node_module.createRequire)(import_node_path12.default.join(getDevPackageDir(), "package.json"));
53768
+ const localRequire = (0, import_node_module.createRequire)(import_node_path15.default.join(getDevPackageDir(), "package.json"));
52613
53769
  return localRequire.resolve("skills/bin/cli.mjs");
52614
53770
  }
52615
53771
  function readCLIVersion() {
52616
- if ("0.1.169".length > 0) {
52617
- return "0.1.169";
53772
+ if ("0.1.171".length > 0) {
53773
+ return "0.1.171";
52618
53774
  }
52619
- const devPackageJsonPath = import_node_path12.default.join(getDevPackageDir(), "package.json");
52620
- if (!(0, import_node_fs10.existsSync)(devPackageJsonPath)) {
53775
+ const devPackageJsonPath = import_node_path15.default.join(getDevPackageDir(), "package.json");
53776
+ if (!(0, import_node_fs12.existsSync)(devPackageJsonPath)) {
52621
53777
  throw new Error("Could not resolve package.json for repo-local CLI version.");
52622
53778
  }
52623
- return JSON.parse((0, import_node_fs10.readFileSync)(devPackageJsonPath, "utf8")).version;
53779
+ return JSON.parse((0, import_node_fs12.readFileSync)(devPackageJsonPath, "utf8")).version;
53780
+ }
53781
+ function inspectTelemetryBuildConfig(env = {}, options = {}) {
53782
+ const project = resolvePostHogProject(env, options);
53783
+ return {
53784
+ telemetryBuild: true ? "production" : null,
53785
+ telemetrySuppressionReason: telemetryEnvironmentSuppressionReason(env),
53786
+ posthogProject: {
53787
+ projectId: project.projectId,
53788
+ projectToken: project.projectToken,
53789
+ ingestionHost: project.ingestionHost
53790
+ }
53791
+ };
52624
53792
  }
52625
53793
  var FRONTMATTER_DELIMITER = "---\n";
52626
53794
  var FRONTMATTER_DELIMITER_LENGTH = FRONTMATTER_DELIMITER.length;
@@ -52673,7 +53841,7 @@ function formatCLIError(error48, argv = []) {
52673
53841
  const status = typeof error48.status === "number" ? Number(error48.status) : void 0;
52674
53842
  if (status === HTTP_UNAUTHORIZED_STATUS2) {
52675
53843
  return ensureHelpPointer(
52676
- `Television server at ${serverURL} rejected the request as unauthorized. Check the token in ${import_node_path12.default.join(storagePathFromArgv(argv) ?? getTelevisionStoragePath(), "state", "token")}.`
53844
+ `Television server at ${serverURL} rejected the request as unauthorized. Check the token in ${import_node_path15.default.join(storagePathFromArgv(argv) ?? getTelevisionStoragePath(), "state", "token")}.`
52677
53845
  );
52678
53846
  }
52679
53847
  if (status !== void 0) {
@@ -52716,63 +53884,63 @@ function resolveStaticDir() {
52716
53884
  if (!process.argv[1]) {
52717
53885
  return void 0;
52718
53886
  }
52719
- const entryDir = import_node_path12.default.dirname((0, import_node_fs10.realpathSync)(process.argv[1]));
52720
- const resolved = import_node_path12.default.resolve(entryDir, "./web");
52721
- return (0, import_node_fs10.existsSync)(import_node_path12.default.join(resolved, "index.html")) ? resolved : void 0;
53887
+ const entryDir = import_node_path15.default.dirname((0, import_node_fs12.realpathSync)(process.argv[1]));
53888
+ const resolved = import_node_path15.default.resolve(entryDir, "./web");
53889
+ return (0, import_node_fs12.existsSync)(import_node_path15.default.join(resolved, "index.html")) ? resolved : void 0;
52722
53890
  }
52723
53891
  function resolveBundledViewsPath() {
52724
53892
  if (process.argv[1]) {
52725
- const entryDir = import_node_path12.default.dirname((0, import_node_fs10.realpathSync)(process.argv[1]));
52726
- const resolved = import_node_path12.default.resolve(entryDir, "./views");
52727
- return (0, import_node_fs10.existsSync)(resolved) ? resolved : void 0;
53893
+ const entryDir = import_node_path15.default.dirname((0, import_node_fs12.realpathSync)(process.argv[1]));
53894
+ const resolved = import_node_path15.default.resolve(entryDir, "./views");
53895
+ return (0, import_node_fs12.existsSync)(resolved) ? resolved : void 0;
52728
53896
  }
52729
- const devViewsPath = import_node_path12.default.join(getDevPackageDir(), "dist/views");
52730
- return (0, import_node_fs10.existsSync)(devViewsPath) ? devViewsPath : void 0;
53897
+ const devViewsPath = import_node_path15.default.join(getDevPackageDir(), "dist/views");
53898
+ return (0, import_node_fs12.existsSync)(devViewsPath) ? devViewsPath : void 0;
52731
53899
  }
52732
53900
  function resolveCanonicalDir() {
52733
53901
  if (process.argv[1]) {
52734
- const entryDir = import_node_path12.default.dirname((0, import_node_fs10.realpathSync)(process.argv[1]));
52735
- const resolved = import_node_path12.default.resolve(entryDir, "./canonical/v1");
52736
- return (0, import_node_fs10.existsSync)(resolved) ? resolved : void 0;
53902
+ const entryDir = import_node_path15.default.dirname((0, import_node_fs12.realpathSync)(process.argv[1]));
53903
+ const resolved = import_node_path15.default.resolve(entryDir, "./canonical/v1");
53904
+ return (0, import_node_fs12.existsSync)(resolved) ? resolved : void 0;
52737
53905
  }
52738
- const devCanonicalPath = import_node_path12.default.resolve(
53906
+ const devCanonicalPath = import_node_path15.default.resolve(
52739
53907
  getDevPackageDir(),
52740
53908
  "../server/dist/canonical/v1"
52741
53909
  );
52742
- return (0, import_node_fs10.existsSync)(devCanonicalPath) ? devCanonicalPath : void 0;
53910
+ return (0, import_node_fs12.existsSync)(devCanonicalPath) ? devCanonicalPath : void 0;
52743
53911
  }
52744
53912
  function resolveOnboardingArtifactSourcePath() {
52745
53913
  if (process.argv[1]) {
52746
- const entryDir = import_node_path12.default.dirname((0, import_node_fs10.realpathSync)(process.argv[1]));
52747
- const resolved = import_node_path12.default.resolve(entryDir, "./onboarding/television-onboarding");
52748
- return (0, import_node_fs10.existsSync)(resolved) ? resolved : void 0;
53914
+ const entryDir = import_node_path15.default.dirname((0, import_node_fs12.realpathSync)(process.argv[1]));
53915
+ const resolved = import_node_path15.default.resolve(entryDir, "./onboarding/television-onboarding");
53916
+ return (0, import_node_fs12.existsSync)(resolved) ? resolved : void 0;
52749
53917
  }
52750
- const devPath = import_node_path12.default.resolve(
53918
+ const devPath = import_node_path15.default.resolve(
52751
53919
  getDevPackageDir(),
52752
53920
  "../server/assets/television-onboarding"
52753
53921
  );
52754
- return (0, import_node_fs10.existsSync)(devPath) ? devPath : void 0;
53922
+ return (0, import_node_fs12.existsSync)(devPath) ? devPath : void 0;
52755
53923
  }
52756
53924
  function resolveBundledSkillsRoot() {
52757
- const builtPath = typeof process.argv[1] === "string" ? import_node_path12.default.resolve(import_node_path12.default.dirname((0, import_node_fs10.realpathSync)(process.argv[1])), "./skills") : void 0;
52758
- if (builtPath && (0, import_node_fs10.existsSync)(builtPath)) {
53925
+ const builtPath = typeof process.argv[1] === "string" ? import_node_path15.default.resolve(import_node_path15.default.dirname((0, import_node_fs12.realpathSync)(process.argv[1])), "./skills") : void 0;
53926
+ if (builtPath && (0, import_node_fs12.existsSync)(builtPath)) {
52759
53927
  return builtPath;
52760
53928
  }
52761
- const devPath = import_node_path12.default.resolve(getDevPackageDir(), "../skills/dist");
52762
- return (0, import_node_fs10.existsSync)(devPath) ? devPath : void 0;
53929
+ const devPath = import_node_path15.default.resolve(getDevPackageDir(), "../skills/dist");
53930
+ return (0, import_node_fs12.existsSync)(devPath) ? devPath : void 0;
52763
53931
  }
52764
53932
  function copyBundledSkillsToDestination(bundledSkillsRoot, destinationRoot) {
52765
- if ((0, import_node_fs10.existsSync)(destinationRoot) && !(0, import_node_fs10.statSync)(destinationRoot).isDirectory()) {
53933
+ if ((0, import_node_fs12.existsSync)(destinationRoot) && !(0, import_node_fs12.statSync)(destinationRoot).isDirectory()) {
52766
53934
  throw new Error(`Skills destination is not a directory: ${destinationRoot}`);
52767
53935
  }
52768
- (0, import_node_fs10.mkdirSync)(destinationRoot, { recursive: true });
53936
+ (0, import_node_fs12.mkdirSync)(destinationRoot, { recursive: true });
52769
53937
  const copied = [];
52770
- const entries = (0, import_node_fs10.readdirSync)(bundledSkillsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).sort((a, b2) => a.name.localeCompare(b2.name));
53938
+ const entries = (0, import_node_fs12.readdirSync)(bundledSkillsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).sort((a, b2) => a.name.localeCompare(b2.name));
52771
53939
  for (const entry of entries) {
52772
- const sourcePath = import_node_path12.default.join(bundledSkillsRoot, entry.name);
52773
- const destinationPath = import_node_path12.default.join(destinationRoot, entry.name);
52774
- (0, import_node_fs10.rmSync)(destinationPath, { recursive: true, force: true });
52775
- (0, import_node_fs10.cpSync)(sourcePath, destinationPath, { recursive: true });
53940
+ const sourcePath = import_node_path15.default.join(bundledSkillsRoot, entry.name);
53941
+ const destinationPath = import_node_path15.default.join(destinationRoot, entry.name);
53942
+ (0, import_node_fs12.rmSync)(destinationPath, { recursive: true, force: true });
53943
+ (0, import_node_fs12.cpSync)(sourcePath, destinationPath, { recursive: true });
52776
53944
  copied.push({ name: entry.name, sourcePath, destinationPath });
52777
53945
  }
52778
53946
  return copied;
@@ -52854,11 +54022,11 @@ function formatCommanderError(argv, error48) {
52854
54022
  return null;
52855
54023
  }
52856
54024
  function readAuthToken(storagePath) {
52857
- const tokenPath = import_node_path12.default.join(storagePath, "state", "token");
52858
- if (!(0, import_node_fs10.existsSync)(tokenPath)) {
54025
+ const tokenPath = import_node_path15.default.join(storagePath, "state", "token");
54026
+ if (!(0, import_node_fs12.existsSync)(tokenPath)) {
52859
54027
  return void 0;
52860
54028
  }
52861
- const token = (0, import_node_fs10.readFileSync)(tokenPath, "utf8").trim();
54029
+ const token = (0, import_node_fs12.readFileSync)(tokenPath, "utf8").trim();
52862
54030
  return token.length > 0 ? token : void 0;
52863
54031
  }
52864
54032
  function readOrCreateAuthToken(storagePath) {
@@ -52876,6 +54044,7 @@ function buildDaemonServeArgs(options = {}) {
52876
54044
  if (options.auth === false) args.push("--no-auth");
52877
54045
  if (options.port !== void 0) args.push("--port", String(options.port));
52878
54046
  if (options.storagePath) args.push("--storage-path", options.storagePath);
54047
+ if (options.installedByAgent) args.push("--installed-by-agent", options.installedByAgent);
52879
54048
  return args;
52880
54049
  }
52881
54050
  function redactSensitiveEnv(env) {
@@ -52885,6 +54054,9 @@ function redactSensitiveEnv(env) {
52885
54054
  }
52886
54055
  return redacted;
52887
54056
  }
54057
+ function resolveTelemetryLaunchMode(env) {
54058
+ return env[TELEMETRY_LAUNCH_MODE_ENV] === "daemon" ? "daemon" : "cli";
54059
+ }
52888
54060
  function isSensitiveEnvKey(key) {
52889
54061
  const normalized = key.toUpperCase();
52890
54062
  return normalized.startsWith("OPENCLAW_") || normalized.startsWith("HERMES_") || normalized.endsWith("_API_KEY") || normalized.endsWith("_TOKEN") || normalized.endsWith("_SECRET") || normalized.endsWith("_PASSWORD");
@@ -52906,7 +54078,11 @@ function createEnvironment(environment) {
52906
54078
  auth: options.auth,
52907
54079
  staticDir: options.staticDir,
52908
54080
  canonicalDir: options.canonicalDir,
52909
- acpProfile: options.acpProfile
54081
+ acpProfile: options.acpProfile,
54082
+ telemetry: {
54083
+ launchMode: options.launchMode ?? "cli",
54084
+ installedByAgent: options.installedByAgent ?? null
54085
+ }
52910
54086
  })),
52911
54087
  createDaemon: environment.createDaemon ?? ((options = {}) => {
52912
54088
  const args = buildDaemonServeArgs(options);
@@ -52923,6 +54099,7 @@ function createEnvironment(environment) {
52923
54099
  resolveBundledViewsPath: environment.resolveBundledViewsPath ?? (() => resolveBundledViewsPath()),
52924
54100
  resolveOnboardingArtifactSourcePath: environment.resolveOnboardingArtifactSourcePath ?? (() => resolveOnboardingArtifactSourcePath()),
52925
54101
  resolveBundledSkillsRoot: environment.resolveBundledSkillsRoot ?? (() => resolveBundledSkillsRoot()),
54102
+ resolveHomeDir: environment.resolveHomeDir ?? (() => import_node_os5.default.homedir()),
52926
54103
  runSkillsInstaller: environment.runSkillsInstaller ?? (async (args) => {
52927
54104
  const vercelSkillsInstallerBin = resolveVercelSkillsInstallerBin();
52928
54105
  const result = (0, import_node_child_process3.spawnSync)(process.execPath, [vercelSkillsInstallerBin, ...args], { stdio: "inherit" });
@@ -52930,6 +54107,7 @@ function createEnvironment(environment) {
52930
54107
  throw new Error(`skills ${args.join(" ")} failed (exit ${result.status ?? "signal"})`);
52931
54108
  }
52932
54109
  }),
54110
+ emitSkillInstalledTelemetry: environment.emitSkillInstalledTelemetry ?? ((options) => emitSkillInstalledTelemetry(options)),
52933
54111
  onSignal: environment.onSignal ?? ((signal, handler) => process.on(signal, handler))
52934
54112
  };
52935
54113
  }
@@ -52944,6 +54122,15 @@ function createProgram(env, argv = []) {
52944
54122
  readAuthToken(resolveClientStoragePath(options.storagePath))
52945
54123
  );
52946
54124
  };
54125
+ const emitSkillInstallTelemetry = async (input) => {
54126
+ await bestEffortWithinTimeout2(env.emitSkillInstalledTelemetry({
54127
+ storagePath: getTelevisionStoragePath(),
54128
+ version: telemetryVersion(readCLIVersion()),
54129
+ agentType: input.agentType,
54130
+ ...input.installedByAgent === void 0 ? {} : { installedByAgent: input.installedByAgent },
54131
+ env: process.env
54132
+ }), SKILL_INSTALL_TELEMETRY_TIMEOUT_MS2);
54133
+ };
52947
54134
  const uninstallPersistedService = async (storagePath) => {
52948
54135
  const daemon = env.createDaemon();
52949
54136
  let outcome = "uninstalled";
@@ -52963,7 +54150,7 @@ function createProgram(env, argv = []) {
52963
54150
  outputError: () => {
52964
54151
  }
52965
54152
  }).exitOverride();
52966
- program2.command("serve").description("Start the Television server").option("--listen <address>", "Additional IPv4 address to bind to (repeatable or comma-separated)", collectOption, []).option("--auth", "Require bearer-token auth on every listener").option("--no-auth", "Disable bearer-token auth on every listener").option("--port <number>", "Port to listen on", parsePortOption).option("--storage-path <path>", "Directory for persisted screen data").option("--persist", "Install as a persistent system service").option("--persist-uninstall", "Uninstall the persistent system service").action(async (opts) => {
54153
+ program2.command("serve").description("Start the Television server").option("--listen <address>", "Additional IPv4 address to bind to (repeatable or comma-separated)", collectOption, []).option("--auth", "Require bearer-token auth on every listener").option("--no-auth", "Disable bearer-token auth on every listener").option("--port <number>", "Port to listen on", parsePortOption).option("--storage-path <path>", "Directory for persisted screen data").option("--installed-by-agent <agent-runtime-harness-name>", "Agent runtime harness name operating this server").option("--persist", "Install as a persistent system service").option("--persist-uninstall", "Uninstall the persistent system service").action(async (opts) => {
52967
54154
  if (opts.persist && opts.persistUninstall) {
52968
54155
  throw createDirectiveError("Use either `--persist` or `--persist-uninstall`, not both.");
52969
54156
  }
@@ -52983,9 +54170,10 @@ function createProgram(env, argv = []) {
52983
54170
  if (opts.persist) {
52984
54171
  const storagePath = opts.storagePath ?? getTelevisionStoragePath();
52985
54172
  const profile2 = resolveACPAgentProfile(process.env);
52986
- const daemonEnv = buildPersistedACPEnvironment(process.env);
54173
+ const daemonEnv = buildPersistedACPEnvironment(process.env, { developerHome: env.resolveHomeDir() });
52987
54174
  if (process.env.TELEVISION_PORT !== void 0) daemonEnv.TELEVISION_PORT = process.env.TELEVISION_PORT;
52988
54175
  if (process.env.TELEVISION_STORAGE_PATH !== void 0) daemonEnv.TELEVISION_STORAGE_PATH = process.env.TELEVISION_STORAGE_PATH;
54176
+ daemonEnv[TELEMETRY_LAUNCH_MODE_ENV] = "daemon";
52989
54177
  if (profile2 && !isACPCommandResolvable(profile2.command, daemonEnv)) {
52990
54178
  const error48 = createDirectiveError(
52991
54179
  `Could not find ACP agent command \`${profile2.command}\` for \`TELEVISION_ACP_AGENT=${profile2.agent}\` on the persisted PATH. Set TELEVISION_ACP_AGENT to \`openclaw\` or \`hermes\`, and ensure the selected agent binary is available on PATH before running \`tv serve --persist\`.`
@@ -52998,6 +54186,7 @@ function createProgram(env, argv = []) {
52998
54186
  auth,
52999
54187
  port: opts.port,
53000
54188
  storagePath,
54189
+ ...opts.installedByAgent === void 0 ? {} : { installedByAgent: opts.installedByAgent },
53001
54190
  env: daemonEnv
53002
54191
  };
53003
54192
  const daemon = env.createDaemon(daemonOptions);
@@ -53024,8 +54213,9 @@ function createProgram(env, argv = []) {
53024
54213
  });
53025
54214
  throw error48;
53026
54215
  }
53027
- const serverURL = buildLocalServerURL(opts.port);
53028
- writeConnectURLs(env.stdout, [serverURL], {
54216
+ const port = resolveClientPort(opts.port);
54217
+ const serverURLs2 = resolveBindAddresses(opts.listen).map((address) => buildServerURL(address, port));
54218
+ writeConnectURLs(env.stdout, serverURLs2, {
53029
54219
  installed: true,
53030
54220
  token: auth === true ? readOrCreateAuthToken(storagePath) : null
53031
54221
  });
@@ -53048,6 +54238,8 @@ function createProgram(env, argv = []) {
53048
54238
  canonicalDir: env.resolveCanonicalDir(),
53049
54239
  bundledViewsPath: env.resolveBundledViewsPath(),
53050
54240
  onboardingArtifactSourcePath: env.resolveOnboardingArtifactSourcePath(),
54241
+ launchMode: resolveTelemetryLaunchMode(process.env),
54242
+ ...opts.installedByAgent === void 0 ? {} : { installedByAgent: opts.installedByAgent },
53051
54243
  ...profile ? { acpProfile: profile } : {}
53052
54244
  });
53053
54245
  await server.start();
@@ -53224,7 +54416,7 @@ function createProgram(env, argv = []) {
53224
54416
  "Examples: ~/.openclaw/skills, ~/.hermes/skills, ~/.agents/skills.",
53225
54417
  "`tv skills install -i` runs the external skills installer against Television's bundled skills root."
53226
54418
  ].join("\n"));
53227
- skillsCommand.command("install").description("Copy bundled Television skills into an agent harness skills folder, or run the external installer against the bundled skills root").argument("[path]", "Destination agent skills folder (for example: ~/.openclaw/skills, ~/.hermes/skills, ~/.agents/skills)").option("-i, --interactive", "Run the external skills installer against the bundled Television skills root").allowUnknownOption(true).action(async function(inputPath, opts) {
54419
+ skillsCommand.command("install").description("Copy bundled Television skills into an agent harness skills folder, or run the external installer against the bundled skills root").argument("[path]", "Destination agent skills folder (for example: ~/.openclaw/skills, ~/.hermes/skills, ~/.agents/skills)").option("-i, --interactive", "Run the external skills installer against the bundled Television skills root").option("--installed-by-agent <agent-runtime-harness-name>", "Agent runtime harness name performing this install").allowUnknownOption(true).action(async function(inputPath, opts) {
53228
54420
  const bundledTelevisionSkillsCollectionRoot = env.resolveBundledSkillsRoot();
53229
54421
  if (opts.interactive) {
53230
54422
  if (inputPath) {
@@ -53235,6 +54427,10 @@ function createProgram(env, argv = []) {
53235
54427
  }
53236
54428
  const args = ["add", bundledTelevisionSkillsCollectionRoot];
53237
54429
  await env.runSkillsInstaller(args);
54430
+ await emitSkillInstallTelemetry({
54431
+ agentType: "interactive-install",
54432
+ ...opts.installedByAgent === void 0 ? {} : { installedByAgent: opts.installedByAgent }
54433
+ });
53238
54434
  return;
53239
54435
  }
53240
54436
  if (!inputPath) {
@@ -53245,7 +54441,7 @@ function createProgram(env, argv = []) {
53245
54441
  if (!bundledTelevisionSkillsCollectionRoot) {
53246
54442
  throw new Error("Could not resolve the bundled Television skills root.");
53247
54443
  }
53248
- const destinationRoot = import_node_path12.default.resolve(inputPath);
54444
+ const destinationRoot = import_node_path15.default.resolve(inputPath);
53249
54445
  const copied = copyBundledSkillsToDestination(bundledTelevisionSkillsCollectionRoot, destinationRoot);
53250
54446
  writeLine(env.stdout, `Copied ${copied.length} bundled Television skill(s):`);
53251
54447
  for (const skill of copied) {
@@ -53253,6 +54449,19 @@ function createProgram(env, argv = []) {
53253
54449
  writeLine(env.stdout, ` from: ${skill.sourcePath}`);
53254
54450
  writeLine(env.stdout, ` to: ${skill.destinationPath}`);
53255
54451
  }
54452
+ await emitSkillInstallTelemetry({
54453
+ agentType: deriveAgentTypeFromPath(destinationRoot).agent_type,
54454
+ ...opts.installedByAgent === void 0 ? {} : { installedByAgent: opts.installedByAgent }
54455
+ });
54456
+ });
54457
+ const telemetryCommand = program2.command("telemetry").description("Control telemetry for the running Television server");
54458
+ telemetryCommand.command("disable").description("Disable telemetry for the running Television server").option("--port <number>", "Server port", parsePortOption).option("--storage-path <path>", "Directory containing the Television token").action(async (opts) => {
54459
+ const client = createAuthenticatedClient(opts);
54460
+ writeJSON(env.stdout, await client.telemetry.disable());
54461
+ });
54462
+ telemetryCommand.command("enable").description("Enable telemetry for the running Television server").option("--port <number>", "Server port", parsePortOption).option("--storage-path <path>", "Directory containing the Television token").action(async (opts) => {
54463
+ const client = createAuthenticatedClient(opts);
54464
+ writeJSON(env.stdout, await client.telemetry.enable());
53256
54465
  });
53257
54466
  program2.command("stop").description("Stop the Television system service").action(async () => {
53258
54467
  await uninstallPersistedService(getTelevisionStoragePath());
@@ -53269,6 +54478,7 @@ function createProgram(env, argv = []) {
53269
54478
  result.healthy = true;
53270
54479
  result.bindAddresses = health.bindAddresses;
53271
54480
  result.port = health.port;
54481
+ result.telemetry = await client.telemetry.status();
53272
54482
  } catch {
53273
54483
  }
53274
54484
  try {
@@ -53320,6 +54530,7 @@ if (!isVitestRuntime()) {
53320
54530
  }
53321
54531
  // Annotate the CommonJS export names for ESM import in node:
53322
54532
  0 && (module.exports = {
54533
+ inspectTelemetryBuildConfig,
53323
54534
  listVisibleCLICommandNames,
53324
54535
  resolveBundledSkillsRoot,
53325
54536
  resolveBundledViewsPath,