@telepath-computer/television 0.1.170 → 0.1.172

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);
@@ -50367,6 +50663,19 @@ function themeExists(storagePath, name) {
50367
50663
  return false;
50368
50664
  }
50369
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
+ }
50370
50679
  function rewriteThemeURLs(css, themeName) {
50371
50680
  return css.replace(URL_RE, (whole, quote, url2) => {
50372
50681
  if (/^(data:|https?:)/.test(url2) || url2.startsWith("/")) {
@@ -50466,7 +50775,7 @@ var HTTP_CONFLICT = 409;
50466
50775
  var CORS_HEADERS = {
50467
50776
  "Access-Control-Allow-Origin": "*",
50468
50777
  "Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
50469
- "Access-Control-Allow-Headers": "Authorization, Content-Type"
50778
+ "Access-Control-Allow-Headers": `Authorization, Content-Type, ${TELEVISION_CLIENT_META_HEADER}`
50470
50779
  };
50471
50780
  function applyCorsHeaders(res) {
50472
50781
  for (const [name, value] of Object.entries(CORS_HEADERS)) {
@@ -50498,11 +50807,20 @@ function handleStoreError(res, error48, fallback) {
50498
50807
  function registerRoutes(app, store, options) {
50499
50808
  const auth = options.requireAuth ? [options.requireAuth] : [];
50500
50809
  const bearerAuth = options.requireBearerAuth ? [options.requireBearerAuth] : [];
50501
- app.use("/screens", applyCorsMiddleware);
50502
- app.use("/artifacts", applyCorsMiddleware);
50503
- app.use("/display", applyCorsMiddleware);
50504
- app.use("/themes", applyCorsMiddleware);
50505
- 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);
50506
50824
  app.all("/artifact/:id", serveArtifactProxy(store));
50507
50825
  app.all("/artifact/:id/*", serveArtifactProxy(store));
50508
50826
  const markdownContent = serveMarkdownContent(store);
@@ -50517,6 +50835,18 @@ function registerRoutes(app, store, options) {
50517
50835
  app.options("/themes/:name/theme.css", (_req, res) => res.status(HTTP_NO_CONTENT2).end());
50518
50836
  app.options("/themes/:name/*", (_req, res) => res.status(HTTP_NO_CONTENT2).end());
50519
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
+ });
50520
50850
  app.get("/screens", ...auth, (_req, res) => {
50521
50851
  res.json({ screens: store.listScreens() });
50522
50852
  });
@@ -50530,7 +50860,7 @@ function registerRoutes(app, store, options) {
50530
50860
  const screen = store.createScreen({
50531
50861
  name: parsed.data.name,
50532
50862
  ...parsed.data.id !== void 0 ? { id: parsed.data.id } : {}
50533
- });
50863
+ }, telemetryContext(req));
50534
50864
  res.status(HTTP_CREATED).json({ screen });
50535
50865
  } catch (error48) {
50536
50866
  sendError(res, HTTP_BAD_REQUEST, error48 instanceof Error ? error48.message : "Failed to create screen");
@@ -50546,7 +50876,7 @@ function registerRoutes(app, store, options) {
50546
50876
  });
50547
50877
  app.delete("/screens/:id", ...auth, (req, res) => {
50548
50878
  try {
50549
- const result = store.removeScreen(req.params.id);
50879
+ const result = store.removeScreen(req.params.id, telemetryContext(req));
50550
50880
  res.json(result);
50551
50881
  } catch (error48) {
50552
50882
  handleStoreError(res, error48, "Failed to delete screen");
@@ -50569,7 +50899,7 @@ function registerRoutes(app, store, options) {
50569
50899
  const screen = store.updateScreen({
50570
50900
  screenID: req.params.id,
50571
50901
  fields: { ...parsed.data, layout: parsed.data.layout }
50572
- });
50902
+ }, telemetryContext(req));
50573
50903
  res.json({ screen });
50574
50904
  } catch (error48) {
50575
50905
  handleStoreError(res, error48, "Failed to update screen");
@@ -50596,7 +50926,7 @@ function registerRoutes(app, store, options) {
50596
50926
  return;
50597
50927
  }
50598
50928
  try {
50599
- const artifact = store.createArtifact(parsed.data);
50929
+ const artifact = store.createArtifact(parsed.data, telemetryContext(req));
50600
50930
  res.status(HTTP_CREATED).json({ artifact, screenID: parsed.data.screenID });
50601
50931
  } catch (error48) {
50602
50932
  handleStoreError(res, error48, "Failed to create artifact");
@@ -50604,7 +50934,7 @@ function registerRoutes(app, store, options) {
50604
50934
  });
50605
50935
  app.delete("/artifacts/:id", ...auth, (req, res) => {
50606
50936
  try {
50607
- const result = store.deleteArtifact(req.params.id);
50937
+ const result = store.deleteArtifact(req.params.id, telemetryContext(req));
50608
50938
  res.json(result);
50609
50939
  } catch (error48) {
50610
50940
  handleStoreError(res, error48, "Failed to delete artifact");
@@ -50617,7 +50947,7 @@ function registerRoutes(app, store, options) {
50617
50947
  return;
50618
50948
  }
50619
50949
  try {
50620
- 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));
50621
50951
  res.json({ artifact });
50622
50952
  } catch (error48) {
50623
50953
  handleStoreError(res, error48, "Failed to update artifact");
@@ -50641,7 +50971,7 @@ function registerRoutes(app, store, options) {
50641
50971
  return;
50642
50972
  }
50643
50973
  try {
50644
- store.patchDisplay(parsed.data);
50974
+ store.patchDisplay(parsed.data, telemetryContext(req));
50645
50975
  res.status(HTTP_NO_CONTENT2).end();
50646
50976
  } catch (error48) {
50647
50977
  handleStoreError(res, error48, "Failed to patch display");
@@ -50700,18 +51030,23 @@ var EventStreamServer = class extends withDisposable(class {
50700
51030
  wsServer;
50701
51031
  store;
50702
51032
  authRequired;
51033
+ recordTelemetryActivity;
50703
51034
  unsubscribe = [];
50704
51035
  constructor(options) {
50705
51036
  super();
50706
51037
  this.store = options.store;
50707
51038
  this.authRequired = options.authRequired;
51039
+ this.recordTelemetryActivity = options.recordTelemetryActivity;
50708
51040
  this.wsServer = new import_websocket_server.default({ noServer: true });
50709
51041
  this.wsServer.on("connection", (socket, request) => {
50710
51042
  if (this.authRequired && !isAuthorizedQueryToken(request.url, this.store.authToken)) {
50711
51043
  socket.close(AUTH_FAILED_CLOSE_CODE, "Authentication failed");
50712
51044
  return;
50713
51045
  }
50714
- 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);
50715
51050
  });
50716
51051
  });
50717
51052
  this.subscribeStore();
@@ -50809,6 +51144,18 @@ var EventStreamServer = class extends withDisposable(class {
50809
51144
  }
50810
51145
  }
50811
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
+ }
50812
51159
 
50813
51160
  // ../server/src/acp-bridge.ts
50814
51161
  var import_node_child_process2 = require("node:child_process");
@@ -51091,13 +51438,13 @@ var ACPServer = class extends withDisposable(class {
51091
51438
  };
51092
51439
 
51093
51440
  // ../server/src/bind-addresses.ts
51094
- var import_node_net = require("node:net");
51441
+ var import_node_net2 = require("node:net");
51095
51442
  var LOCALHOST_IPV4 = "127.0.0.1";
51096
51443
  var ANY_IPV4 = "0.0.0.0";
51097
51444
  function resolveBindAddresses(listenValues = []) {
51098
51445
  const addresses = [LOCALHOST_IPV4];
51099
51446
  for (const address of splitListenValues(listenValues)) {
51100
- if (!(0, import_node_net.isIPv4)(address)) {
51447
+ if (!(0, import_node_net2.isIPv4)(address)) {
51101
51448
  throw new Error(`Invalid --listen address \`${address}\`. Use an IPv4 address.`);
51102
51449
  }
51103
51450
  addresses.push(address);
@@ -51341,7 +51688,715 @@ function pad2(value) {
51341
51688
  return String(value).padStart(2, "0");
51342
51689
  }
51343
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
+
51344
52398
  // ../server/src/server.ts
52399
+ var import_meta = {};
51345
52400
  var HTTP_UNAUTHORIZED_STATUS = 401;
51346
52401
  var LOOPBACK_IPV4 = "127.0.0.1";
51347
52402
  var Server = class {
@@ -51355,7 +52410,9 @@ var Server = class {
51355
52410
  authRequired;
51356
52411
  authMode;
51357
52412
  bindAddresses;
52413
+ telemetryOptions;
51358
52414
  bindFailures = [];
52415
+ telemetryRuntime = null;
51359
52416
  listeningPort;
51360
52417
  baseURLs;
51361
52418
  disposed = false;
@@ -51365,6 +52422,7 @@ var Server = class {
51365
52422
  this.authRequired = options.auth ?? false;
51366
52423
  this.authMode = options.auth === true ? "auth" : options.auth === false ? "no-auth" : "none";
51367
52424
  this.bindAddresses = resolveBindAddresses(options.host ? [options.host] : options.listen);
52425
+ this.telemetryOptions = options.telemetry ?? {};
51368
52426
  this.listeningPort = this.port;
51369
52427
  this.baseURLs = [];
51370
52428
  this.app = (0, import_express2.default)();
@@ -51380,7 +52438,8 @@ var Server = class {
51380
52438
  this.app.use(import_express2.default.json());
51381
52439
  this.events = new EventStreamServer({
51382
52440
  store: this.store,
51383
- authRequired: this.authRequired
52441
+ authRequired: this.authRequired,
52442
+ recordTelemetryActivity: (clientContext) => this.telemetryRuntime?.recordClientActivity(clientContext)
51384
52443
  });
51385
52444
  this.acp = options.acpProfile ? new ACPServer({
51386
52445
  authToken: this.store.authToken,
@@ -51390,7 +52449,13 @@ var Server = class {
51390
52449
  registerRoutes(this.app, this.store, {
51391
52450
  requireAuth: this.requireAuthorization,
51392
52451
  requireBearerAuth: this.requireBearerAuthorization,
51393
- 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" }
51394
52459
  });
51395
52460
  if (options.canonicalDir) {
51396
52461
  this.app.use("/canonical/v1", (_req, res, next) => {
@@ -51456,6 +52521,7 @@ var Server = class {
51456
52521
  log(this.store.storagePath, message, { reason: "all bind addresses failed", snapshot: this.configurationSnapshot() });
51457
52522
  throw new Error(message);
51458
52523
  }
52524
+ await this.startTelemetry();
51459
52525
  log(this.store.storagePath, "server started", { snapshot: this.configurationSnapshot() });
51460
52526
  if (!this.authRequired) {
51461
52527
  log(this.store.storagePath, "server running without bearer-token enforcement", { authMode: this.authMode });
@@ -51501,7 +52567,8 @@ var Server = class {
51501
52567
  await Promise.all([
51502
52568
  this.events.dispose(),
51503
52569
  this.acp?.dispose() ?? Promise.resolve(),
51504
- Promise.resolve(this.store.dispose())
52570
+ Promise.resolve(this.store.dispose()),
52571
+ this.telemetryRuntime?.shutdown() ?? Promise.resolve()
51505
52572
  ]);
51506
52573
  await Promise.all(this.httpServers.map((server) => this.closeServer(server)));
51507
52574
  } catch (error48) {
@@ -51551,6 +52618,35 @@ var Server = class {
51551
52618
  getNonLoopbackBoundAddresses() {
51552
52619
  return this.baseURLs.map((url2) => new URL(url2).hostname).filter((address) => address !== LOOPBACK_IPV4);
51553
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
+ }
51554
52650
  configurationSnapshot() {
51555
52651
  return {
51556
52652
  storagePath: this.store.storagePath,
@@ -51598,15 +52694,23 @@ var Server = class {
51598
52694
  res.status(HTTP_UNAUTHORIZED_STATUS).json({ error: "Unauthorized" });
51599
52695
  };
51600
52696
  };
52697
+ function readServerPackageVersion() {
52698
+ if ("0.1.172".length > 0) {
52699
+ return telemetryVersion("0.1.172");
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
+ }
51601
52705
 
51602
52706
  // ../server/src/server-store.ts
51603
- var import_node_fs9 = require("node:fs");
51604
- 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);
51605
52709
 
51606
52710
  // ../server/src/file-watcher.ts
51607
52711
  var import_node_events = require("node:events");
51608
52712
  var fs3 = __toESM(require("node:fs"), 1);
51609
- var import_node_path8 = __toESM(require("node:path"), 1);
52713
+ var import_node_path12 = __toESM(require("node:path"), 1);
51610
52714
  var DEFAULT_REARM_INTERVAL_MS = 250;
51611
52715
  function isMissingWatchRootError(error48) {
51612
52716
  return typeof error48 === "object" && error48 !== null && "code" in error48 && error48.code === "ENOENT";
@@ -51625,9 +52729,9 @@ var ReArmingContentWatcher = class extends import_node_events.EventEmitter {
51625
52729
  #rootEventImmediate = null;
51626
52730
  constructor(filePath, onChange, basenames, options = {}) {
51627
52731
  super();
51628
- this.#dir = basenames === void 0 ? import_node_path8.default.dirname(filePath) : filePath;
51629
- this.#watchedBasenames = new Set(basenames ?? [import_node_path8.default.basename(filePath)]);
51630
- 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));
51631
52735
  this.#onChange = onChange;
51632
52736
  this.#options = options;
51633
52737
  try {
@@ -51671,7 +52775,7 @@ var ReArmingContentWatcher = class extends import_node_events.EventEmitter {
51671
52775
  });
51672
52776
  const ancestorWatchers = [];
51673
52777
  for (const ancestorDir of this.#ancestorDirs()) {
51674
- 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));
51675
52779
  try {
51676
52780
  const ancestorWatcher = fs3.watch(ancestorDir, (_event, filename) => {
51677
52781
  const basename = filename?.toString();
@@ -51717,10 +52821,10 @@ var ReArmingContentWatcher = class extends import_node_events.EventEmitter {
51717
52821
  }
51718
52822
  #ancestorDirs() {
51719
52823
  const ancestors = [];
51720
- let current = import_node_path8.default.dirname(this.#dir);
51721
- 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)) {
51722
52826
  ancestors.push(current);
51723
- current = import_node_path8.default.dirname(current);
52827
+ current = import_node_path12.default.dirname(current);
51724
52828
  }
51725
52829
  return ancestors;
51726
52830
  }
@@ -51776,54 +52880,27 @@ var defaultWatchContentFile = (filePath, onChange, basenames, options) => {
51776
52880
  return new ReArmingContentWatcher(filePath, onChange, basenames, options);
51777
52881
  };
51778
52882
 
51779
- // ../server/src/artifact-paths.ts
51780
- var import_node_path9 = __toESM(require("node:path"), 1);
51781
- function getStateDir(storagePath) {
51782
- return import_node_path9.default.join(storagePath, "state");
51783
- }
51784
- function getScreensDir(storagePath) {
51785
- return import_node_path9.default.join(getStateDir(storagePath), "screens");
51786
- }
51787
- function getArtifactsMetadataDir(storagePath) {
51788
- return import_node_path9.default.join(getStateDir(storagePath), "artifacts");
51789
- }
51790
- function getDisplayStatePath(storagePath) {
51791
- return import_node_path9.default.join(getStateDir(storagePath), "display.json");
51792
- }
51793
- function getTokenPath(storagePath) {
51794
- return import_node_path9.default.join(getStateDir(storagePath), "token");
51795
- }
51796
- function getOnboardingArtifactSentinelPath(storagePath) {
51797
- return import_node_path9.default.join(getStateDir(storagePath), "onboarding-artifact.json");
51798
- }
51799
- function getAgentArtifactsDir(storagePath) {
51800
- return import_node_path9.default.join(...[storagePath, "artifacts"]);
51801
- }
51802
- function getArtifactLiveMetadataPath(storagePath, artifactID) {
51803
- return import_node_path9.default.join(getArtifactsMetadataDir(storagePath), `${artifactID}.json`);
51804
- }
51805
-
51806
52883
  // ../server/src/onboarding.ts
51807
- var import_node_fs8 = require("node:fs");
51808
- var import_node_path10 = __toESM(require("node:path"), 1);
51809
- var import_node_url = require("node:url");
51810
- 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 = {};
51811
52888
  var ONBOARDING_ARTIFACT_ID = "television-onboarding";
51812
52889
  var ONBOARDING_SCREEN_NAME = "TV Guide";
51813
52890
  var ONBOARDING_ARTIFACT_TITLE = "Welcome to Television";
51814
52891
  var ONBOARDING_ARTIFACT_DIRNAME = "television-onboarding";
51815
52892
  var ONBOARDING_ARTIFACT_SENTINEL_VERSION = 1;
51816
52893
  function getDefaultOnboardingArtifactSourcePath() {
51817
- const moduleURL = import_meta.url;
52894
+ const moduleURL = import_meta2.url;
51818
52895
  if (typeof moduleURL !== "string") {
51819
52896
  return void 0;
51820
52897
  }
51821
- const sourcePath = import_node_path10.default.resolve(
51822
- 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)),
51823
52900
  "../assets",
51824
52901
  ONBOARDING_ARTIFACT_DIRNAME
51825
52902
  );
51826
- return (0, import_node_fs8.existsSync)(sourcePath) ? sourcePath : void 0;
52903
+ return (0, import_node_fs10.existsSync)(sourcePath) ? sourcePath : void 0;
51827
52904
  }
51828
52905
 
51829
52906
  // ../server/src/server-store.ts
@@ -51835,6 +52912,17 @@ var BUNDLED_VIEW_IDS = /* @__PURE__ */ new Set(["artifact-missing", "markdown"])
51835
52912
  function isBundledViewID(id) {
51836
52913
  return BUNDLED_VIEW_IDS.has(id);
51837
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
+ }
51838
52926
  function artifactWatchTarget(artifact) {
51839
52927
  if (artifact.kind === "url") {
51840
52928
  return null;
@@ -51850,6 +52938,7 @@ function artifactWatchTarget(artifact) {
51850
52938
  var ServerStore = class extends EventTarget {
51851
52939
  storagePath;
51852
52940
  authToken;
52941
+ dataDirCreated;
51853
52942
  screens = /* @__PURE__ */ new Map();
51854
52943
  activeScreenID = null;
51855
52944
  activeThemeName = null;
@@ -51863,9 +52952,11 @@ var ServerStore = class extends EventTarget {
51863
52952
  watchContentFile;
51864
52953
  bundledViewsPath;
51865
52954
  onboardingArtifactSourcePath;
52955
+ telemetryHooks = null;
51866
52956
  constructor(options) {
51867
52957
  super();
51868
52958
  this.storagePath = options.storagePath;
52959
+ this.dataDirCreated = !hasExistingTelevisionDataStructure(options.storagePath);
51869
52960
  this.watchContentFile = options.watchContentFile ?? defaultWatchContentFile;
51870
52961
  this.bundledViewsPath = options.bundledViewsPath;
51871
52962
  this.onboardingArtifactSourcePath = options.onboardingArtifactSourcePath ?? getDefaultOnboardingArtifactSourcePath();
@@ -51887,6 +52978,9 @@ var ServerStore = class extends EventTarget {
51887
52978
  }
51888
52979
  this.startWatchingActiveTheme();
51889
52980
  }
52981
+ setTelemetryHooks(hooks) {
52982
+ this.telemetryHooks = hooks;
52983
+ }
51890
52984
  getViews() {
51891
52985
  return [];
51892
52986
  }
@@ -51894,8 +52988,8 @@ var ServerStore = class extends EventTarget {
51894
52988
  if (!isBundledViewID(id) || this.bundledViewsPath === void 0) {
51895
52989
  return null;
51896
52990
  }
51897
- const viewPath = import_node_path11.default.join(this.bundledViewsPath, id);
51898
- 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;
51899
52993
  }
51900
52994
  getScreen(id) {
51901
52995
  const screen = this.screens.get(id);
@@ -51917,7 +53011,7 @@ var ServerStore = class extends EventTarget {
51917
53011
  return [...this._artifacts.values()];
51918
53012
  }
51919
53013
  /** Create a new artifact and append its card to the owning screen. */
51920
- createArtifact(input) {
53014
+ createArtifact(input, telemetryContext) {
51921
53015
  const screen = this.requireScreen(input.screenID);
51922
53016
  const artifact = this.createKindArtifact(input);
51923
53017
  const previousLayout = screen.layout;
@@ -51927,16 +53021,17 @@ var ServerStore = class extends EventTarget {
51927
53021
  this.persistScreen(screen);
51928
53022
  } catch (error48) {
51929
53023
  screen.layout = previousLayout;
51930
- (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 });
51931
53025
  throw error48;
51932
53026
  }
51933
53027
  this._artifacts.set(artifact.id, artifact);
51934
53028
  this.artifactScreens.set(artifact.id, screen.id);
51935
53029
  this.startWatchingArtifactContent(artifact);
51936
53030
  this.dispatchEvent(new ArtifactCreatedEvent("artifact-created", { screenID: screen.id, artifact }));
53031
+ this.emitTelemetry((hooks) => hooks.artifactCreated(artifact, telemetryContext));
51937
53032
  return artifact;
51938
53033
  }
51939
- updateArtifact(input) {
53034
+ updateArtifact(input, telemetryContext) {
51940
53035
  const artifact = this._artifacts.get(input.artifactID);
51941
53036
  if (!artifact) {
51942
53037
  throw new NotFoundError(`Artifact not found: ${input.artifactID}`, { entityType: "artifact", entityID: input.artifactID });
@@ -51978,6 +53073,7 @@ var ServerStore = class extends EventTarget {
51978
53073
  this.scheduleArtifactContentChangedEvent(updated.id);
51979
53074
  }
51980
53075
  this.dispatchEvent(new ArtifactUpdatedEvent("artifact-updated", { artifact: updated }));
53076
+ this.emitTelemetry((hooks) => hooks.artifactUpdated(updated, telemetryContext));
51981
53077
  return updated;
51982
53078
  }
51983
53079
  /**
@@ -51986,7 +53082,7 @@ var ServerStore = class extends EventTarget {
51986
53082
  *
51987
53083
  * Throws `NotFoundError` when the artifact does not exist.
51988
53084
  */
51989
- deleteArtifact(artifactID) {
53085
+ deleteArtifact(artifactID, telemetryContext) {
51990
53086
  const artifact = this._artifacts.get(artifactID);
51991
53087
  if (!artifact) {
51992
53088
  throw new NotFoundError(`Artifact not found: ${artifactID}`, { entityType: "artifact", entityID: artifactID });
@@ -52006,13 +53102,14 @@ var ServerStore = class extends EventTarget {
52006
53102
  }
52007
53103
  this.stopWatchingArtifactContent(artifactID);
52008
53104
  this._artifacts.delete(artifactID);
52009
- (0, import_node_fs9.rmSync)(getArtifactLiveMetadataPath(this.storagePath, artifactID), { force: true });
53105
+ (0, import_node_fs11.rmSync)(getArtifactLiveMetadataPath(this.storagePath, artifactID), { force: true });
52010
53106
  if (screenID !== void 0) {
52011
53107
  this.dispatchEvent(new ArtifactRemovedEvent("artifact-removed", { artifactID, screenID }));
52012
53108
  }
53109
+ this.emitTelemetry((hooks) => hooks.artifactDeleted(artifact, telemetryContext));
52013
53110
  return artifact.kind === "path" ? { outcome: "deleted", kind: "path", artifactID, path: artifact.path } : { outcome: "deleted", kind: "url", artifactID, url: artifact.url };
52014
53111
  }
52015
- createScreen(input) {
53112
+ createScreen(input, telemetryContext) {
52016
53113
  const screen = {
52017
53114
  id: input.id ?? ulid3(),
52018
53115
  name: input.name,
@@ -52021,9 +53118,10 @@ var ServerStore = class extends EventTarget {
52021
53118
  this.screens.set(screen.id, screen);
52022
53119
  this.persistScreen(screen);
52023
53120
  this.dispatchEvent(new ScreenCreatedEvent("screen-created", { screen }));
53121
+ this.emitTelemetry((hooks) => hooks.screenCreated(screen, telemetryContext));
52024
53122
  return screen;
52025
53123
  }
52026
- updateScreen(input) {
53124
+ updateScreen(input, telemetryContext) {
52027
53125
  const screen = this.requireScreen(input.screenID);
52028
53126
  if (typeof input.fields.name === "string") {
52029
53127
  screen.name = input.fields.name;
@@ -52041,10 +53139,12 @@ var ServerStore = class extends EventTarget {
52041
53139
  }
52042
53140
  this.rebuildArtifactScreensForScreen(screen);
52043
53141
  this.dispatchEvent(new ScreenUpdatedEvent("screen-updated", { screen }));
53142
+ this.emitTelemetry((hooks) => hooks.screenLayoutChanged(previousLayout, screen.layout, telemetryContext));
52044
53143
  return screen;
52045
53144
  }
52046
53145
  this.persistScreen(screen);
52047
53146
  this.dispatchEvent(new ScreenUpdatedEvent("screen-updated", { screen }));
53147
+ this.emitTelemetry((hooks) => hooks.screenUpdated(screen, telemetryContext));
52048
53148
  return screen;
52049
53149
  }
52050
53150
  /** The screen that Television's GUI is currently focused on. */
@@ -52060,7 +53160,7 @@ var ServerStore = class extends EventTarget {
52060
53160
  activeThemeName: this.activeThemeName
52061
53161
  };
52062
53162
  }
52063
- patchDisplay(input) {
53163
+ patchDisplay(input, telemetryContext) {
52064
53164
  const currentActiveScreenID = this.getActiveScreenID();
52065
53165
  let nextActiveScreenID = this.activeScreenID;
52066
53166
  let nextActiveThemeName = this.activeThemeName;
@@ -52104,6 +53204,7 @@ var ServerStore = class extends EventTarget {
52104
53204
  this.dispatchEvent(
52105
53205
  new ThemeChangedEvent("theme-changed", { themeName: this.activeThemeName })
52106
53206
  );
53207
+ this.emitTelemetry((hooks) => hooks.themeChanged(telemetryContext));
52107
53208
  }
52108
53209
  }
52109
53210
  /**
@@ -52133,15 +53234,16 @@ var ServerStore = class extends EventTarget {
52133
53234
  );
52134
53235
  return { screenID: target, artifactID: input.artifactID };
52135
53236
  }
52136
- removeScreen(screenID) {
53237
+ removeScreen(screenID, telemetryContext) {
52137
53238
  const screen = this.requireScreen(screenID);
52138
53239
  const previousActiveScreenID = this.getActiveScreenID();
52139
53240
  const artifactIDs = [...new Set(getScreenArtifactIDs(screen))];
52140
- const artifactResults = artifactIDs.map((artifactID) => this.deleteArtifact(artifactID));
52141
- const metadataPath = import_node_path11.default.join(this.screensDir, `${screen.id}.json`);
52142
- (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 });
52143
53244
  this.screens.delete(screen.id);
52144
53245
  this.dispatchEvent(new ScreenRemovedEvent("screen-removed", { screenID }));
53246
+ this.emitTelemetry((hooks) => hooks.screenDeleted(screen, telemetryContext));
52145
53247
  const nextActiveScreenID = this.getActiveScreenID();
52146
53248
  if (previousActiveScreenID !== nextActiveScreenID) {
52147
53249
  this.dispatchEvent(
@@ -52157,14 +53259,21 @@ var ServerStore = class extends EventTarget {
52157
53259
  [Symbol.dispose]() {
52158
53260
  this.dispose();
52159
53261
  }
53262
+ emitTelemetry(callback) {
53263
+ if (!this.telemetryHooks) return;
53264
+ try {
53265
+ callback(this.telemetryHooks);
53266
+ } catch {
53267
+ }
53268
+ }
52160
53269
  load() {
52161
- if ((0, import_node_fs9.existsSync)(this.screensDir)) {
52162
- 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)) {
52163
53272
  if (!file2.endsWith(JSON_FILE_SUFFIX)) continue;
52164
- const filePath = import_node_path11.default.join(this.screensDir, file2);
53273
+ const filePath = import_node_path14.default.join(this.screensDir, file2);
52165
53274
  let raw;
52166
53275
  try {
52167
- raw = JSON.parse((0, import_node_fs9.readFileSync)(filePath, "utf8"));
53276
+ raw = JSON.parse((0, import_node_fs11.readFileSync)(filePath, "utf8"));
52168
53277
  } catch (error48) {
52169
53278
  console.warn(`Skipping malformed JSON file: ${filePath}`, error48);
52170
53279
  continue;
@@ -52180,15 +53289,15 @@ var ServerStore = class extends EventTarget {
52180
53289
  });
52181
53290
  }
52182
53291
  }
52183
- if (!(0, import_node_fs9.existsSync)(this.artifactsDir)) {
53292
+ if (!(0, import_node_fs11.existsSync)(this.artifactsDir)) {
52184
53293
  return;
52185
53294
  }
52186
- for (const file2 of (0, import_node_fs9.readdirSync)(this.artifactsDir)) {
53295
+ for (const file2 of (0, import_node_fs11.readdirSync)(this.artifactsDir)) {
52187
53296
  if (!file2.endsWith(JSON_FILE_SUFFIX)) {
52188
53297
  continue;
52189
53298
  }
52190
53299
  const id = file2.slice(0, -JSON_FILE_SUFFIX.length);
52191
- const metadataPath = import_node_path11.default.join(this.artifactsDir, file2);
53300
+ const metadataPath = import_node_path14.default.join(this.artifactsDir, file2);
52192
53301
  const metadata = this.readArtifactFile(metadataPath, id);
52193
53302
  this._artifacts.set(id, metadata);
52194
53303
  this.startWatchingArtifactContent(metadata);
@@ -52357,20 +53466,20 @@ var ServerStore = class extends EventTarget {
52357
53466
  * without statting.
52358
53467
  */
52359
53468
  normalizeArtifactPath(artifactPath) {
52360
- if (!import_node_path11.default.isAbsolute(artifactPath)) {
53469
+ if (!import_node_path14.default.isAbsolute(artifactPath)) {
52361
53470
  throw new InvalidRequestError("path must be absolute");
52362
53471
  }
52363
53472
  const stripped = stripTrailingSeparators(artifactPath);
52364
53473
  let stat;
52365
53474
  try {
52366
- (0, import_node_fs9.accessSync)(stripped, import_node_fs9.constants.R_OK);
52367
- 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);
52368
53477
  } catch {
52369
53478
  throw new InvalidRequestError(`path does not exist or is not readable: ${artifactPath}`);
52370
53479
  }
52371
53480
  if (stat.isDirectory()) {
52372
- const canonical = hasTrailingSeparator(stripped) ? stripped : `${stripped}${import_node_path11.default.sep}`;
52373
- 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)))) {
52374
53483
  throw new InvalidRequestError(`directory artifact must contain index.html or index.htm: ${canonical}`);
52375
53484
  }
52376
53485
  return canonical;
@@ -52384,11 +53493,11 @@ var ServerStore = class extends EventTarget {
52384
53493
  return stripped;
52385
53494
  }
52386
53495
  canInstallOnboardingArtifact() {
52387
- 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;
52388
53497
  }
52389
53498
  installOnboardingArtifactIfNeeded() {
52390
53499
  try {
52391
- if ((0, import_node_fs9.existsSync)(getOnboardingArtifactSentinelPath(this.storagePath))) {
53500
+ if ((0, import_node_fs11.existsSync)(getOnboardingArtifactSentinelPath(this.storagePath))) {
52392
53501
  return;
52393
53502
  }
52394
53503
  if (this._artifacts.has(ONBOARDING_ARTIFACT_ID)) {
@@ -52400,9 +53509,9 @@ var ServerStore = class extends EventTarget {
52400
53509
  return;
52401
53510
  }
52402
53511
  const screenID = this.resolveActiveScreenID(this.activeScreenID) ?? this.pickPreferredScreenID();
52403
- const onboardingPath = import_node_path11.default.join(getAgentArtifactsDir(this.storagePath), ONBOARDING_ARTIFACT_DIRNAME) + import_node_path11.default.sep;
52404
- if (!(0, import_node_fs9.existsSync)(onboardingPath)) {
52405
- (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 });
52406
53515
  }
52407
53516
  this.createArtifact({
52408
53517
  id: ONBOARDING_ARTIFACT_ID,
@@ -52418,7 +53527,7 @@ var ServerStore = class extends EventTarget {
52418
53527
  }
52419
53528
  }
52420
53529
  writeOnboardingArtifactSentinel() {
52421
- (0, import_node_fs9.writeFileSync)(
53530
+ (0, import_node_fs11.writeFileSync)(
52422
53531
  getOnboardingArtifactSentinelPath(this.storagePath),
52423
53532
  JSON.stringify({
52424
53533
  version: ONBOARDING_ARTIFACT_SENTINEL_VERSION,
@@ -52436,11 +53545,11 @@ var ServerStore = class extends EventTarget {
52436
53545
  this.persistDisplayState();
52437
53546
  }
52438
53547
  ensureDirectories() {
52439
- (0, import_node_fs9.mkdirSync)(import_node_path11.default.join(this.storagePath, "state"), { recursive: true });
52440
- (0, import_node_fs9.mkdirSync)(this.screensDir, { recursive: true });
52441
- (0, import_node_fs9.mkdirSync)(this.artifactsDir, { recursive: true });
52442
- (0, import_node_fs9.mkdirSync)(getThemesDir(this.storagePath), { recursive: true });
52443
- (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 });
52444
53553
  }
52445
53554
  rebuildArtifactScreens() {
52446
53555
  this.artifactScreens.clear();
@@ -52459,12 +53568,12 @@ var ServerStore = class extends EventTarget {
52459
53568
  }
52460
53569
  }
52461
53570
  loadDisplayState() {
52462
- if (!(0, import_node_fs9.existsSync)(this.displayStatePath)) {
53571
+ if (!(0, import_node_fs11.existsSync)(this.displayStatePath)) {
52463
53572
  return false;
52464
53573
  }
52465
53574
  let raw;
52466
53575
  try {
52467
- raw = (0, import_node_fs9.readFileSync)(this.displayStatePath, "utf8");
53576
+ raw = (0, import_node_fs11.readFileSync)(this.displayStatePath, "utf8");
52468
53577
  } catch {
52469
53578
  return false;
52470
53579
  }
@@ -52482,7 +53591,7 @@ var ServerStore = class extends EventTarget {
52482
53591
  return false;
52483
53592
  }
52484
53593
  persistDisplayState() {
52485
- (0, import_node_fs9.writeFileSync)(
53594
+ (0, import_node_fs11.writeFileSync)(
52486
53595
  this.displayStatePath,
52487
53596
  JSON.stringify(this.getDisplayState(), null, JSON_INDENT_SPACES)
52488
53597
  );
@@ -52504,11 +53613,11 @@ var ServerStore = class extends EventTarget {
52504
53613
  return firstScreen.id;
52505
53614
  }
52506
53615
  loadOrCreateAuthToken() {
52507
- if ((0, import_node_fs9.existsSync)(this.tokenPath)) {
52508
- 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();
52509
53618
  }
52510
53619
  const token = createToken();
52511
- (0, import_node_fs9.writeFileSync)(this.tokenPath, `${token}
53620
+ (0, import_node_fs11.writeFileSync)(this.tokenPath, `${token}
52512
53621
  `);
52513
53622
  return token;
52514
53623
  }
@@ -52516,12 +53625,12 @@ var ServerStore = class extends EventTarget {
52516
53625
  if (!this.screens.has(screen.id)) {
52517
53626
  throw new Error(`Cannot persist screen ${screen.id}: not in live map`);
52518
53627
  }
52519
- (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));
52520
53629
  }
52521
53630
  readArtifactFile(filePath, expectedID) {
52522
53631
  let raw;
52523
53632
  try {
52524
- raw = (0, import_node_fs9.readFileSync)(filePath, "utf8");
53633
+ raw = (0, import_node_fs11.readFileSync)(filePath, "utf8");
52525
53634
  } catch (error48) {
52526
53635
  throw this.invalidMetadataFile(filePath, "unreadable", error48);
52527
53636
  }
@@ -52543,7 +53652,7 @@ var ServerStore = class extends EventTarget {
52543
53652
  `id ${result.data.id} does not match filename ${expectedID}`
52544
53653
  );
52545
53654
  }
52546
- 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)) {
52547
53656
  throw this.invalidMetadataFile(filePath, "path must be absolute");
52548
53657
  }
52549
53658
  return result.data;
@@ -52560,7 +53669,7 @@ Review docs/storage.md for the current schema, and either update the file to mat
52560
53669
  return cause !== void 0 ? new Error(message, { cause }) : new Error(message);
52561
53670
  }
52562
53671
  writeArtifact(artifact) {
52563
- (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));
52564
53673
  }
52565
53674
  get screensDir() {
52566
53675
  return getScreensDir(this.storagePath);
@@ -52596,8 +53705,10 @@ function collectLayoutArtifactIDs(node) {
52596
53705
  }
52597
53706
 
52598
53707
  // src/index.ts
52599
- var import_meta2 = {};
53708
+ var import_meta3 = {};
52600
53709
  var DAEMON_NAME = "com.television.server";
53710
+ var TELEMETRY_LAUNCH_MODE_ENV = "TELEVISION_LAUNCH_MODE";
53711
+ var SKILL_INSTALL_TELEMETRY_TIMEOUT_MS2 = 1e3;
52601
53712
  var MAX_PORT = 65535;
52602
53713
  var HTTP_UNAUTHORIZED_STATUS2 = 401;
52603
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`.";
@@ -52623,6 +53734,23 @@ function writeConnectURLs(output, urls, options = {}) {
52623
53734
  writeLine(output, ` ${terminalHyperlink(connectURL)}`);
52624
53735
  }
52625
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
+ }
52626
53754
  function ensureHelpPointer(message) {
52627
53755
  return message.includes(HELP_POINTER) ? message : `${message}
52628
53756
  ${HELP_POINTER}`;
@@ -52631,24 +53759,36 @@ function createDirectiveError(message) {
52631
53759
  return new CLIDirectiveError(ensureHelpPointer(message));
52632
53760
  }
52633
53761
  function getDevPackageDir() {
52634
- 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)), "..");
52635
53763
  }
52636
53764
  function resolveVercelSkillsInstallerBin() {
52637
53765
  if (typeof require === "function" && typeof require.resolve === "function") {
52638
53766
  return require.resolve("skills/bin/cli.mjs");
52639
53767
  }
52640
- 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"));
52641
53769
  return localRequire.resolve("skills/bin/cli.mjs");
52642
53770
  }
52643
53771
  function readCLIVersion() {
52644
- if ("0.1.170".length > 0) {
52645
- return "0.1.170";
53772
+ if ("0.1.172".length > 0) {
53773
+ return "0.1.172";
52646
53774
  }
52647
- const devPackageJsonPath = import_node_path12.default.join(getDevPackageDir(), "package.json");
52648
- 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)) {
52649
53777
  throw new Error("Could not resolve package.json for repo-local CLI version.");
52650
53778
  }
52651
- 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
+ };
52652
53792
  }
52653
53793
  var FRONTMATTER_DELIMITER = "---\n";
52654
53794
  var FRONTMATTER_DELIMITER_LENGTH = FRONTMATTER_DELIMITER.length;
@@ -52701,7 +53841,7 @@ function formatCLIError(error48, argv = []) {
52701
53841
  const status = typeof error48.status === "number" ? Number(error48.status) : void 0;
52702
53842
  if (status === HTTP_UNAUTHORIZED_STATUS2) {
52703
53843
  return ensureHelpPointer(
52704
- `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")}.`
52705
53845
  );
52706
53846
  }
52707
53847
  if (status !== void 0) {
@@ -52744,63 +53884,63 @@ function resolveStaticDir() {
52744
53884
  if (!process.argv[1]) {
52745
53885
  return void 0;
52746
53886
  }
52747
- const entryDir = import_node_path12.default.dirname((0, import_node_fs10.realpathSync)(process.argv[1]));
52748
- const resolved = import_node_path12.default.resolve(entryDir, "./web");
52749
- 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;
52750
53890
  }
52751
53891
  function resolveBundledViewsPath() {
52752
53892
  if (process.argv[1]) {
52753
- const entryDir = import_node_path12.default.dirname((0, import_node_fs10.realpathSync)(process.argv[1]));
52754
- const resolved = import_node_path12.default.resolve(entryDir, "./views");
52755
- 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;
52756
53896
  }
52757
- const devViewsPath = import_node_path12.default.join(getDevPackageDir(), "dist/views");
52758
- 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;
52759
53899
  }
52760
53900
  function resolveCanonicalDir() {
52761
53901
  if (process.argv[1]) {
52762
- const entryDir = import_node_path12.default.dirname((0, import_node_fs10.realpathSync)(process.argv[1]));
52763
- const resolved = import_node_path12.default.resolve(entryDir, "./canonical/v1");
52764
- 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;
52765
53905
  }
52766
- const devCanonicalPath = import_node_path12.default.resolve(
53906
+ const devCanonicalPath = import_node_path15.default.resolve(
52767
53907
  getDevPackageDir(),
52768
53908
  "../server/dist/canonical/v1"
52769
53909
  );
52770
- return (0, import_node_fs10.existsSync)(devCanonicalPath) ? devCanonicalPath : void 0;
53910
+ return (0, import_node_fs12.existsSync)(devCanonicalPath) ? devCanonicalPath : void 0;
52771
53911
  }
52772
53912
  function resolveOnboardingArtifactSourcePath() {
52773
53913
  if (process.argv[1]) {
52774
- const entryDir = import_node_path12.default.dirname((0, import_node_fs10.realpathSync)(process.argv[1]));
52775
- const resolved = import_node_path12.default.resolve(entryDir, "./onboarding/television-onboarding");
52776
- 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;
52777
53917
  }
52778
- const devPath = import_node_path12.default.resolve(
53918
+ const devPath = import_node_path15.default.resolve(
52779
53919
  getDevPackageDir(),
52780
53920
  "../server/assets/television-onboarding"
52781
53921
  );
52782
- return (0, import_node_fs10.existsSync)(devPath) ? devPath : void 0;
53922
+ return (0, import_node_fs12.existsSync)(devPath) ? devPath : void 0;
52783
53923
  }
52784
53924
  function resolveBundledSkillsRoot() {
52785
- 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;
52786
- 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)) {
52787
53927
  return builtPath;
52788
53928
  }
52789
- const devPath = import_node_path12.default.resolve(getDevPackageDir(), "../skills/dist");
52790
- 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;
52791
53931
  }
52792
53932
  function copyBundledSkillsToDestination(bundledSkillsRoot, destinationRoot) {
52793
- 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()) {
52794
53934
  throw new Error(`Skills destination is not a directory: ${destinationRoot}`);
52795
53935
  }
52796
- (0, import_node_fs10.mkdirSync)(destinationRoot, { recursive: true });
53936
+ (0, import_node_fs12.mkdirSync)(destinationRoot, { recursive: true });
52797
53937
  const copied = [];
52798
- 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));
52799
53939
  for (const entry of entries) {
52800
- const sourcePath = import_node_path12.default.join(bundledSkillsRoot, entry.name);
52801
- const destinationPath = import_node_path12.default.join(destinationRoot, entry.name);
52802
- (0, import_node_fs10.rmSync)(destinationPath, { recursive: true, force: true });
52803
- (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 });
52804
53944
  copied.push({ name: entry.name, sourcePath, destinationPath });
52805
53945
  }
52806
53946
  return copied;
@@ -52882,11 +54022,11 @@ function formatCommanderError(argv, error48) {
52882
54022
  return null;
52883
54023
  }
52884
54024
  function readAuthToken(storagePath) {
52885
- const tokenPath = import_node_path12.default.join(storagePath, "state", "token");
52886
- 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)) {
52887
54027
  return void 0;
52888
54028
  }
52889
- const token = (0, import_node_fs10.readFileSync)(tokenPath, "utf8").trim();
54029
+ const token = (0, import_node_fs12.readFileSync)(tokenPath, "utf8").trim();
52890
54030
  return token.length > 0 ? token : void 0;
52891
54031
  }
52892
54032
  function readOrCreateAuthToken(storagePath) {
@@ -52904,6 +54044,7 @@ function buildDaemonServeArgs(options = {}) {
52904
54044
  if (options.auth === false) args.push("--no-auth");
52905
54045
  if (options.port !== void 0) args.push("--port", String(options.port));
52906
54046
  if (options.storagePath) args.push("--storage-path", options.storagePath);
54047
+ if (options.installedByAgent) args.push("--installed-by-agent", options.installedByAgent);
52907
54048
  return args;
52908
54049
  }
52909
54050
  function redactSensitiveEnv(env) {
@@ -52913,6 +54054,9 @@ function redactSensitiveEnv(env) {
52913
54054
  }
52914
54055
  return redacted;
52915
54056
  }
54057
+ function resolveTelemetryLaunchMode(env) {
54058
+ return env[TELEMETRY_LAUNCH_MODE_ENV] === "daemon" ? "daemon" : "cli";
54059
+ }
52916
54060
  function isSensitiveEnvKey(key) {
52917
54061
  const normalized = key.toUpperCase();
52918
54062
  return normalized.startsWith("OPENCLAW_") || normalized.startsWith("HERMES_") || normalized.endsWith("_API_KEY") || normalized.endsWith("_TOKEN") || normalized.endsWith("_SECRET") || normalized.endsWith("_PASSWORD");
@@ -52934,7 +54078,11 @@ function createEnvironment(environment) {
52934
54078
  auth: options.auth,
52935
54079
  staticDir: options.staticDir,
52936
54080
  canonicalDir: options.canonicalDir,
52937
- acpProfile: options.acpProfile
54081
+ acpProfile: options.acpProfile,
54082
+ telemetry: {
54083
+ launchMode: options.launchMode ?? "cli",
54084
+ installedByAgent: options.installedByAgent ?? null
54085
+ }
52938
54086
  })),
52939
54087
  createDaemon: environment.createDaemon ?? ((options = {}) => {
52940
54088
  const args = buildDaemonServeArgs(options);
@@ -52951,6 +54099,7 @@ function createEnvironment(environment) {
52951
54099
  resolveBundledViewsPath: environment.resolveBundledViewsPath ?? (() => resolveBundledViewsPath()),
52952
54100
  resolveOnboardingArtifactSourcePath: environment.resolveOnboardingArtifactSourcePath ?? (() => resolveOnboardingArtifactSourcePath()),
52953
54101
  resolveBundledSkillsRoot: environment.resolveBundledSkillsRoot ?? (() => resolveBundledSkillsRoot()),
54102
+ resolveHomeDir: environment.resolveHomeDir ?? (() => import_node_os5.default.homedir()),
52954
54103
  runSkillsInstaller: environment.runSkillsInstaller ?? (async (args) => {
52955
54104
  const vercelSkillsInstallerBin = resolveVercelSkillsInstallerBin();
52956
54105
  const result = (0, import_node_child_process3.spawnSync)(process.execPath, [vercelSkillsInstallerBin, ...args], { stdio: "inherit" });
@@ -52958,6 +54107,7 @@ function createEnvironment(environment) {
52958
54107
  throw new Error(`skills ${args.join(" ")} failed (exit ${result.status ?? "signal"})`);
52959
54108
  }
52960
54109
  }),
54110
+ emitSkillInstalledTelemetry: environment.emitSkillInstalledTelemetry ?? ((options) => emitSkillInstalledTelemetry(options)),
52961
54111
  onSignal: environment.onSignal ?? ((signal, handler) => process.on(signal, handler))
52962
54112
  };
52963
54113
  }
@@ -52972,6 +54122,15 @@ function createProgram(env, argv = []) {
52972
54122
  readAuthToken(resolveClientStoragePath(options.storagePath))
52973
54123
  );
52974
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
+ };
52975
54134
  const uninstallPersistedService = async (storagePath) => {
52976
54135
  const daemon = env.createDaemon();
52977
54136
  let outcome = "uninstalled";
@@ -52991,7 +54150,7 @@ function createProgram(env, argv = []) {
52991
54150
  outputError: () => {
52992
54151
  }
52993
54152
  }).exitOverride();
52994
- 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) => {
52995
54154
  if (opts.persist && opts.persistUninstall) {
52996
54155
  throw createDirectiveError("Use either `--persist` or `--persist-uninstall`, not both.");
52997
54156
  }
@@ -53011,9 +54170,10 @@ function createProgram(env, argv = []) {
53011
54170
  if (opts.persist) {
53012
54171
  const storagePath = opts.storagePath ?? getTelevisionStoragePath();
53013
54172
  const profile2 = resolveACPAgentProfile(process.env);
53014
- const daemonEnv = buildPersistedACPEnvironment(process.env);
54173
+ const daemonEnv = buildPersistedACPEnvironment(process.env, { developerHome: env.resolveHomeDir() });
53015
54174
  if (process.env.TELEVISION_PORT !== void 0) daemonEnv.TELEVISION_PORT = process.env.TELEVISION_PORT;
53016
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";
53017
54177
  if (profile2 && !isACPCommandResolvable(profile2.command, daemonEnv)) {
53018
54178
  const error48 = createDirectiveError(
53019
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\`.`
@@ -53026,6 +54186,7 @@ function createProgram(env, argv = []) {
53026
54186
  auth,
53027
54187
  port: opts.port,
53028
54188
  storagePath,
54189
+ ...opts.installedByAgent === void 0 ? {} : { installedByAgent: opts.installedByAgent },
53029
54190
  env: daemonEnv
53030
54191
  };
53031
54192
  const daemon = env.createDaemon(daemonOptions);
@@ -53052,8 +54213,9 @@ function createProgram(env, argv = []) {
53052
54213
  });
53053
54214
  throw error48;
53054
54215
  }
53055
- const serverURL = buildLocalServerURL(opts.port);
53056
- 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, {
53057
54219
  installed: true,
53058
54220
  token: auth === true ? readOrCreateAuthToken(storagePath) : null
53059
54221
  });
@@ -53076,6 +54238,8 @@ function createProgram(env, argv = []) {
53076
54238
  canonicalDir: env.resolveCanonicalDir(),
53077
54239
  bundledViewsPath: env.resolveBundledViewsPath(),
53078
54240
  onboardingArtifactSourcePath: env.resolveOnboardingArtifactSourcePath(),
54241
+ launchMode: resolveTelemetryLaunchMode(process.env),
54242
+ ...opts.installedByAgent === void 0 ? {} : { installedByAgent: opts.installedByAgent },
53079
54243
  ...profile ? { acpProfile: profile } : {}
53080
54244
  });
53081
54245
  await server.start();
@@ -53252,7 +54416,7 @@ function createProgram(env, argv = []) {
53252
54416
  "Examples: ~/.openclaw/skills, ~/.hermes/skills, ~/.agents/skills.",
53253
54417
  "`tv skills install -i` runs the external skills installer against Television's bundled skills root."
53254
54418
  ].join("\n"));
53255
- 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) {
53256
54420
  const bundledTelevisionSkillsCollectionRoot = env.resolveBundledSkillsRoot();
53257
54421
  if (opts.interactive) {
53258
54422
  if (inputPath) {
@@ -53263,6 +54427,10 @@ function createProgram(env, argv = []) {
53263
54427
  }
53264
54428
  const args = ["add", bundledTelevisionSkillsCollectionRoot];
53265
54429
  await env.runSkillsInstaller(args);
54430
+ await emitSkillInstallTelemetry({
54431
+ agentType: "interactive-install",
54432
+ ...opts.installedByAgent === void 0 ? {} : { installedByAgent: opts.installedByAgent }
54433
+ });
53266
54434
  return;
53267
54435
  }
53268
54436
  if (!inputPath) {
@@ -53273,7 +54441,7 @@ function createProgram(env, argv = []) {
53273
54441
  if (!bundledTelevisionSkillsCollectionRoot) {
53274
54442
  throw new Error("Could not resolve the bundled Television skills root.");
53275
54443
  }
53276
- const destinationRoot = import_node_path12.default.resolve(inputPath);
54444
+ const destinationRoot = import_node_path15.default.resolve(inputPath);
53277
54445
  const copied = copyBundledSkillsToDestination(bundledTelevisionSkillsCollectionRoot, destinationRoot);
53278
54446
  writeLine(env.stdout, `Copied ${copied.length} bundled Television skill(s):`);
53279
54447
  for (const skill of copied) {
@@ -53281,6 +54449,19 @@ function createProgram(env, argv = []) {
53281
54449
  writeLine(env.stdout, ` from: ${skill.sourcePath}`);
53282
54450
  writeLine(env.stdout, ` to: ${skill.destinationPath}`);
53283
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());
53284
54465
  });
53285
54466
  program2.command("stop").description("Stop the Television system service").action(async () => {
53286
54467
  await uninstallPersistedService(getTelevisionStoragePath());
@@ -53297,6 +54478,7 @@ function createProgram(env, argv = []) {
53297
54478
  result.healthy = true;
53298
54479
  result.bindAddresses = health.bindAddresses;
53299
54480
  result.port = health.port;
54481
+ result.telemetry = await client.telemetry.status();
53300
54482
  } catch {
53301
54483
  }
53302
54484
  try {
@@ -53348,6 +54530,7 @@ if (!isVitestRuntime()) {
53348
54530
  }
53349
54531
  // Annotate the CommonJS export names for ESM import in node:
53350
54532
  0 && (module.exports = {
54533
+ inspectTelemetryBuildConfig,
53351
54534
  listVisibleCLICommandNames,
53352
54535
  resolveBundledSkillsRoot,
53353
54536
  resolveBundledViewsPath,