@telepath-computer/television 0.1.178 → 0.1.180

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.
Files changed (34) hide show
  1. package/dist/canonical/v1/components.js +13 -1
  2. package/dist/cli.cjs +1188 -392
  3. package/dist/onboarding/README.md +35 -0
  4. package/dist/onboarding/business-ops/about.html +150 -0
  5. package/dist/onboarding/business-ops/retention-vs-releases.html +572 -0
  6. package/dist/onboarding/business-ops/revenue-vs-goals.html +621 -0
  7. package/dist/onboarding/onboarding-screens.json +167 -0
  8. package/dist/onboarding/productivity/about.html +149 -0
  9. package/dist/onboarding/productivity/company-todos/index.html +121 -0
  10. package/dist/onboarding/productivity/company-todos/task.css +205 -0
  11. package/dist/onboarding/productivity/company-todos/task.js +307 -0
  12. package/dist/onboarding/productivity/meeting-prep.html +440 -0
  13. package/dist/onboarding/productivity/priorities-today.html +409 -0
  14. package/dist/onboarding/productivity/todays-calendar/calendar.css +1 -0
  15. package/dist/onboarding/productivity/todays-calendar/calendar.js +716 -0
  16. package/dist/onboarding/productivity/todays-calendar/index.html +52 -0
  17. package/dist/onboarding/research/about.html +152 -0
  18. package/dist/onboarding/research/draft-blog-post.md +30 -0
  19. package/dist/onboarding/research/open-model-research.html +542 -0
  20. package/dist/onboarding/research/todays-news.html +503 -0
  21. package/dist/onboarding/{television-onboarding → tv-guide/welcome}/index.html +2 -2
  22. package/dist/skills/television/SKILL.md +4 -0
  23. package/dist/views/markdown/index.html +1 -1
  24. package/dist/web/assets/calendar-DToAnkzj.png +0 -0
  25. package/dist/web/assets/main-5017mprd.css +1 -0
  26. package/dist/web/assets/main-C2WA733G.js +865 -0
  27. package/dist/web/assets/markdown-DdDrJuVK.png +0 -0
  28. package/dist/web/assets/table-oeG9uAN1.png +0 -0
  29. package/dist/web/assets/tasks-D4xqXFPl.png +0 -0
  30. package/dist/web/index.html +2 -2
  31. package/package.json +1 -1
  32. package/dist/web/assets/main-FDJtlHD7.js +0 -768
  33. package/dist/web/assets/main-o9Z-XUYA.css +0 -1
  34. /package/dist/onboarding/{television-onboarding → tv-guide/welcome}/assets/television.svg +0 -0
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 path15 = require("node:path");
1197
+ var path17 = 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 = path15.resolve(baseDir, baseName);
2210
+ const localBin = path17.resolve(baseDir, baseName);
2211
2211
  if (fs4.existsSync(localBin)) return localBin;
2212
- if (sourceExt.includes(path15.extname(baseName))) return void 0;
2212
+ if (sourceExt.includes(path17.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 = path15.resolve(
2231
- path15.dirname(resolvedScriptPath),
2230
+ executableDir = path17.resolve(
2231
+ path17.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 = path15.basename(
2238
+ const legacyName = path17.basename(
2239
2239
  this._scriptPath,
2240
- path15.extname(this._scriptPath)
2240
+ path17.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(path15.extname(executableFile));
2251
+ launchWithNode = sourceExt.includes(path17.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 = path15.basename(filename, path15.extname(filename));
3166
+ this._name = path17.basename(filename, path17.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(path16) {
3181
- if (path16 === void 0) return this._executableDir;
3182
- this._executableDir = path16;
3180
+ executableDir(path18) {
3181
+ if (path18 === void 0) return this._executableDir;
3182
+ this._executableDir = path18;
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(path15) {
21484
- if (!path15 || typeof path15 !== "string") {
21483
+ function lookup(path17) {
21484
+ if (!path17 || typeof path17 !== "string") {
21485
21485
  return false;
21486
21486
  }
21487
- var extension3 = extname("x." + path15).toLowerCase().substr(1);
21487
+ var extension3 = extname("x." + path17).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(path15, keys, options) {
24224
+ function pathToRegexp(path17, 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 (path15 instanceof RegExp) {
24239
- while (m2 = MATCHING_GROUP_REGEXP.exec(path15.source)) {
24238
+ if (path17 instanceof RegExp) {
24239
+ while (m2 = MATCHING_GROUP_REGEXP.exec(path17.source)) {
24240
24240
  if (m2[0][0] === "\\") continue;
24241
24241
  keys.push({
24242
24242
  name: m2[1] || name++,
@@ -24244,18 +24244,18 @@ var require_path_to_regexp = __commonJS({
24244
24244
  offset: m2.index
24245
24245
  });
24246
24246
  }
24247
- return path15;
24247
+ return path17;
24248
24248
  }
24249
- if (Array.isArray(path15)) {
24250
- path15 = path15.map(function(value) {
24249
+ if (Array.isArray(path17)) {
24250
+ path17 = path17.map(function(value) {
24251
24251
  return pathToRegexp(value, keys, options).source;
24252
24252
  });
24253
- return new RegExp(path15.join("|"), flags);
24253
+ return new RegExp(path17.join("|"), flags);
24254
24254
  }
24255
- if (typeof path15 !== "string") {
24255
+ if (typeof path17 !== "string") {
24256
24256
  throw new TypeError("path must be a string, array of strings, or regular expression");
24257
24257
  }
24258
- path15 = path15.replace(
24258
+ path17 = path17.replace(
24259
24259
  /\\.|(\/)?(\.)?:(\w+)(\(.*?\))?(\*)?(\?)?|[.*]|\/\(/g,
24260
24260
  function(match, slash, format, key, capture2, star, optional2, offset) {
24261
24261
  if (match[0] === "\\") {
@@ -24272,7 +24272,7 @@ var require_path_to_regexp = __commonJS({
24272
24272
  if (slash || format) {
24273
24273
  backtrack = "";
24274
24274
  } else {
24275
- backtrack += path15.slice(pos, offset);
24275
+ backtrack += path17.slice(pos, offset);
24276
24276
  }
24277
24277
  pos = offset + match.length;
24278
24278
  if (match === "*") {
@@ -24302,7 +24302,7 @@ var require_path_to_regexp = __commonJS({
24302
24302
  return result;
24303
24303
  }
24304
24304
  );
24305
- while (m2 = MATCHING_GROUP_REGEXP.exec(path15)) {
24305
+ while (m2 = MATCHING_GROUP_REGEXP.exec(path17)) {
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
- path15 += strict ? "" : path15[path15.length - 1] === "/" ? "?" : "/?";
24317
+ path17 += strict ? "" : path17[path17.length - 1] === "/" ? "?" : "/?";
24318
24318
  if (end) {
24319
- path15 += "$";
24320
- } else if (path15[path15.length - 1] !== "/") {
24321
- path15 += lookahead ? "(?=/|$)" : "(?:/|$)";
24319
+ path17 += "$";
24320
+ } else if (path17[path17.length - 1] !== "/") {
24321
+ path17 += lookahead ? "(?=/|$)" : "(?:/|$)";
24322
24322
  }
24323
- return new RegExp("^" + path15, flags);
24323
+ return new RegExp("^" + path17, 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(path15, options, fn) {
24336
+ function Layer(path17, options, fn) {
24337
24337
  if (!(this instanceof Layer)) {
24338
- return new Layer(path15, options, fn);
24338
+ return new Layer(path17, options, fn);
24339
24339
  }
24340
- debug("new %o", path15);
24340
+ debug("new %o", path17);
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(path15, this.keys = [], opts);
24347
- this.regexp.fast_star = path15 === "*";
24348
- this.regexp.fast_slash = path15 === "/" && opts.end === false;
24346
+ this.regexp = pathRegexp(path17, this.keys = [], opts);
24347
+ this.regexp.fast_star = path17 === "*";
24348
+ this.regexp.fast_slash = path17 === "/" && 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(path15) {
24372
+ Layer.prototype.match = function match(path17) {
24373
24373
  var match2;
24374
- if (path15 != null) {
24374
+ if (path17 != 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(path15) };
24382
- this.path = path15;
24381
+ this.params = { "0": decode_param(path17) };
24382
+ this.path = path17;
24383
24383
  return true;
24384
24384
  }
24385
- match2 = this.regexp.exec(path15);
24385
+ match2 = this.regexp.exec(path17);
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(path15) {
24479
- this.path = path15;
24478
+ function Route(path17) {
24479
+ this.path = path17;
24480
24480
  this.stack = [];
24481
- debug("new %o", path15);
24481
+ debug("new %o", path17);
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 path15 = getPathname(req);
24694
- if (path15 == null) {
24693
+ var path17 = getPathname(req);
24694
+ if (path17 == 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, path15);
24702
+ match = matchLayer(layer, path17);
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, path15);
24740
+ trim_prefix(layer, layerError, layerPath, path17);
24741
24741
  }
24742
24742
  sync = 0;
24743
24743
  });
24744
24744
  }
24745
- function trim_prefix(layer, layerError, layerPath, path15) {
24745
+ function trim_prefix(layer, layerError, layerPath, path17) {
24746
24746
  if (layerPath.length !== 0) {
24747
- if (layerPath !== path15.slice(0, layerPath.length)) {
24747
+ if (layerPath !== path17.slice(0, layerPath.length)) {
24748
24748
  next(layerError);
24749
24749
  return;
24750
24750
  }
24751
- var c = path15[layerPath.length];
24751
+ var c = path17[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 path15 = "/";
24829
+ var path17 = "/";
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
- path15 = fn;
24837
+ path17 = 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", path15, fn.name || "<anonymous>");
24850
- var layer = new Layer(path15, {
24849
+ debug("use %o %s", path17, fn.name || "<anonymous>");
24850
+ var layer = new Layer(path17, {
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(path15) {
24861
- var route2 = new Route(path15);
24862
- var layer = new Layer(path15, {
24860
+ proto.route = function route(path17) {
24861
+ var route2 = new Route(path17);
24862
+ var layer = new Layer(path17, {
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(path15) {
24873
- var route = this.route(path15);
24872
+ proto[method] = function(path17) {
24873
+ var route = this.route(path17);
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, path15) {
24909
+ function matchLayer(layer, path17) {
24910
24910
  try {
24911
- return layer.match(path15);
24911
+ return layer.match(path17);
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 path15 = require("path");
25029
+ var path17 = require("path");
25030
25030
  var fs4 = require("fs");
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;
25031
+ var dirname = path17.dirname;
25032
+ var basename = path17.basename;
25033
+ var extname = path17.extname;
25034
+ var join2 = path17.join;
25035
+ var resolve = path17.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 path16;
25064
+ var path18;
25065
25065
  var roots = [].concat(this.root);
25066
25066
  debug('lookup "%s"', name);
25067
- for (var i = 0; i < roots.length && !path16; i++) {
25067
+ for (var i = 0; i < roots.length && !path18; 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
- path16 = this.resolve(dir, file2);
25072
+ path18 = this.resolve(dir, file2);
25073
25073
  }
25074
- return path16;
25074
+ return path18;
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 path16 = join2(dir, file2);
25083
- var stat = tryStat(path16);
25082
+ var path18 = join2(dir, file2);
25083
+ var stat = tryStat(path18);
25084
25084
  if (stat && stat.isFile()) {
25085
- return path16;
25085
+ return path18;
25086
25086
  }
25087
- path16 = join2(dir, basename(file2, ext), "index" + ext);
25088
- stat = tryStat(path16);
25087
+ path18 = join2(dir, basename(file2, ext), "index" + ext);
25088
+ stat = tryStat(path18);
25089
25089
  if (stat && stat.isFile()) {
25090
- return path16;
25090
+ return path18;
25091
25091
  }
25092
25092
  };
25093
- function tryStat(path16) {
25094
- debug('stat "%s"', path16);
25093
+ function tryStat(path18) {
25094
+ debug('stat "%s"', path18);
25095
25095
  try {
25096
- return fs4.statSync(path16);
25096
+ return fs4.statSync(path18);
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 path15 = require("path");
25874
+ var path17 = 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(path16, fallback) {
25905
- var ext = path16.replace(/^.*[\.\/\\]/, "").toLowerCase();
25904
+ Mime.prototype.lookup = function(path18, fallback) {
25905
+ var ext = path18.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 path15 = require("path");
26139
+ var path17 = require("path");
26140
26140
  var statuses = require_statuses();
26141
26141
  var Stream = require("stream");
26142
26142
  var util = require("util");
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;
26143
+ var extname = path17.extname;
26144
+ var join2 = path17.join;
26145
+ var normalize = path17.normalize;
26146
+ var resolve = path17.resolve;
26147
+ var sep = path17.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, path16, options) {
26154
- return new SendStream(req, path16, options);
26153
+ function send2(req, path18, options) {
26154
+ return new SendStream(req, path18, options);
26155
26155
  }
26156
- function SendStream(req, path16, options) {
26156
+ function SendStream(req, path18, options) {
26157
26157
  Stream.call(this);
26158
26158
  var opts = options || {};
26159
26159
  this.options = opts;
26160
- this.path = path16;
26160
+ this.path = path18;
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(path16) {
26207
- this._root = resolve(String(path16));
26206
+ SendStream.prototype.root = function root(path18) {
26207
+ this._root = resolve(String(path18));
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(path16) {
26320
+ SendStream.prototype.redirect = function redirect(path18) {
26321
26321
  var res = this.res;
26322
26322
  if (hasListeners(this, "directory")) {
26323
- this.emit("directory", res, path16);
26323
+ this.emit("directory", res, path18);
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 path16 = decode3(this.path);
26344
- if (path16 === -1) {
26343
+ var path18 = decode3(this.path);
26344
+ if (path18 === -1) {
26345
26345
  this.error(400);
26346
26346
  return res;
26347
26347
  }
26348
- if (~path16.indexOf("\0")) {
26348
+ if (~path18.indexOf("\0")) {
26349
26349
  this.error(400);
26350
26350
  return res;
26351
26351
  }
26352
26352
  var parts;
26353
26353
  if (root !== null) {
26354
- if (path16) {
26355
- path16 = normalize("." + sep + path16);
26354
+ if (path18) {
26355
+ path18 = normalize("." + sep + path18);
26356
26356
  }
26357
- if (UP_PATH_REGEXP.test(path16)) {
26358
- debug('malicious path "%s"', path16);
26357
+ if (UP_PATH_REGEXP.test(path18)) {
26358
+ debug('malicious path "%s"', path18);
26359
26359
  this.error(403);
26360
26360
  return res;
26361
26361
  }
26362
- parts = path16.split(sep);
26363
- path16 = normalize(join2(root, path16));
26362
+ parts = path18.split(sep);
26363
+ path18 = normalize(join2(root, path18));
26364
26364
  } else {
26365
- if (UP_PATH_REGEXP.test(path16)) {
26366
- debug('malicious path "%s"', path16);
26365
+ if (UP_PATH_REGEXP.test(path18)) {
26366
+ debug('malicious path "%s"', path18);
26367
26367
  this.error(403);
26368
26368
  return res;
26369
26369
  }
26370
- parts = normalize(path16).split(sep);
26371
- path16 = resolve(path16);
26370
+ parts = normalize(path18).split(sep);
26371
+ path18 = resolve(path18);
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, path16);
26378
+ debug('%s dotfile "%s"', access2, path18);
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(path16);
26392
+ this.sendIndex(path18);
26393
26393
  return res;
26394
26394
  }
26395
- this.sendFile(path16);
26395
+ this.sendFile(path18);
26396
26396
  return res;
26397
26397
  };
26398
- SendStream.prototype.send = function send3(path16, stat) {
26398
+ SendStream.prototype.send = function send3(path18, 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"', path16);
26411
- this.setHeader(path16, stat);
26412
- this.type(path16);
26410
+ debug('pipe "%s"', path18);
26411
+ this.setHeader(path18, stat);
26412
+ this.type(path18);
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(path16, opts);
26461
+ this.stream(path18, opts);
26462
26462
  };
26463
- SendStream.prototype.sendFile = function sendFile(path16) {
26463
+ SendStream.prototype.sendFile = function sendFile(path18) {
26464
26464
  var i = 0;
26465
26465
  var self2 = this;
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) {
26466
+ debug('stat "%s"', path18);
26467
+ fs4.stat(path18, function onstat(err, stat) {
26468
+ if (err && err.code === "ENOENT" && !extname(path18) && path18[path18.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(path16);
26473
- self2.emit("file", path16, stat);
26474
- self2.send(path16, stat);
26472
+ if (stat.isDirectory()) return self2.redirect(path18);
26473
+ self2.emit("file", path18, stat);
26474
+ self2.send(path18, 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 = path16 + "." + self2._extensions[i++];
26480
+ var p = path18 + "." + 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(path16) {
26490
+ SendStream.prototype.sendIndex = function sendIndex(path18) {
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(path16, self2._index[i]);
26498
+ var p = join2(path18, 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(path16, options) {
26509
+ SendStream.prototype.stream = function stream(path18, options) {
26510
26510
  var self2 = this;
26511
26511
  var res = this.res;
26512
- var stream2 = fs4.createReadStream(path16, options);
26512
+ var stream2 = fs4.createReadStream(path18, 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(path16) {
26527
+ SendStream.prototype.type = function type(path18) {
26528
26528
  var res = this.res;
26529
26529
  if (res.getHeader("Content-Type")) return;
26530
- var type2 = mime.lookup(path16);
26530
+ var type2 = mime.lookup(path18);
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(path16, stat) {
26539
+ SendStream.prototype.setHeader = function setHeader(path18, stat) {
26540
26540
  var res = this.res;
26541
- this.emit("headers", res, path16, stat);
26541
+ this.emit("headers", res, path18, 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(path16) {
26600
+ function decode3(path18) {
26601
26601
  try {
26602
- return decodeURIComponent(path16);
26602
+ return decodeURIComponent(path18);
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(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;
27511
+ exports2.isAbsolute = function(path17) {
27512
+ if ("/" === path17[0]) return true;
27513
+ if (":" === path17[1] && ("\\" === path17[2] || "/" === path17[2])) return true;
27514
+ if ("\\\\" === path17.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 path15 = "/";
27725
+ var path17 = "/";
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
- path15 = fn;
27733
+ path17 = 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(path15, fn2);
27744
+ return router.use(path17, fn2);
27745
27745
  }
27746
- debug(".use app under %s", path15);
27747
- fn2.mountpath = path15;
27746
+ debug(".use app under %s", path17);
27747
+ fn2.mountpath = path17;
27748
27748
  fn2.parent = this;
27749
- router.use(path15, function mounted_app(req, res, next) {
27749
+ router.use(path17, 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(path15) {
27761
+ app.route = function route(path17) {
27762
27762
  this.lazyrouter();
27763
- return this._router.route(path15);
27763
+ return this._router.route(path17);
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 path15() {
27814
+ app.path = function path17() {
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(path15) {
27830
+ app[method] = function(path17) {
27831
27831
  if (method === "get" && arguments.length === 1) {
27832
- return this.set(path15);
27832
+ return this.set(path17);
27833
27833
  }
27834
27834
  this.lazyrouter();
27835
- var route = this._router.route(path15);
27835
+ var route = this._router.route(path17);
27836
27836
  route[method].apply(route, slice.call(arguments, 1));
27837
27837
  return this;
27838
27838
  };
27839
27839
  });
27840
- app.all = function all(path15) {
27840
+ app.all = function all(path17) {
27841
27841
  this.lazyrouter();
27842
- var route = this._router.route(path15);
27842
+ var route = this._router.route(path17);
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);
@@ -28598,7 +28598,7 @@ var require_request = __commonJS({
28598
28598
  var subdomains2 = !isIP2(hostname3) ? hostname3.split(".").reverse() : [hostname3];
28599
28599
  return subdomains2.slice(offset);
28600
28600
  });
28601
- defineGetter(req, "path", function path15() {
28601
+ defineGetter(req, "path", function path17() {
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 path15 = require("path");
28923
+ var path17 = 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 = path15.extname;
28932
+ var extname = path17.extname;
28933
28933
  var mime = send2.mime;
28934
- var resolve = path15.resolve;
28934
+ var resolve = path17.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(path16, options, callback) {
29111
+ res.sendFile = function sendFile(path18, 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 (!path16) {
29117
+ if (!path18) {
29118
29118
  throw new TypeError("path argument is required to res.sendFile");
29119
29119
  }
29120
- if (typeof path16 !== "string") {
29120
+ if (typeof path18 !== "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(path16)) {
29127
+ if (!opts.root && !isAbsolute(path18)) {
29128
29128
  throw new TypeError("path must be absolute or specify root to res.sendFile");
29129
29129
  }
29130
- var pathname = encodeURI(path16);
29130
+ var pathname = encodeURI(path18);
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(path16, options, callback) {
29140
+ res.sendfile = function(path18, 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, path16, opts);
29150
+ var file2 = send2(req, path18, 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(path16, filename, options, callback) {
29163
+ res.download = function download(path18, 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 || path16)
29180
+ "Content-Disposition": contentDisposition(name || path18)
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(path16) : path16;
29193
+ var fullPath = !opts.root ? resolve(path18) : path18;
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 path15 = parseUrl(req).pathname;
29495
- if (path15 === "/" && originalUrl.pathname.substr(-1) !== "/") {
29496
- path15 = "";
29494
+ var path17 = parseUrl(req).pathname;
29495
+ if (path17 === "/" && originalUrl.pathname.substr(-1) !== "/") {
29496
+ path17 = "";
29497
29497
  }
29498
- var stream = send2(req, path15, opts);
29498
+ var stream = send2(req, path17, opts);
29499
29499
  stream.on("directory", onDirectory);
29500
29500
  if (setHeaders) {
29501
29501
  stream.on("headers", setHeaders);
@@ -33255,17 +33255,17 @@ __export(index_exports, {
33255
33255
  resolveBundledSkillsRoot: () => resolveBundledSkillsRoot,
33256
33256
  resolveBundledViewsPath: () => resolveBundledViewsPath,
33257
33257
  resolveCanonicalDir: () => resolveCanonicalDir,
33258
- resolveOnboardingArtifactSourcePath: () => resolveOnboardingArtifactSourcePath,
33258
+ resolveOnboardingContentPath: () => resolveOnboardingContentPath,
33259
33259
  resolveStaticDir: () => resolveStaticDir,
33260
33260
  runCLI: () => runCLI
33261
33261
  });
33262
33262
  module.exports = __toCommonJS(index_exports);
33263
33263
  var import_node_child_process3 = require("node:child_process");
33264
- var import_node_fs12 = require("node:fs");
33264
+ var import_node_fs14 = require("node:fs");
33265
33265
  var import_node_os5 = __toESM(require("node:os"), 1);
33266
- var import_node_path15 = __toESM(require("node:path"), 1);
33266
+ var import_node_path17 = __toESM(require("node:path"), 1);
33267
33267
  var import_node_module = require("node:module");
33268
- var import_node_url3 = require("node:url");
33268
+ var import_node_url2 = require("node:url");
33269
33269
 
33270
33270
  // ../../node_modules/commander/esm.mjs
33271
33271
  var import_index = __toESM(require_commander(), 1);
@@ -33416,22 +33416,22 @@ var Daemon = class {
33416
33416
  }
33417
33417
  async install() {
33418
33418
  if (this.platform === "darwin") {
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);
33419
+ const path17 = plistPath(this.home, this.name);
33420
+ if ((0, import_node_fs.existsSync)(path17)) {
33421
+ await this.exec("launchctl", ["unload", "-w", path17]).catch(() => void 0);
33422
33422
  }
33423
33423
  await (0, import_promises.mkdir)((0, import_node_path.join)(this.home, "Library", "LaunchAgents"), { recursive: true });
33424
- await (0, import_promises.writeFile)(path15, renderPlist(this.name, this.programArgs, this.env), "utf8");
33425
- await this.exec("launchctl", ["load", "-w", path15]);
33424
+ await (0, import_promises.writeFile)(path17, renderPlist(this.name, this.programArgs, this.env), "utf8");
33425
+ await this.exec("launchctl", ["load", "-w", path17]);
33426
33426
  return;
33427
33427
  }
33428
33428
  if (this.platform === "linux") {
33429
- const path15 = unitPath(this.home, this.name);
33430
- if ((0, import_node_fs.existsSync)(path15)) {
33429
+ const path17 = unitPath(this.home, this.name);
33430
+ if ((0, import_node_fs.existsSync)(path17)) {
33431
33431
  await this.exec("systemctl", ["--user", "disable", "--now", `${this.name}.service`]).catch(() => void 0);
33432
33432
  }
33433
33433
  await (0, import_promises.mkdir)((0, import_node_path.join)(this.home, ".config", "systemd", "user"), { recursive: true });
33434
- await (0, import_promises.writeFile)(path15, renderUnit(this.description, this.programArgs, this.env), "utf8");
33434
+ await (0, import_promises.writeFile)(path17, renderUnit(this.description, this.programArgs, this.env), "utf8");
33435
33435
  await this.exec("systemctl", ["--user", "daemon-reload"]);
33436
33436
  await this.exec("systemctl", ["--user", "enable", "--now", `${this.name}.service`]);
33437
33437
  return;
@@ -33440,17 +33440,17 @@ var Daemon = class {
33440
33440
  }
33441
33441
  async uninstall() {
33442
33442
  if (this.platform === "darwin") {
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 });
33443
+ const path17 = plistPath(this.home, this.name);
33444
+ if ((0, import_node_fs.existsSync)(path17)) {
33445
+ await this.exec("launchctl", ["unload", "-w", path17]).catch(() => void 0);
33446
+ await (0, import_promises.rm)(path17, { force: true });
33447
33447
  }
33448
33448
  return;
33449
33449
  }
33450
33450
  if (this.platform === "linux") {
33451
- const path15 = unitPath(this.home, this.name);
33451
+ const path17 = unitPath(this.home, this.name);
33452
33452
  await this.exec("systemctl", ["--user", "disable", "--now", `${this.name}.service`]).catch(() => void 0);
33453
- await (0, import_promises.rm)(path15, { force: true });
33453
+ await (0, import_promises.rm)(path17, { force: true });
33454
33454
  await this.exec("systemctl", ["--user", "daemon-reload"]);
33455
33455
  return;
33456
33456
  }
@@ -33458,8 +33458,8 @@ var Daemon = class {
33458
33458
  }
33459
33459
  async status() {
33460
33460
  if (this.platform === "darwin") {
33461
- const path15 = plistPath(this.home, this.name);
33462
- if (!(0, import_node_fs.existsSync)(path15))
33461
+ const path17 = plistPath(this.home, this.name);
33462
+ if (!(0, import_node_fs.existsSync)(path17))
33463
33463
  return { installed: false, running: false };
33464
33464
  try {
33465
33465
  await this.exec("launchctl", ["list", this.name]);
@@ -33469,8 +33469,8 @@ var Daemon = class {
33469
33469
  }
33470
33470
  }
33471
33471
  if (this.platform === "linux") {
33472
- const path15 = unitPath(this.home, this.name);
33473
- if (!(0, import_node_fs.existsSync)(path15))
33472
+ const path17 = unitPath(this.home, this.name);
33473
+ if (!(0, import_node_fs.existsSync)(path17))
33474
33474
  return { installed: false, running: false };
33475
33475
  try {
33476
33476
  const result = await this.exec("systemctl", [
@@ -33746,6 +33746,7 @@ function cloneStackChild(node) {
33746
33746
  // ../shared/src/types.ts
33747
33747
  var TELEVISION_CLIENT_META_HEADER = "X-Television-Client-Meta";
33748
33748
  var TELEMETRY_ACTIVITY_MESSAGE_TYPE = "telemetry-activity";
33749
+ var TELEMETRY_SIGNAL_MESSAGE_TYPE = "telemetry-signal";
33749
33750
  function createCardNode(artifactID, overrides = {}) {
33750
33751
  return {
33751
33752
  type: "card",
@@ -34185,6 +34186,22 @@ function buildConnectURL(serverURL, token) {
34185
34186
  return clean.toString();
34186
34187
  }
34187
34188
 
34189
+ // ../shared/src/version.ts
34190
+ var DEV_VERSION = "0.0.0";
34191
+ var RELEASE_VERSION_PATTERN = /^\d+\.\d+\.\d+$/;
34192
+ var TRIPLE_COMPONENTS = 3;
34193
+ function isReleaseVersion(value) {
34194
+ return RELEASE_VERSION_PATTERN.test(value);
34195
+ }
34196
+ function isNewerVersion(candidate, baseline) {
34197
+ const a = candidate.split(".").map(Number);
34198
+ const b2 = baseline.split(".").map(Number);
34199
+ for (let i = 0; i < TRIPLE_COMPONENTS; i++) {
34200
+ if (a[i] !== b2[i]) return a[i] > b2[i];
34201
+ }
34202
+ return false;
34203
+ }
34204
+
34188
34205
  // ../server/src/server.ts
34189
34206
  var import_express2 = __toESM(require_express2(), 1);
34190
34207
  var import_node_fs9 = require("node:fs");
@@ -34208,6 +34225,10 @@ var TELEMETRY_CONTROL_ENV_VARS = [
34208
34225
  "TV_TELEMETRY_DEV",
34209
34226
  "TELEVISION_TELEMETRY_BUILD"
34210
34227
  ];
34228
+ var UPDATE_CHANNEL_ENV_VARS = [
34229
+ "TV_UPDATE_CHANNEL_URL",
34230
+ "TV_UPDATE_CHANNEL_POLL_INTERVAL_MS"
34231
+ ];
34211
34232
  var ACP_AGENT_PROFILES = {
34212
34233
  openclaw: {
34213
34234
  agent: "openclaw",
@@ -34265,7 +34286,8 @@ function buildPersistedACPEnvironment(env, options = {}) {
34265
34286
  const snapshot = { PATH: pathValue };
34266
34287
  const developerHome = options.developerHome ?? import_node_os2.default.homedir();
34267
34288
  if (developerHome !== "") snapshot[TELEVISION_DEVELOPER_HOME_ENV] = developerHome;
34268
- copyTelemetryControlEnvironment(env, snapshot);
34289
+ copyEnvironmentAllowlist(env, snapshot, TELEMETRY_CONTROL_ENV_VARS);
34290
+ copyEnvironmentAllowlist(env, snapshot, UPDATE_CHANNEL_ENV_VARS);
34269
34291
  const profile = resolveACPAgentProfile(env);
34270
34292
  if (!profile) {
34271
34293
  return snapshot;
@@ -34278,8 +34300,8 @@ function buildPersistedACPEnvironment(env, options = {}) {
34278
34300
  }
34279
34301
  return snapshot;
34280
34302
  }
34281
- function copyTelemetryControlEnvironment(env, snapshot) {
34282
- for (const key of TELEMETRY_CONTROL_ENV_VARS) {
34303
+ function copyEnvironmentAllowlist(env, snapshot, keys) {
34304
+ for (const key of keys) {
34283
34305
  const value = env[key];
34284
34306
  if (value !== void 0 && value !== "") snapshot[key] = value;
34285
34307
  }
@@ -35072,10 +35094,10 @@ function mergeDefs(...defs) {
35072
35094
  function cloneDef(schema) {
35073
35095
  return mergeDefs(schema._zod.def);
35074
35096
  }
35075
- function getElementAtPath(obj, path15) {
35076
- if (!path15)
35097
+ function getElementAtPath(obj, path17) {
35098
+ if (!path17)
35077
35099
  return obj;
35078
- return path15.reduce((acc, key) => acc?.[key], obj);
35100
+ return path17.reduce((acc, key) => acc?.[key], obj);
35079
35101
  }
35080
35102
  function promiseAllObject(promisesObj) {
35081
35103
  const keys = Object.keys(promisesObj);
@@ -35458,11 +35480,11 @@ function aborted(x2, startIndex = 0) {
35458
35480
  }
35459
35481
  return false;
35460
35482
  }
35461
- function prefixIssues(path15, issues) {
35483
+ function prefixIssues(path17, issues) {
35462
35484
  return issues.map((iss) => {
35463
35485
  var _a2;
35464
35486
  (_a2 = iss).path ?? (_a2.path = []);
35465
- iss.path.unshift(path15);
35487
+ iss.path.unshift(path17);
35466
35488
  return iss;
35467
35489
  });
35468
35490
  }
@@ -35645,7 +35667,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
35645
35667
  }
35646
35668
  function treeifyError(error48, mapper = (issue2) => issue2.message) {
35647
35669
  const result = { errors: [] };
35648
- const processError = (error49, path15 = []) => {
35670
+ const processError = (error49, path17 = []) => {
35649
35671
  var _a2, _b;
35650
35672
  for (const issue2 of error49.issues) {
35651
35673
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -35655,7 +35677,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
35655
35677
  } else if (issue2.code === "invalid_element") {
35656
35678
  processError({ issues: issue2.issues }, issue2.path);
35657
35679
  } else {
35658
- const fullpath = [...path15, ...issue2.path];
35680
+ const fullpath = [...path17, ...issue2.path];
35659
35681
  if (fullpath.length === 0) {
35660
35682
  result.errors.push(mapper(issue2));
35661
35683
  continue;
@@ -35687,8 +35709,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
35687
35709
  }
35688
35710
  function toDotPath(_path) {
35689
35711
  const segs = [];
35690
- const path15 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
35691
- for (const seg of path15) {
35712
+ const path17 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
35713
+ for (const seg of path17) {
35692
35714
  if (typeof seg === "number")
35693
35715
  segs.push(`[${seg}]`);
35694
35716
  else if (typeof seg === "symbol")
@@ -47665,13 +47687,13 @@ function resolveRef(ref, ctx) {
47665
47687
  if (!ref.startsWith("#")) {
47666
47688
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
47667
47689
  }
47668
- const path15 = ref.slice(1).split("/").filter(Boolean);
47669
- if (path15.length === 0) {
47690
+ const path17 = ref.slice(1).split("/").filter(Boolean);
47691
+ if (path17.length === 0) {
47670
47692
  return ctx.rootSchema;
47671
47693
  }
47672
47694
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
47673
- if (path15[0] === defsKey) {
47674
- const key = path15[1];
47695
+ if (path17[0] === defsKey) {
47696
+ const key = path17[1];
47675
47697
  if (!key || !ctx.defs[key]) {
47676
47698
  throw new Error(`Reference not found: ${ref}`);
47677
47699
  }
@@ -50728,7 +50750,11 @@ var stackNodeSchema = external_exports.object({
50728
50750
  var layoutNodeSchema = external_exports.union([cardNodeSchema, rowNodeSchema, stackNodeSchema]);
50729
50751
  var patchScreenSchema = external_exports.object({
50730
50752
  name: external_exports.string().optional(),
50731
- layout: external_exports.array(layoutNodeSchema).optional()
50753
+ layout: external_exports.array(layoutNodeSchema).optional(),
50754
+ // Accepted but never read: the onboarding marker is installer-only and a
50755
+ // stray `onboarding` field must not fail an otherwise-valid request
50756
+ // (specs/arch/onboarding/tab-promotion.md#^marker-api-readonly).
50757
+ onboarding: external_exports.unknown().optional()
50732
50758
  }).strict().refine(
50733
50759
  (value) => value.name !== void 0 || value.layout !== void 0,
50734
50760
  { message: "At least one of name or layout must be provided" }
@@ -50775,7 +50801,10 @@ var HTTP_CONFLICT = 409;
50775
50801
  var CORS_HEADERS = {
50776
50802
  "Access-Control-Allow-Origin": "*",
50777
50803
  "Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
50778
- "Access-Control-Allow-Headers": `Authorization, Content-Type, ${TELEVISION_CLIENT_META_HEADER}`
50804
+ "Access-Control-Allow-Headers": `Authorization, Content-Type, ${TELEVISION_CLIENT_META_HEADER}`,
50805
+ // Cross-origin clients can read the version advertisement header
50806
+ // (specs/arch/updates/version-advertisement.md ^version-header).
50807
+ "Access-Control-Expose-Headers": "X-TV-Version"
50779
50808
  };
50780
50809
  function applyCorsHeaders(res) {
50781
50810
  for (const [name, value] of Object.entries(CORS_HEADERS)) {
@@ -50898,7 +50927,10 @@ function registerRoutes(app, store, options) {
50898
50927
  try {
50899
50928
  const screen = store.updateScreen({
50900
50929
  screenID: req.params.id,
50901
- fields: { ...parsed.data, layout: parsed.data.layout }
50930
+ fields: {
50931
+ ...parsed.data.name !== void 0 ? { name: parsed.data.name } : {},
50932
+ layout: parsed.data.layout
50933
+ }
50902
50934
  }, telemetryContext(req));
50903
50935
  res.json({ screen });
50904
50936
  } catch (error48) {
@@ -51023,6 +51055,36 @@ function isAuthorizedQueryToken(requestURL, expectedToken) {
51023
51055
  return token === expectedToken;
51024
51056
  }
51025
51057
 
51058
+ // ../server/src/telemetry/client-signals.ts
51059
+ var RELEASE_VERSION = /^\d+\.\d+\.\d+$/;
51060
+ var CLIENT_SIGNAL_REGISTRY = {
51061
+ client_autoreloaded: { from_version: RELEASE_VERSION, to_version: RELEASE_VERSION },
51062
+ update_toast_shown: { server_version: RELEASE_VERSION, channel_version: RELEASE_VERSION },
51063
+ update_prompt_copy_clicked: { server_version: RELEASE_VERSION, channel_version: RELEASE_VERSION },
51064
+ desktop_upgrade_gate_shown: { desktop_app_version: RELEASE_VERSION, required_desktop_version: RELEASE_VERSION }
51065
+ };
51066
+ function validateClientSignal(message, expectedClientId) {
51067
+ if (!message || typeof message !== "object" || Array.isArray(message)) return null;
51068
+ const record2 = message;
51069
+ if (record2.type !== TELEMETRY_SIGNAL_MESSAGE_TYPE) return null;
51070
+ if (record2.clientId !== expectedClientId) return null;
51071
+ if (typeof record2.event !== "string" || !Object.hasOwn(CLIENT_SIGNAL_REGISTRY, record2.event)) return null;
51072
+ const patterns = CLIENT_SIGNAL_REGISTRY[record2.event];
51073
+ const rawProperties = record2.properties === void 0 ? {} : record2.properties;
51074
+ if (!rawProperties || typeof rawProperties !== "object" || Array.isArray(rawProperties)) return null;
51075
+ const properties = {};
51076
+ for (const [key, value] of Object.entries(rawProperties)) {
51077
+ if (!Object.hasOwn(patterns, key)) return null;
51078
+ const pattern = patterns[key];
51079
+ if (typeof value !== "string" || !pattern.test(value)) return null;
51080
+ properties[key] = telemetryVersion(value);
51081
+ }
51082
+ return {
51083
+ name: record2.event,
51084
+ properties
51085
+ };
51086
+ }
51087
+
51026
51088
  // ../server/src/event-stream.ts
51027
51089
  var AUTH_FAILED_CLOSE_CODE = 4401;
51028
51090
  var EventStreamServer = class extends withDisposable(class {
@@ -51030,27 +51092,54 @@ var EventStreamServer = class extends withDisposable(class {
51030
51092
  wsServer;
51031
51093
  store;
51032
51094
  authRequired;
51095
+ buildServerStatus;
51033
51096
  recordTelemetryActivity;
51097
+ recordTelemetryClientSignal;
51034
51098
  unsubscribe = [];
51035
51099
  constructor(options) {
51036
51100
  super();
51037
51101
  this.store = options.store;
51038
51102
  this.authRequired = options.authRequired;
51103
+ this.buildServerStatus = options.buildServerStatus;
51039
51104
  this.recordTelemetryActivity = options.recordTelemetryActivity;
51105
+ this.recordTelemetryClientSignal = options.recordTelemetryClientSignal;
51040
51106
  this.wsServer = new import_websocket_server.default({ noServer: true });
51041
51107
  this.wsServer.on("connection", (socket, request) => {
51042
51108
  if (this.authRequired && !isAuthorizedQueryToken(request.url, this.store.authToken)) {
51043
51109
  socket.close(AUTH_FAILED_CLOSE_CODE, "Authentication failed");
51044
51110
  return;
51045
51111
  }
51112
+ if (this.buildServerStatus) {
51113
+ socket.send(JSON.stringify(this.buildServerStatus()));
51114
+ }
51046
51115
  const clientContext = parseClientTelemetryMetaFromRequest(request);
51047
51116
  socket.on("message", (data) => {
51048
- if (!isTelemetryActivityMessage(data, clientContext?.clientId ?? null)) return;
51049
- if (clientContext) this.recordTelemetryActivity?.(clientContext);
51117
+ if (!clientContext) return;
51118
+ const parsed = parseJSONMessage(data);
51119
+ if (parsed === null) return;
51120
+ if (isTelemetryActivityMessage(parsed, clientContext.clientId)) {
51121
+ this.recordTelemetryActivity?.(clientContext);
51122
+ return;
51123
+ }
51124
+ const signal = validateClientSignal(parsed, clientContext.clientId);
51125
+ if (signal) this.recordTelemetryClientSignal?.(clientContext, signal);
51050
51126
  });
51051
51127
  });
51052
51128
  this.subscribeStore();
51053
51129
  }
51130
+ /**
51131
+ * Re-broadcast the current server-status to every connected client — the
51132
+ * update-state-change relay (specs/arch/updates/update-channel.md ^relay).
51133
+ */
51134
+ broadcastServerStatus() {
51135
+ if (!this.buildServerStatus) return;
51136
+ const payload = JSON.stringify(this.buildServerStatus());
51137
+ for (const socket of this.wsServer.clients) {
51138
+ if (socket.readyState === import_websocket.default.OPEN) {
51139
+ socket.send(payload);
51140
+ }
51141
+ }
51142
+ }
51054
51143
  /** Number of currently-open `/events` sockets. */
51055
51144
  getConnectedClientCount() {
51056
51145
  let count = 0;
@@ -51144,14 +51233,14 @@ var EventStreamServer = class extends withDisposable(class {
51144
51233
  }
51145
51234
  }
51146
51235
  };
51147
- function isTelemetryActivityMessage(data, expectedClientId) {
51148
- if (!expectedClientId) return false;
51149
- let parsed;
51236
+ function parseJSONMessage(data) {
51150
51237
  try {
51151
- parsed = JSON.parse(data.toString());
51238
+ return JSON.parse(data.toString());
51152
51239
  } catch {
51153
- return false;
51240
+ return null;
51154
51241
  }
51242
+ }
51243
+ function isTelemetryActivityMessage(parsed, expectedClientId) {
51155
51244
  if (!parsed || typeof parsed !== "object") return false;
51156
51245
  const record2 = parsed;
51157
51246
  return record2.type === TELEMETRY_ACTIVITY_MESSAGE_TYPE && record2.clientId === expectedClientId && Object.keys(record2).length === 2;
@@ -51829,6 +51918,9 @@ function getTelemetryStatePath(storagePath) {
51829
51918
  function getTokenPath(storagePath) {
51830
51919
  return import_node_path8.default.join(getStateDir(storagePath), "token");
51831
51920
  }
51921
+ function getOnboardingStatePath(storagePath) {
51922
+ return import_node_path8.default.join(getStateDir(storagePath), "onboarding.json");
51923
+ }
51832
51924
  function getOnboardingArtifactSentinelPath(storagePath) {
51833
51925
  return import_node_path8.default.join(getStateDir(storagePath), "onboarding-artifact.json");
51834
51926
  }
@@ -52395,6 +52487,171 @@ function disabledTelemetryRuntime() {
52395
52487
  };
52396
52488
  }
52397
52489
 
52490
+ // ../server/src/updates/version.ts
52491
+ function readVersionStamp() {
52492
+ if ("0.1.180".length > 0) return "0.1.180";
52493
+ return void 0;
52494
+ }
52495
+ function resolveUpdateReleaseVersion(env = process.env, stamp = readVersionStamp()) {
52496
+ if (stamp !== void 0) return stamp;
52497
+ const hook = env.TV_TEST_VERSION;
52498
+ if (hook !== void 0 && isReleaseVersion(hook)) return hook;
52499
+ return DEV_VERSION;
52500
+ }
52501
+ function resolveRequiredDesktopVersion(baked, env = process.env, stamp = readVersionStamp()) {
52502
+ if (stamp !== void 0) return baked;
52503
+ const hook = env.TV_TEST_REQUIRED_DESKTOP_VERSION;
52504
+ if (hook !== void 0 && isReleaseVersion(hook)) return hook;
52505
+ return baked;
52506
+ }
52507
+
52508
+ // ../server/src/required-desktop-version.ts
52509
+ var REQUIRED_DESKTOP_VERSION = "0.1.177";
52510
+
52511
+ // ../server/src/updates/server-status.ts
52512
+ function buildServerStatus(env = process.env, stamp = readVersionStamp(), baked = REQUIRED_DESKTOP_VERSION, update = null) {
52513
+ const version2 = resolveUpdateReleaseVersion(env, stamp);
52514
+ const requiredDesktopVersion = version2 === DEV_VERSION ? null : resolveRequiredDesktopVersion(baked, env, stamp);
52515
+ return { type: "server-status", version: version2, requiredDesktopVersion, update };
52516
+ }
52517
+
52518
+ // ../server/src/updates/update-channel.ts
52519
+ var PRODUCTION_UPDATE_CHANNEL_URL = "https://television.run/update-channel.json";
52520
+ var MINUTES_PER_HOUR3 = 60;
52521
+ var SECONDS_PER_MINUTE3 = 60;
52522
+ var MILLISECONDS_PER_SECOND2 = 1e3;
52523
+ var HOURLY_POLL_INTERVAL_MS = MINUTES_PER_HOUR3 * SECONDS_PER_MINUTE3 * MILLISECONDS_PER_SECOND2;
52524
+ var JITTER_MAX_MINUTES = 10;
52525
+ var POLL_JITTER_MAX_MS = JITTER_MAX_MINUTES * SECONDS_PER_MINUTE3 * MILLISECONDS_PER_SECOND2;
52526
+ var FETCH_TIMEOUT_MS = 1e4;
52527
+ function parseUpdateChannelDocument(value) {
52528
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
52529
+ const record2 = value;
52530
+ if (typeof record2.schemaVersion !== "number" || !Number.isInteger(record2.schemaVersion) || record2.schemaVersion < 1) return null;
52531
+ if (typeof record2.version !== "string" || !isReleaseVersion(record2.version)) return null;
52532
+ const toast = record2.toast;
52533
+ if (!toast || typeof toast !== "object" || Array.isArray(toast)) return null;
52534
+ const toastRecord = toast;
52535
+ if (typeof toastRecord.markdown !== "string" || toastRecord.markdown.length === 0) return null;
52536
+ if (toastRecord.prompt !== void 0 && typeof toastRecord.prompt !== "string") return null;
52537
+ if (toastRecord.promptButtonLabel !== void 0 && typeof toastRecord.promptButtonLabel !== "string") return null;
52538
+ let desktop;
52539
+ if (record2.desktop !== void 0) {
52540
+ if (!record2.desktop || typeof record2.desktop !== "object" || Array.isArray(record2.desktop)) return null;
52541
+ const desktopRecord = record2.desktop;
52542
+ if (typeof desktopRecord.upgradeMarkdown !== "string" || desktopRecord.upgradeMarkdown.length === 0) return null;
52543
+ desktop = { upgradeMarkdown: desktopRecord.upgradeMarkdown };
52544
+ }
52545
+ return {
52546
+ schemaVersion: record2.schemaVersion,
52547
+ version: record2.version,
52548
+ toast: {
52549
+ markdown: toastRecord.markdown,
52550
+ ...toastRecord.prompt === void 0 ? {} : { prompt: toastRecord.prompt },
52551
+ ...toastRecord.promptButtonLabel === void 0 ? {} : { promptButtonLabel: toastRecord.promptButtonLabel }
52552
+ },
52553
+ ...desktop === void 0 ? {} : { desktop }
52554
+ };
52555
+ }
52556
+ function deriveUpdateState(document2, serverVersion) {
52557
+ if (document2 === null) return null;
52558
+ return {
52559
+ toast: isNewerVersion(document2.version, serverVersion) ? {
52560
+ version: document2.version,
52561
+ markdown: document2.toast.markdown,
52562
+ ...document2.toast.prompt === void 0 ? {} : { prompt: document2.toast.prompt },
52563
+ ...document2.toast.promptButtonLabel === void 0 ? {} : { promptButtonLabel: document2.toast.promptButtonLabel }
52564
+ } : null,
52565
+ desktop: document2.desktop === void 0 ? null : { upgradeMarkdown: document2.desktop.upgradeMarkdown }
52566
+ };
52567
+ }
52568
+ function createUpdateChannelPoller(options) {
52569
+ const env = options.env ?? process.env;
52570
+ const fetchImpl = options.fetchImpl ?? ((url2, init) => fetch(url2, init));
52571
+ const setTimeoutImpl = options.setTimeoutImpl ?? ((callback, delayMs) => setTimeout(callback, delayMs));
52572
+ const clearTimeoutImpl = options.clearTimeoutImpl ?? ((handle) => clearTimeout(handle));
52573
+ const random = options.random ?? Math.random;
52574
+ const nowSeconds = options.nowSeconds ?? (() => Math.floor(Date.now() / MILLISECONDS_PER_SECOND2));
52575
+ const urlOverride = env.TV_UPDATE_CHANNEL_URL;
52576
+ const hasURLOverride = typeof urlOverride === "string" && urlOverride.length > 0;
52577
+ const pollingEnabled = hasURLOverride || options.serverVersion !== DEV_VERSION;
52578
+ const channelURL = hasURLOverride ? urlOverride : PRODUCTION_UPDATE_CHANNEL_URL;
52579
+ const intervalOverrideMs = hasURLOverride ? parseIntervalOverride(env.TV_UPDATE_CHANNEL_POLL_INTERVAL_MS) : null;
52580
+ let stopped = false;
52581
+ let started = false;
52582
+ let timer = null;
52583
+ let inFlight = null;
52584
+ let lastKnownGood = null;
52585
+ let lastKnownGoodKey = null;
52586
+ function cacheBustedURL() {
52587
+ const url2 = new URL(channelURL);
52588
+ url2.searchParams.set("t", String(nowSeconds()));
52589
+ return url2.toString();
52590
+ }
52591
+ function nextDelayMs() {
52592
+ if (intervalOverrideMs !== null) return intervalOverrideMs;
52593
+ return HOURLY_POLL_INTERVAL_MS + Math.floor(random() * POLL_JITTER_MAX_MS);
52594
+ }
52595
+ function scheduleNext() {
52596
+ if (stopped) return;
52597
+ timer = setTimeoutImpl(() => {
52598
+ timer = null;
52599
+ void pollOnce();
52600
+ }, nextDelayMs());
52601
+ }
52602
+ function adopt(document2) {
52603
+ const key = JSON.stringify(document2);
52604
+ if (key === lastKnownGoodKey) return;
52605
+ lastKnownGood = document2;
52606
+ lastKnownGoodKey = key;
52607
+ options.onStateChange?.();
52608
+ }
52609
+ async function pollOnce() {
52610
+ const controller = new AbortController();
52611
+ inFlight = controller;
52612
+ const timeoutHandle = setTimeoutImpl(() => controller.abort(), FETCH_TIMEOUT_MS);
52613
+ try {
52614
+ const response = await fetchImpl(cacheBustedURL(), {
52615
+ headers: { "cache-control": "no-cache" },
52616
+ signal: controller.signal
52617
+ });
52618
+ if (response.ok) {
52619
+ const document2 = parseUpdateChannelDocument(await response.json());
52620
+ if (document2 !== null) adopt(document2);
52621
+ }
52622
+ } catch {
52623
+ } finally {
52624
+ clearTimeoutImpl(timeoutHandle);
52625
+ inFlight = null;
52626
+ scheduleNext();
52627
+ }
52628
+ }
52629
+ return {
52630
+ start() {
52631
+ if (started || stopped || !pollingEnabled) return;
52632
+ started = true;
52633
+ void pollOnce();
52634
+ },
52635
+ stop() {
52636
+ stopped = true;
52637
+ if (timer !== null) {
52638
+ clearTimeoutImpl(timer);
52639
+ timer = null;
52640
+ }
52641
+ inFlight?.abort();
52642
+ },
52643
+ getState() {
52644
+ return deriveUpdateState(lastKnownGood, options.serverVersion);
52645
+ }
52646
+ };
52647
+ }
52648
+ function parseIntervalOverride(value) {
52649
+ if (value === void 0 || value.length === 0) return null;
52650
+ const parsed = Number(value);
52651
+ if (!Number.isInteger(parsed) || parsed <= 0) return null;
52652
+ return parsed;
52653
+ }
52654
+
52398
52655
  // ../server/src/server.ts
52399
52656
  var import_meta = {};
52400
52657
  var HTTP_UNAUTHORIZED_STATUS = 401;
@@ -52413,6 +52670,7 @@ var Server = class {
52413
52670
  telemetryOptions;
52414
52671
  bindFailures = [];
52415
52672
  telemetryRuntime = null;
52673
+ updateChannel = null;
52416
52674
  listeningPort;
52417
52675
  baseURLs;
52418
52676
  disposed = false;
@@ -52428,9 +52686,17 @@ var Server = class {
52428
52686
  this.app = (0, import_express2.default)();
52429
52687
  this.httpServers = this.bindAddresses.map(() => import_node_http.default.createServer(this.app));
52430
52688
  this.httpServer = this.httpServers[0];
52689
+ const updateReleaseVersion = resolveUpdateReleaseVersion();
52690
+ this.app.use((_req, res, next) => {
52691
+ res.setHeader("X-TV-Version", updateReleaseVersion);
52692
+ next();
52693
+ });
52431
52694
  this.app.get("/health", (_req, res) => {
52432
52695
  res.json({
52433
52696
  status: "ok",
52697
+ // ^health-version: the unauthenticated liveness probe carries the
52698
+ // release version; a release version is not sensitive.
52699
+ version: updateReleaseVersion,
52434
52700
  bindAddresses: this.bindAddresses,
52435
52701
  port: this.getListeningPort()
52436
52702
  });
@@ -52439,7 +52705,14 @@ var Server = class {
52439
52705
  this.events = new EventStreamServer({
52440
52706
  store: this.store,
52441
52707
  authRequired: this.authRequired,
52442
- recordTelemetryActivity: (clientContext) => this.telemetryRuntime?.recordClientActivity(clientContext)
52708
+ buildServerStatus: () => buildServerStatus(void 0, void 0, void 0, this.updateChannel?.getState() ?? null),
52709
+ recordTelemetryActivity: (clientContext) => this.telemetryRuntime?.recordClientActivity(clientContext),
52710
+ // Validated client signals forward through the ordinary chokepoint with
52711
+ // completely normal handling — $session_id attribution (which bumps
52712
+ // session activity like any client-attributed request) and the
52713
+ // suppression gate (specs/arch/telemetry/client-signals.md
52714
+ // ^signal-forwarding).
52715
+ recordTelemetryClientSignal: (clientContext, event) => this.telemetryRuntime?.capture(event, clientContext)
52443
52716
  });
52444
52717
  this.acp = options.acpProfile ? new ACPServer({
52445
52718
  authToken: this.store.authToken,
@@ -52480,7 +52753,12 @@ var Server = class {
52480
52753
  if (options.staticDir) {
52481
52754
  this.app.use(import_express2.default.static(options.staticDir, {
52482
52755
  setHeaders: (res, filePath) => {
52483
- if (filePath.endsWith(".html") || filePath.endsWith(".htm")) res.setHeader("Referrer-Policy", "no-referrer");
52756
+ if (filePath.endsWith(".html") || filePath.endsWith(".htm")) {
52757
+ res.setHeader("Referrer-Policy", "no-referrer");
52758
+ res.setHeader("Cache-Control", "no-cache");
52759
+ } else if (filePath.includes(`${import_node_path11.default.sep}assets${import_node_path11.default.sep}`)) {
52760
+ res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
52761
+ }
52484
52762
  }
52485
52763
  }));
52486
52764
  }
@@ -52522,6 +52800,7 @@ var Server = class {
52522
52800
  throw new Error(message);
52523
52801
  }
52524
52802
  await this.startTelemetry();
52803
+ this.startUpdateChannel();
52525
52804
  log(this.store.storagePath, "server started", { snapshot: this.configurationSnapshot() });
52526
52805
  if (!this.authRequired) {
52527
52806
  log(this.store.storagePath, "server running without bearer-token enforcement", { authMode: this.authMode });
@@ -52562,6 +52841,8 @@ var Server = class {
52562
52841
  async dispose(signal) {
52563
52842
  if (this.disposed) return;
52564
52843
  this.disposed = true;
52844
+ this.updateChannel?.stop();
52845
+ this.updateChannel = null;
52565
52846
  let disposalError;
52566
52847
  try {
52567
52848
  await Promise.all([
@@ -52618,6 +52899,18 @@ var Server = class {
52618
52899
  getNonLoopbackBoundAddresses() {
52619
52900
  return this.baseURLs.map((url2) => new URL(url2).hostname).filter((address) => address !== LOOPBACK_IPV4);
52620
52901
  }
52902
+ /**
52903
+ * Update-channel poller lifecycle (specs/arch/updates/update-channel.md):
52904
+ * owned by the Server — started here, stopped in dispose() with its timer
52905
+ * cleared and any in-flight fetch aborted.
52906
+ */
52907
+ startUpdateChannel() {
52908
+ this.updateChannel = createUpdateChannelPoller({
52909
+ serverVersion: resolveUpdateReleaseVersion(),
52910
+ onStateChange: () => this.events.broadcastServerStatus()
52911
+ });
52912
+ this.updateChannel.start();
52913
+ }
52621
52914
  async startTelemetry() {
52622
52915
  const version2 = this.telemetryOptions.version ?? readServerPackageVersion();
52623
52916
  const launchMode = this.telemetryOptions.launchMode ?? "cli";
@@ -52627,7 +52920,9 @@ var Server = class {
52627
52920
  dataDirCreated: this.store.dataDirCreated,
52628
52921
  ...this.telemetryOptions.env === void 0 ? {} : { env: this.telemetryOptions.env },
52629
52922
  ...this.telemetryOptions.sink === void 0 ? {} : { sink: this.telemetryOptions.sink },
52630
- ...this.telemetryOptions.developerHost === void 0 ? {} : { developerHost: this.telemetryOptions.developerHost }
52923
+ ...this.telemetryOptions.developerHost === void 0 ? {} : { developerHost: this.telemetryOptions.developerHost },
52924
+ ...this.telemetryOptions.sessions === void 0 ? {} : { sessions: this.telemetryOptions.sessions },
52925
+ ...this.telemetryOptions.nowMs === void 0 ? {} : { nowMs: this.telemetryOptions.nowMs }
52631
52926
  });
52632
52927
  this.telemetryRuntime = runtime;
52633
52928
  this.store.setTelemetryHooks(createServerStoreTelemetryHooks(this.store, runtime.capture));
@@ -52695,8 +52990,8 @@ var Server = class {
52695
52990
  };
52696
52991
  };
52697
52992
  function readServerPackageVersion() {
52698
- if ("0.1.178".length > 0) {
52699
- return telemetryVersion("0.1.178");
52993
+ if ("0.1.180".length > 0) {
52994
+ return telemetryVersion("0.1.180");
52700
52995
  }
52701
52996
  const packageJsonPath = import_node_path11.default.resolve(import_node_path11.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url)), "..", "package.json");
52702
52997
  if (!(0, import_node_fs9.existsSync)(packageJsonPath)) return telemetryVersion("0.0.0");
@@ -52704,8 +52999,8 @@ function readServerPackageVersion() {
52704
52999
  }
52705
53000
 
52706
53001
  // ../server/src/server-store.ts
52707
- var import_node_fs11 = require("node:fs");
52708
- var import_node_path14 = __toESM(require("node:path"), 1);
53002
+ var import_node_fs13 = require("node:fs");
53003
+ var import_node_path16 = __toESM(require("node:path"), 1);
52709
53004
 
52710
53005
  // ../server/src/file-watcher.ts
52711
53006
  var import_node_events = require("node:events");
@@ -52880,31 +53175,524 @@ var defaultWatchContentFile = (filePath, onChange, basenames, options) => {
52880
53175
  return new ReArmingContentWatcher(filePath, onChange, basenames, options);
52881
53176
  };
52882
53177
 
52883
- // ../server/src/onboarding.ts
53178
+ // ../server/src/onboarding-installer.ts
53179
+ var import_node_fs12 = require("node:fs");
53180
+ var import_node_path15 = __toESM(require("node:path"), 1);
53181
+
53182
+ // ../server/src/onboarding-content.ts
52884
53183
  var import_node_fs10 = require("node:fs");
52885
53184
  var import_node_path13 = __toESM(require("node:path"), 1);
52886
- var import_node_url2 = require("node:url");
52887
- var import_meta2 = {};
53185
+ var ONBOARDING_CONFIG_FILENAME = "onboarding-screens.json";
53186
+ var ONBOARDING_ARTIFACT_ID_PREFIX = "television-onboarding";
53187
+ function onboardingArtifactID(screenSlug, artifactSlug) {
53188
+ return `${ONBOARDING_ARTIFACT_ID_PREFIX}--${screenSlug}--${artifactSlug}`;
53189
+ }
53190
+ function buildOnboardingScreenLayout(screenSlug, layout) {
53191
+ const substituteCard = (card) => createCardNode(onboardingArtifactID(screenSlug, card.slug), {
53192
+ ...card.width !== void 0 ? { width: card.width } : {},
53193
+ ...card.height !== void 0 ? { height: card.height } : {}
53194
+ });
53195
+ return layout.map((node) => {
53196
+ switch (node.type) {
53197
+ case "card":
53198
+ return substituteCard(node);
53199
+ case "row":
53200
+ return { id: node.id, type: "row", height: node.height, children: node.children.map(substituteCard) };
53201
+ case "stack":
53202
+ return {
53203
+ id: node.id,
53204
+ type: "stack",
53205
+ children: node.children.map(
53206
+ (child) => child.type === "card" ? substituteCard(child) : { id: child.id, type: "row", height: child.height, children: child.children.map(substituteCard) }
53207
+ )
53208
+ };
53209
+ }
53210
+ });
53211
+ }
53212
+ var ONBOARDING_SLUG_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
53213
+ function isValidOnboardingSlug(slug) {
53214
+ return ONBOARDING_SLUG_PATTERN.test(slug) && !slug.includes("--");
53215
+ }
53216
+ function loadOnboardingConfig(contentRoot) {
53217
+ const configPath = import_node_path13.default.join(contentRoot, ONBOARDING_CONFIG_FILENAME);
53218
+ let raw;
53219
+ try {
53220
+ raw = (0, import_node_fs10.readFileSync)(configPath, "utf8");
53221
+ } catch (error48) {
53222
+ return { errors: [`cannot read ${ONBOARDING_CONFIG_FILENAME}: ${describeError(error48)}`] };
53223
+ }
53224
+ let parsed;
53225
+ try {
53226
+ parsed = JSON.parse(raw);
53227
+ } catch (error48) {
53228
+ return { errors: [`failed to parse ${ONBOARDING_CONFIG_FILENAME}: ${describeError(error48)}`] };
53229
+ }
53230
+ const errors = validateConfigSchema(parsed);
53231
+ if (errors.length > 0) {
53232
+ return { errors };
53233
+ }
53234
+ return { config: parsed, errors: [] };
53235
+ }
53236
+ function resolveOnboardingArtifactSource(contentRoot, screenSlug, artifactSlug) {
53237
+ const label = `artifact "${artifactSlug}" in screen "${screenSlug}"`;
53238
+ const screenDir = import_node_path13.default.join(contentRoot, screenSlug);
53239
+ const shapes = [];
53240
+ for (const extension2 of [".html", ".md"]) {
53241
+ const candidate = import_node_path13.default.join(screenDir, `${artifactSlug}${extension2}`);
53242
+ if (isFile(candidate)) {
53243
+ shapes.push({ kind: "file", path: candidate, display: `${artifactSlug}${extension2}` });
53244
+ }
53245
+ }
53246
+ const dirPath = import_node_path13.default.join(screenDir, artifactSlug);
53247
+ if (isDirectory(dirPath)) {
53248
+ shapes.push({ kind: "directory", path: dirPath, display: `${artifactSlug}/` });
53249
+ }
53250
+ if (shapes.length > 1) {
53251
+ return {
53252
+ ok: false,
53253
+ error: `${label} is ambiguous: more than one source shape exists (${shapes.map((shape2) => shape2.display).join(", ")})`
53254
+ };
53255
+ }
53256
+ const shape = shapes[0];
53257
+ if (shape === void 0) {
53258
+ return {
53259
+ ok: false,
53260
+ error: `${label} has no source: expected ${artifactSlug}.html, ${artifactSlug}.md, or ${artifactSlug}/`
53261
+ };
53262
+ }
53263
+ if (shape.kind === "directory" && !isFile(import_node_path13.default.join(shape.path, "index.html"))) {
53264
+ return { ok: false, error: `${label} is a directory artifact missing index.html at its root` };
53265
+ }
53266
+ return { ok: true, source: { kind: shape.kind, path: shape.path } };
53267
+ }
53268
+ function validateConfigSchema(parsed) {
53269
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
53270
+ return [`${ONBOARDING_CONFIG_FILENAME} must be a JSON object`];
53271
+ }
53272
+ const config2 = parsed;
53273
+ const errors = [];
53274
+ if (config2.version !== 1) {
53275
+ errors.push(`config version must be 1, got ${JSON.stringify(config2.version)}`);
53276
+ }
53277
+ if (typeof config2.focusScreen !== "string") {
53278
+ errors.push("focusScreen must be a screen slug string");
53279
+ }
53280
+ if (!Array.isArray(config2.screens) || config2.screens.length === 0) {
53281
+ errors.push("screens must be a non-empty array");
53282
+ return errors;
53283
+ }
53284
+ const screenSlugs = /* @__PURE__ */ new Set();
53285
+ for (const [index, rawScreen] of config2.screens.entries()) {
53286
+ errors.push(...validateScreenSchema(rawScreen, index, screenSlugs));
53287
+ }
53288
+ if (typeof config2.focusScreen === "string" && !screenSlugs.has(config2.focusScreen)) {
53289
+ errors.push(`focusScreen "${config2.focusScreen}" does not name a configured screen`);
53290
+ }
53291
+ return errors;
53292
+ }
53293
+ function validateScreenSchema(rawScreen, index, screenSlugs) {
53294
+ if (typeof rawScreen !== "object" || rawScreen === null) {
53295
+ return [`screens[${index}] must be an object`];
53296
+ }
53297
+ const screen = rawScreen;
53298
+ const errors = [];
53299
+ const slugLabel = typeof screen.slug === "string" ? `"${screen.slug}"` : `at index ${index}`;
53300
+ if (typeof screen.slug !== "string" || !isValidOnboardingSlug(screen.slug)) {
53301
+ errors.push(
53302
+ `screen ${slugLabel} has an invalid slug: must match ${ONBOARDING_SLUG_PATTERN} with no "--"`
53303
+ );
53304
+ } else if (screenSlugs.has(screen.slug)) {
53305
+ errors.push(`duplicate screen slug "${screen.slug}"`);
53306
+ } else {
53307
+ screenSlugs.add(screen.slug);
53308
+ }
53309
+ if (typeof screen.name !== "string" || screen.name.trim().length === 0) {
53310
+ errors.push(`screen ${slugLabel} must have a non-empty name`);
53311
+ }
53312
+ if (!Array.isArray(screen.artifacts)) {
53313
+ errors.push(`screen ${slugLabel} must have an artifacts array`);
53314
+ return errors;
53315
+ }
53316
+ const artifactSlugs = /* @__PURE__ */ new Set();
53317
+ for (const [artifactIndex, rawArtifact] of screen.artifacts.entries()) {
53318
+ errors.push(...validateArtifactSchema(rawArtifact, slugLabel, artifactIndex, artifactSlugs));
53319
+ }
53320
+ errors.push(...validateScreenLayoutSchema(screen, slugLabel, artifactSlugs));
53321
+ return errors;
53322
+ }
53323
+ function validateScreenLayoutSchema(screen, slugLabel, artifactSlugs) {
53324
+ if (!Array.isArray(screen.layout)) {
53325
+ return [`screen ${slugLabel} must have a layout array`];
53326
+ }
53327
+ const errors = [];
53328
+ const placedSlugs = [];
53329
+ for (const rawNode of screen.layout) {
53330
+ errors.push(...validateLayoutNodeShape(rawNode, slugLabel, placedSlugs));
53331
+ }
53332
+ if (errors.length > 0) {
53333
+ return errors;
53334
+ }
53335
+ const screenSlug = typeof screen.slug === "string" ? screen.slug : "";
53336
+ const substituted = buildOnboardingScreenLayout(screenSlug, screen.layout);
53337
+ const layoutValidation = validateLayout(substituted);
53338
+ errors.push(...layoutValidation.errors.map((error48) => `screen ${slugLabel} layout is invalid: ${error48}`));
53339
+ const placed = new Set(placedSlugs);
53340
+ for (const slug of placed) {
53341
+ if (!artifactSlugs.has(slug)) {
53342
+ errors.push(`screen ${slugLabel} layout card references unconfigured artifact "${slug}"`);
53343
+ }
53344
+ }
53345
+ for (const slug of artifactSlugs) {
53346
+ if (!placed.has(slug)) {
53347
+ errors.push(`screen ${slugLabel} artifact "${slug}" is absent from the layout`);
53348
+ }
53349
+ }
53350
+ return errors;
53351
+ }
53352
+ function validateLayoutNodeShape(rawNode, slugLabel, placedSlugs) {
53353
+ if (typeof rawNode !== "object" || rawNode === null || Array.isArray(rawNode)) {
53354
+ return [`screen ${slugLabel} layout contains a non-object node`];
53355
+ }
53356
+ const node = rawNode;
53357
+ switch (node.type) {
53358
+ case "card":
53359
+ return validateCardNodeShape(node, slugLabel, placedSlugs);
53360
+ case "row":
53361
+ return validateRowNodeShape(node, slugLabel, placedSlugs);
53362
+ case "stack": {
53363
+ const errors = checkNodeKeys(node, ["id", "type", "children"], `screen ${slugLabel} layout stack`);
53364
+ if (!Array.isArray(node.children)) {
53365
+ errors.push(`screen ${slugLabel} layout stack must have a children array`);
53366
+ return errors;
53367
+ }
53368
+ for (const child of node.children) {
53369
+ const childNode = typeof child === "object" && child !== null ? child : void 0;
53370
+ if (childNode?.type === "card") {
53371
+ errors.push(...validateCardNodeShape(childNode, slugLabel, placedSlugs));
53372
+ } else if (childNode?.type === "row") {
53373
+ errors.push(...validateRowNodeShape(childNode, slugLabel, placedSlugs));
53374
+ } else {
53375
+ errors.push(`screen ${slugLabel} layout stack children must be card or row nodes`);
53376
+ }
53377
+ }
53378
+ return errors;
53379
+ }
53380
+ default:
53381
+ return [`screen ${slugLabel} layout node has unknown type ${JSON.stringify(node.type)}`];
53382
+ }
53383
+ }
53384
+ function validateCardNodeShape(node, slugLabel, placedSlugs) {
53385
+ const errors = checkNodeKeys(node, ["type", "slug", "width", "height"], `screen ${slugLabel} layout card`);
53386
+ if (typeof node.slug !== "string" || node.slug.length === 0) {
53387
+ errors.push(`screen ${slugLabel} layout card must reference an artifact slug`);
53388
+ } else {
53389
+ placedSlugs.push(node.slug);
53390
+ }
53391
+ return errors;
53392
+ }
53393
+ function validateRowNodeShape(node, slugLabel, placedSlugs) {
53394
+ const errors = checkNodeKeys(node, ["id", "type", "height", "children"], `screen ${slugLabel} layout row`);
53395
+ if (!Array.isArray(node.children)) {
53396
+ errors.push(`screen ${slugLabel} layout row must have a children array`);
53397
+ return errors;
53398
+ }
53399
+ for (const child of node.children) {
53400
+ const childNode = typeof child === "object" && child !== null ? child : void 0;
53401
+ if (childNode?.type === "card") {
53402
+ errors.push(...validateCardNodeShape(childNode, slugLabel, placedSlugs));
53403
+ } else {
53404
+ errors.push(`screen ${slugLabel} layout row children must be card nodes`);
53405
+ }
53406
+ }
53407
+ return errors;
53408
+ }
53409
+ function checkNodeKeys(node, allowed, label) {
53410
+ const unknownKeys = Object.keys(node).filter((key) => !allowed.includes(key));
53411
+ if (unknownKeys.length > 0) {
53412
+ return [`${label} has unknown fields: ${unknownKeys.join(", ")} (only ${allowed.join("/")} are allowed)`];
53413
+ }
53414
+ return [];
53415
+ }
53416
+ function validateArtifactSchema(rawArtifact, screenLabel, index, artifactSlugs) {
53417
+ if (typeof rawArtifact !== "object" || rawArtifact === null) {
53418
+ return [`artifact at index ${index} in screen ${screenLabel} must be an object`];
53419
+ }
53420
+ const artifact = rawArtifact;
53421
+ const errors = [];
53422
+ const slugLabel = typeof artifact.slug === "string" ? `"${artifact.slug}"` : `at index ${index}`;
53423
+ const label = `artifact ${slugLabel} in screen ${screenLabel}`;
53424
+ if (typeof artifact.slug !== "string" || !isValidOnboardingSlug(artifact.slug)) {
53425
+ errors.push(`${label} has an invalid slug: must match ${ONBOARDING_SLUG_PATTERN} with no "--"`);
53426
+ } else if (artifactSlugs.has(artifact.slug)) {
53427
+ errors.push(`duplicate artifact slug "${artifact.slug}" in screen ${screenLabel}`);
53428
+ } else {
53429
+ artifactSlugs.add(artifact.slug);
53430
+ }
53431
+ if (typeof artifact.title !== "string" || artifact.title.trim().length === 0) {
53432
+ errors.push(`${label} must have a non-empty title`);
53433
+ }
53434
+ return errors;
53435
+ }
53436
+ function isFile(candidate) {
53437
+ return (0, import_node_fs10.existsSync)(candidate) && (0, import_node_fs10.statSync)(candidate).isFile();
53438
+ }
53439
+ function isDirectory(candidate) {
53440
+ return (0, import_node_fs10.existsSync)(candidate) && (0, import_node_fs10.statSync)(candidate).isDirectory();
53441
+ }
53442
+ function describeError(error48) {
53443
+ return error48 instanceof Error ? error48.message : String(error48);
53444
+ }
53445
+
53446
+ // ../server/src/onboarding-state.ts
53447
+ var import_node_fs11 = require("node:fs");
53448
+ var import_node_path14 = __toESM(require("node:path"), 1);
53449
+
53450
+ // ../server/src/onboarding.ts
52888
53451
  var ONBOARDING_ARTIFACT_ID = "television-onboarding";
52889
- var ONBOARDING_SCREEN_NAME = "TV Guide";
52890
- var ONBOARDING_ARTIFACT_TITLE = "Welcome to Television";
52891
- var ONBOARDING_ARTIFACT_DIRNAME = "television-onboarding";
52892
- var ONBOARDING_ARTIFACT_SENTINEL_VERSION = 1;
52893
- function getDefaultOnboardingArtifactSourcePath() {
52894
- const moduleURL = import_meta2.url;
52895
- if (typeof moduleURL !== "string") {
53452
+
53453
+ // ../server/src/onboarding-state.ts
53454
+ var JSON_INDENT_SPACES = 2;
53455
+ function readOnboardingStateFile(storagePath) {
53456
+ const statePath = getOnboardingStatePath(storagePath);
53457
+ if (!(0, import_node_fs11.existsSync)(statePath)) {
53458
+ return { status: "absent" };
53459
+ }
53460
+ const parsed = parseJSONFile(statePath);
53461
+ if (!parsed.ok) {
53462
+ return { status: "invalid", error: parsed.error };
53463
+ }
53464
+ const state = parseV2State(parsed.value);
53465
+ return state !== void 0 ? { status: "ok", state } : { status: "invalid", error: `not a version 2 onboarding state payload: ${statePath}` };
53466
+ }
53467
+ function readLegacyOnboardingFile(storagePath) {
53468
+ const legacyPath = getOnboardingArtifactSentinelPath(storagePath);
53469
+ if (!(0, import_node_fs11.existsSync)(legacyPath)) {
53470
+ return { status: "absent" };
53471
+ }
53472
+ const parsed = parseJSONFile(legacyPath);
53473
+ if (!parsed.ok) {
53474
+ return { status: "invalid", error: parsed.error };
53475
+ }
53476
+ const v2 = parseV2State(parsed.value);
53477
+ if (v2 !== void 0) {
53478
+ return { status: "v2", state: v2 };
53479
+ }
53480
+ const value = parsed.value;
53481
+ if (typeof value === "object" && value !== null && value.version === 1) {
53482
+ if (value.artifactID !== ONBOARDING_ARTIFACT_ID) {
53483
+ return { status: "invalid", error: `not a recognized onboarding payload: ${legacyPath}` };
53484
+ }
53485
+ const installedAt = value.installedAt;
53486
+ return {
53487
+ status: "v1",
53488
+ installedAt: isUsableTimestamp(installedAt) ? installedAt : void 0
53489
+ };
53490
+ }
53491
+ return { status: "invalid", error: `not a recognized onboarding payload: ${legacyPath}` };
53492
+ }
53493
+ function getOnboardingStateTempPath(storagePath) {
53494
+ const statePath = getOnboardingStatePath(storagePath);
53495
+ return import_node_path14.default.join(import_node_path14.default.dirname(statePath), `.${import_node_path14.default.basename(statePath)}.tmp-${process.pid}`);
53496
+ }
53497
+ function writeOnboardingStateFile(storagePath, state) {
53498
+ const statePath = getOnboardingStatePath(storagePath);
53499
+ const tempPath = getOnboardingStateTempPath(storagePath);
53500
+ try {
53501
+ (0, import_node_fs11.writeFileSync)(tempPath, JSON.stringify(state, null, JSON_INDENT_SPACES));
53502
+ (0, import_node_fs11.renameSync)(tempPath, statePath);
53503
+ } catch (error48) {
53504
+ try {
53505
+ (0, import_node_fs11.rmSync)(tempPath, { force: true });
53506
+ } catch {
53507
+ }
53508
+ throw error48;
53509
+ }
53510
+ }
53511
+ function parseJSONFile(filePath) {
53512
+ let raw;
53513
+ try {
53514
+ raw = (0, import_node_fs11.readFileSync)(filePath, "utf8");
53515
+ } catch (error48) {
53516
+ return { ok: false, error: `cannot read ${filePath}: ${describeError2(error48)}` };
53517
+ }
53518
+ try {
53519
+ return { ok: true, value: JSON.parse(raw) };
53520
+ } catch (error48) {
53521
+ return { ok: false, error: `cannot parse ${filePath}: ${describeError2(error48)}` };
53522
+ }
53523
+ }
53524
+ function parseV2State(value) {
53525
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
52896
53526
  return void 0;
52897
53527
  }
52898
- const sourcePath = import_node_path13.default.resolve(
52899
- import_node_path13.default.dirname((0, import_node_url2.fileURLToPath)(moduleURL)),
52900
- "../assets",
52901
- ONBOARDING_ARTIFACT_DIRNAME
52902
- );
52903
- return (0, import_node_fs10.existsSync)(sourcePath) ? sourcePath : void 0;
53528
+ const candidate = value;
53529
+ if (candidate.version !== 2) {
53530
+ return void 0;
53531
+ }
53532
+ if (typeof candidate.screens !== "object" || candidate.screens === null || Array.isArray(candidate.screens)) {
53533
+ return void 0;
53534
+ }
53535
+ const screens = {};
53536
+ for (const [slug, record2] of Object.entries(candidate.screens)) {
53537
+ if (!isValidOnboardingSlug(slug)) {
53538
+ return void 0;
53539
+ }
53540
+ if (typeof record2 !== "object" || record2 === null || !isUsableTimestamp(record2.installedAt)) {
53541
+ return void 0;
53542
+ }
53543
+ screens[slug] = { installedAt: record2.installedAt };
53544
+ }
53545
+ return { version: 2, screens };
53546
+ }
53547
+ function isUsableTimestamp(value) {
53548
+ return typeof value === "string" && !Number.isNaN(Date.parse(value));
53549
+ }
53550
+ function describeError2(error48) {
53551
+ return error48 instanceof Error ? error48.message : String(error48);
53552
+ }
53553
+
53554
+ // ../server/src/onboarding-installer.ts
53555
+ var MIGRATED_TV_GUIDE_SLUG = "tv-guide";
53556
+ function runOnboardingBootstrap(target, contentPath) {
53557
+ let state;
53558
+ try {
53559
+ const migrated = migrateOnboardingState(target);
53560
+ if (migrated === void 0) {
53561
+ return { focusScreenID: void 0 };
53562
+ }
53563
+ state = migrated;
53564
+ } catch (error48) {
53565
+ console.warn("Onboarding state migration failed; skipping onboarding install for this boot.", error48);
53566
+ return { focusScreenID: void 0 };
53567
+ }
53568
+ if (contentPath === void 0) {
53569
+ return { focusScreenID: void 0 };
53570
+ }
53571
+ const { config: config2, errors } = loadOnboardingConfig(contentPath);
53572
+ if (!config2) {
53573
+ console.warn(
53574
+ `Onboarding config at ${contentPath} is unusable; skipping onboarding install for this boot.
53575
+ ` + errors.map((error48) => ` - ${error48}`).join("\n")
53576
+ );
53577
+ return { focusScreenID: void 0 };
53578
+ }
53579
+ const completed = /* @__PURE__ */ new Map();
53580
+ for (const [index, screenConfig] of config2.screens.entries()) {
53581
+ if (state.screens[screenConfig.slug] !== void 0) {
53582
+ continue;
53583
+ }
53584
+ try {
53585
+ const screenID = installScreen(target, contentPath, screenConfig, index);
53586
+ const nextState = {
53587
+ version: 2,
53588
+ screens: {
53589
+ ...state.screens,
53590
+ [screenConfig.slug]: { installedAt: (/* @__PURE__ */ new Date()).toISOString() }
53591
+ }
53592
+ };
53593
+ writeOnboardingStateFile(target.storagePath, nextState);
53594
+ state = nextState;
53595
+ completed.set(screenConfig.slug, screenID);
53596
+ } catch (error48) {
53597
+ console.warn(
53598
+ `Failed to install onboarding screen "${screenConfig.slug}"; it will retry on the next boot.`,
53599
+ error48
53600
+ );
53601
+ }
53602
+ }
53603
+ return { focusScreenID: completed.get(config2.focusScreen) };
53604
+ }
53605
+ function migrateOnboardingState(target) {
53606
+ const existing = readOnboardingStateFile(target.storagePath);
53607
+ if (existing.status === "ok") {
53608
+ return existing.state;
53609
+ }
53610
+ if (existing.status === "invalid") {
53611
+ console.warn(
53612
+ `Onboarding state file is unreadable; skipping onboarding install for this boot rather than risking a duplicate install. ${existing.error}`
53613
+ );
53614
+ return void 0;
53615
+ }
53616
+ const legacy = readLegacyOnboardingFile(target.storagePath);
53617
+ switch (legacy.status) {
53618
+ case "v1": {
53619
+ const state = {
53620
+ version: 2,
53621
+ screens: {
53622
+ [MIGRATED_TV_GUIDE_SLUG]: { installedAt: legacy.installedAt ?? (/* @__PURE__ */ new Date()).toISOString() }
53623
+ }
53624
+ };
53625
+ writeOnboardingStateFile(target.storagePath, state);
53626
+ return state;
53627
+ }
53628
+ case "v2": {
53629
+ writeOnboardingStateFile(target.storagePath, legacy.state);
53630
+ return legacy.state;
53631
+ }
53632
+ case "invalid":
53633
+ console.warn(
53634
+ `Legacy onboarding sentinel is unreadable; skipping onboarding install for this boot rather than risking a duplicate install. ${legacy.error}`
53635
+ );
53636
+ return void 0;
53637
+ case "absent": {
53638
+ if (target.hasArtifact(ONBOARDING_ARTIFACT_ID)) {
53639
+ const state = {
53640
+ version: 2,
53641
+ screens: { [MIGRATED_TV_GUIDE_SLUG]: { installedAt: (/* @__PURE__ */ new Date()).toISOString() } }
53642
+ };
53643
+ writeOnboardingStateFile(target.storagePath, state);
53644
+ return state;
53645
+ }
53646
+ return { version: 2, screens: {} };
53647
+ }
53648
+ }
53649
+ }
53650
+ function installScreen(target, contentPath, screenConfig, configIndex) {
53651
+ const existing = target.listScreens().find((screen2) => screen2.onboarding?.slug === screenConfig.slug);
53652
+ const screen = existing ?? target.createScreen({
53653
+ name: screenConfig.name,
53654
+ onboarding: { slug: screenConfig.slug, order: configIndex }
53655
+ });
53656
+ const copies = [];
53657
+ for (const artifactConfig of screenConfig.artifacts) {
53658
+ const resolved = resolveOnboardingArtifactSource(contentPath, screenConfig.slug, artifactConfig.slug);
53659
+ if (!resolved.ok) {
53660
+ throw new Error(resolved.error);
53661
+ }
53662
+ const artifactID = onboardingArtifactID(screenConfig.slug, artifactConfig.slug);
53663
+ const artifactsDir = getAgentArtifactsDir(target.storagePath);
53664
+ if (resolved.source.kind === "file") {
53665
+ const destination = import_node_path15.default.join(artifactsDir, `${artifactID}${import_node_path15.default.extname(resolved.source.path)}`);
53666
+ (0, import_node_fs12.rmSync)(destination, { recursive: true, force: true });
53667
+ (0, import_node_fs12.cpSync)(resolved.source.path, destination);
53668
+ copies.push({ artifactConfig, artifactID, destination });
53669
+ } else {
53670
+ const destinationDir = import_node_path15.default.join(artifactsDir, artifactID);
53671
+ if ((0, import_node_fs12.existsSync)(destinationDir)) {
53672
+ (0, import_node_fs12.rmSync)(destinationDir, { recursive: true, force: true });
53673
+ }
53674
+ (0, import_node_fs12.cpSync)(resolved.source.path, destinationDir, { recursive: true });
53675
+ copies.push({ artifactConfig, artifactID, destination: destinationDir + import_node_path15.default.sep });
53676
+ }
53677
+ }
53678
+ for (const { artifactConfig, artifactID, destination } of copies) {
53679
+ if (target.hasArtifact(artifactID)) {
53680
+ continue;
53681
+ }
53682
+ target.createArtifact({
53683
+ id: artifactID,
53684
+ kind: "path",
53685
+ title: artifactConfig.title,
53686
+ screenID: screen.id,
53687
+ path: destination
53688
+ });
53689
+ }
53690
+ target.setScreenLayout(screen.id, buildOnboardingScreenLayout(screenConfig.slug, screenConfig.layout));
53691
+ return screen.id;
52904
53692
  }
52905
53693
 
52906
53694
  // ../server/src/server-store.ts
52907
- var JSON_INDENT_SPACES = 2;
53695
+ var JSON_INDENT_SPACES2 = 2;
52908
53696
  var CONTENT_WATCH_DEBOUNCE_MS = 100;
52909
53697
  var JSON_FILE_SUFFIX = ".json";
52910
53698
  var DIRECTORY_INDEX_BASENAMES = ["index.html", "index.htm"];
@@ -52916,12 +53704,13 @@ function hasExistingTelevisionDataStructure(storagePath) {
52916
53704
  return [
52917
53705
  getDisplayStatePath(storagePath),
52918
53706
  getTokenPath(storagePath),
53707
+ getOnboardingStatePath(storagePath),
52919
53708
  getOnboardingArtifactSentinelPath(storagePath),
52920
53709
  getScreensDir(storagePath),
52921
53710
  getArtifactsMetadataDir(storagePath),
52922
53711
  getThemesDir(storagePath),
52923
53712
  getAgentArtifactsDir(storagePath)
52924
- ].some((markerPath) => (0, import_node_fs11.existsSync)(markerPath));
53713
+ ].some((markerPath) => (0, import_node_fs13.existsSync)(markerPath));
52925
53714
  }
52926
53715
  function artifactWatchTarget(artifact) {
52927
53716
  if (artifact.kind === "url") {
@@ -52951,30 +53740,55 @@ var ServerStore = class extends EventTarget {
52951
53740
  themeWatchDebounceTimer = null;
52952
53741
  watchContentFile;
52953
53742
  bundledViewsPath;
52954
- onboardingArtifactSourcePath;
53743
+ onboardingContentPath;
53744
+ serving;
53745
+ // True only while the constructor's install phase runs: content watchers
53746
+ // must not start before the final bootstrap step
53747
+ // (specs/arch/onboarding/installer.md#^bootstrap-sequence step 7).
53748
+ inBootstrapInstall = false;
52955
53749
  telemetryHooks = null;
53750
+ // The serving bootstrap sequence and the token-only cutoff are spec'd:
53751
+ // specs/arch/onboarding/installer.md#^bootstrap-sequence, #^token-only-boot.
52956
53752
  constructor(options) {
52957
53753
  super();
52958
- this.storagePath = options.storagePath;
53754
+ this.storagePath = import_node_path16.default.resolve(options.storagePath);
52959
53755
  this.dataDirCreated = !hasExistingTelevisionDataStructure(options.storagePath);
52960
53756
  this.watchContentFile = options.watchContentFile ?? defaultWatchContentFile;
52961
53757
  this.bundledViewsPath = options.bundledViewsPath;
52962
- this.onboardingArtifactSourcePath = options.onboardingArtifactSourcePath ?? getDefaultOnboardingArtifactSourcePath();
53758
+ this.onboardingContentPath = options.onboardingContentPath;
53759
+ this.serving = options.installOnboardingScreens === true;
52963
53760
  this.ensureDirectories();
52964
53761
  this.authToken = this.loadOrCreateAuthToken();
52965
53762
  this.load();
52966
53763
  this.rebuildArtifactScreens();
52967
- const installOnboardingArtifact = options.installOnboardingArtifact === true;
53764
+ if (!this.serving) {
53765
+ return;
53766
+ }
53767
+ const noContentAtBoot = this._artifacts.size === 0 && [...this.screens.values()].every((screen) => screen.layout.length === 0);
53768
+ this.inBootstrapInstall = true;
53769
+ const onboarding = runOnboardingBootstrap(
53770
+ {
53771
+ storagePath: this.storagePath,
53772
+ listScreens: () => this.listScreens(),
53773
+ hasArtifact: (id) => this._artifacts.has(id),
53774
+ createScreen: (input) => this.createScreen(input),
53775
+ createArtifact: (input) => this.createArtifact(input),
53776
+ setScreenLayout: (screenID, layout) => this.setScreenLayoutForInstall(screenID, layout)
53777
+ },
53778
+ this.onboardingContentPath
53779
+ );
53780
+ this.inBootstrapInstall = false;
52968
53781
  if (this.screens.size === 0) {
52969
- this.createDefaultScreen({
52970
- name: installOnboardingArtifact && this.canInstallOnboardingArtifact() ? ONBOARDING_SCREEN_NAME : "Default"
52971
- });
53782
+ this.createScreen({ name: "Default" });
52972
53783
  }
52973
53784
  if (!this.loadDisplayState()) {
52974
53785
  this.initializeDisplayState();
52975
53786
  }
52976
- if (installOnboardingArtifact) {
52977
- this.installOnboardingArtifactIfNeeded();
53787
+ if (noContentAtBoot && onboarding.focusScreenID !== void 0 && this.screens.has(onboarding.focusScreenID)) {
53788
+ this.patchDisplay({ activeScreenID: onboarding.focusScreenID });
53789
+ }
53790
+ for (const artifact of this._artifacts.values()) {
53791
+ this.startWatchingArtifactContent(artifact);
52978
53792
  }
52979
53793
  this.startWatchingActiveTheme();
52980
53794
  }
@@ -52988,8 +53802,8 @@ var ServerStore = class extends EventTarget {
52988
53802
  if (!isBundledViewID(id) || this.bundledViewsPath === void 0) {
52989
53803
  return null;
52990
53804
  }
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;
53805
+ const viewPath = import_node_path16.default.join(this.bundledViewsPath, id);
53806
+ return (0, import_node_fs13.existsSync)(import_node_path16.default.join(viewPath, "index.html")) ? viewPath : null;
52993
53807
  }
52994
53808
  getScreen(id) {
52995
53809
  const screen = this.screens.get(id);
@@ -53021,7 +53835,7 @@ var ServerStore = class extends EventTarget {
53021
53835
  this.persistScreen(screen);
53022
53836
  } catch (error48) {
53023
53837
  screen.layout = previousLayout;
53024
- (0, import_node_fs11.rmSync)(getArtifactLiveMetadataPath(this.storagePath, artifact.id), { force: true });
53838
+ (0, import_node_fs13.rmSync)(getArtifactLiveMetadataPath(this.storagePath, artifact.id), { force: true });
53025
53839
  throw error48;
53026
53840
  }
53027
53841
  this._artifacts.set(artifact.id, artifact);
@@ -53102,18 +53916,21 @@ var ServerStore = class extends EventTarget {
53102
53916
  }
53103
53917
  this.stopWatchingArtifactContent(artifactID);
53104
53918
  this._artifacts.delete(artifactID);
53105
- (0, import_node_fs11.rmSync)(getArtifactLiveMetadataPath(this.storagePath, artifactID), { force: true });
53919
+ (0, import_node_fs13.rmSync)(getArtifactLiveMetadataPath(this.storagePath, artifactID), { force: true });
53106
53920
  if (screenID !== void 0) {
53107
53921
  this.dispatchEvent(new ArtifactRemovedEvent("artifact-removed", { artifactID, screenID }));
53108
53922
  }
53109
53923
  this.emitTelemetry((hooks) => hooks.artifactDeleted(artifact, telemetryContext));
53110
53924
  return artifact.kind === "path" ? { outcome: "deleted", kind: "path", artifactID, path: artifact.path } : { outcome: "deleted", kind: "url", artifactID, url: artifact.url };
53111
53925
  }
53926
+ // `onboarding` is installer-only: routes never forward the field from
53927
+ // public request bodies (specs/arch/onboarding/tab-promotion.md#^marker-api-readonly).
53112
53928
  createScreen(input, telemetryContext) {
53113
53929
  const screen = {
53114
53930
  id: input.id ?? ulid3(),
53115
53931
  name: input.name,
53116
- layout: []
53932
+ layout: [],
53933
+ ...input.onboarding ? { onboarding: input.onboarding } : {}
53117
53934
  };
53118
53935
  this.screens.set(screen.id, screen);
53119
53936
  this.persistScreen(screen);
@@ -53239,8 +54056,8 @@ var ServerStore = class extends EventTarget {
53239
54056
  const previousActiveScreenID = this.getActiveScreenID();
53240
54057
  const artifactIDs = [...new Set(getScreenArtifactIDs(screen))];
53241
54058
  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 });
54059
+ const metadataPath = import_node_path16.default.join(this.screensDir, `${screen.id}.json`);
54060
+ (0, import_node_fs13.rmSync)(metadataPath, { force: true });
53244
54061
  this.screens.delete(screen.id);
53245
54062
  this.dispatchEvent(new ScreenRemovedEvent("screen-removed", { screenID }));
53246
54063
  this.emitTelemetry((hooks) => hooks.screenDeleted(screen, telemetryContext));
@@ -53267,13 +54084,13 @@ var ServerStore = class extends EventTarget {
53267
54084
  }
53268
54085
  }
53269
54086
  load() {
53270
- if ((0, import_node_fs11.existsSync)(this.screensDir)) {
53271
- for (const file2 of (0, import_node_fs11.readdirSync)(this.screensDir)) {
54087
+ if ((0, import_node_fs13.existsSync)(this.screensDir)) {
54088
+ for (const file2 of (0, import_node_fs13.readdirSync)(this.screensDir)) {
53272
54089
  if (!file2.endsWith(JSON_FILE_SUFFIX)) continue;
53273
- const filePath = import_node_path14.default.join(this.screensDir, file2);
54090
+ const filePath = import_node_path16.default.join(this.screensDir, file2);
53274
54091
  let raw;
53275
54092
  try {
53276
- raw = JSON.parse((0, import_node_fs11.readFileSync)(filePath, "utf8"));
54093
+ raw = JSON.parse((0, import_node_fs13.readFileSync)(filePath, "utf8"));
53277
54094
  } catch (error48) {
53278
54095
  console.warn(`Skipping malformed JSON file: ${filePath}`, error48);
53279
54096
  continue;
@@ -53282,28 +54099,32 @@ var ServerStore = class extends EventTarget {
53282
54099
  console.warn(`Skipping malformed screen file: ${filePath}`);
53283
54100
  continue;
53284
54101
  }
54102
+ const onboarding = parseOnboardingMarker(raw.onboarding);
53285
54103
  this.screens.set(raw.id, {
53286
54104
  id: raw.id,
53287
54105
  name: raw.name,
53288
- layout: raw.layout
54106
+ layout: raw.layout,
54107
+ ...onboarding ? { onboarding } : {}
53289
54108
  });
53290
54109
  }
53291
54110
  }
53292
- if (!(0, import_node_fs11.existsSync)(this.artifactsDir)) {
54111
+ if (!(0, import_node_fs13.existsSync)(this.artifactsDir)) {
53293
54112
  return;
53294
54113
  }
53295
- for (const file2 of (0, import_node_fs11.readdirSync)(this.artifactsDir)) {
54114
+ for (const file2 of (0, import_node_fs13.readdirSync)(this.artifactsDir)) {
53296
54115
  if (!file2.endsWith(JSON_FILE_SUFFIX)) {
53297
54116
  continue;
53298
54117
  }
53299
54118
  const id = file2.slice(0, -JSON_FILE_SUFFIX.length);
53300
- const metadataPath = import_node_path14.default.join(this.artifactsDir, file2);
54119
+ const metadataPath = import_node_path16.default.join(this.artifactsDir, file2);
53301
54120
  const metadata = this.readArtifactFile(metadataPath, id);
53302
54121
  this._artifacts.set(id, metadata);
53303
- this.startWatchingArtifactContent(metadata);
53304
54122
  }
53305
54123
  }
53306
54124
  startWatchingArtifactContent(artifact) {
54125
+ if (this.inBootstrapInstall) {
54126
+ return;
54127
+ }
53307
54128
  this.stopWatchingArtifactContent(artifact.id);
53308
54129
  const target = artifactWatchTarget(artifact);
53309
54130
  if (target === null) {
@@ -53466,20 +54287,20 @@ var ServerStore = class extends EventTarget {
53466
54287
  * without statting.
53467
54288
  */
53468
54289
  normalizeArtifactPath(artifactPath) {
53469
- if (!import_node_path14.default.isAbsolute(artifactPath)) {
54290
+ if (!import_node_path16.default.isAbsolute(artifactPath)) {
53470
54291
  throw new InvalidRequestError("path must be absolute");
53471
54292
  }
53472
54293
  const stripped = stripTrailingSeparators(artifactPath);
53473
54294
  let stat;
53474
54295
  try {
53475
- (0, import_node_fs11.accessSync)(stripped, import_node_fs11.constants.R_OK);
53476
- stat = (0, import_node_fs11.statSync)(stripped);
54296
+ (0, import_node_fs13.accessSync)(stripped, import_node_fs13.constants.R_OK);
54297
+ stat = (0, import_node_fs13.statSync)(stripped);
53477
54298
  } catch {
53478
54299
  throw new InvalidRequestError(`path does not exist or is not readable: ${artifactPath}`);
53479
54300
  }
53480
54301
  if (stat.isDirectory()) {
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)))) {
54302
+ const canonical = hasTrailingSeparator(stripped) ? stripped : `${stripped}${import_node_path16.default.sep}`;
54303
+ if (!DIRECTORY_INDEX_BASENAMES.some((basename) => (0, import_node_fs13.existsSync)(import_node_path16.default.join(canonical, basename)))) {
53483
54304
  throw new InvalidRequestError(`directory artifact must contain index.html or index.htm: ${canonical}`);
53484
54305
  }
53485
54306
  return canonical;
@@ -53492,52 +54313,18 @@ var ServerStore = class extends EventTarget {
53492
54313
  }
53493
54314
  return stripped;
53494
54315
  }
53495
- canInstallOnboardingArtifact() {
53496
- return !(0, import_node_fs11.existsSync)(getOnboardingArtifactSentinelPath(this.storagePath)) && !this._artifacts.has(ONBOARDING_ARTIFACT_ID) && this.onboardingArtifactSourcePath !== void 0;
53497
- }
53498
- installOnboardingArtifactIfNeeded() {
53499
- try {
53500
- if ((0, import_node_fs11.existsSync)(getOnboardingArtifactSentinelPath(this.storagePath))) {
53501
- return;
53502
- }
53503
- if (this._artifacts.has(ONBOARDING_ARTIFACT_ID)) {
53504
- this.writeOnboardingArtifactSentinel();
53505
- return;
53506
- }
53507
- if (!this.onboardingArtifactSourcePath) {
53508
- console.warn("Skipping onboarding artifact install: bundled onboarding artifact was not found.");
53509
- return;
53510
- }
53511
- const screenID = this.resolveActiveScreenID(this.activeScreenID) ?? this.pickPreferredScreenID();
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 });
53515
- }
53516
- this.createArtifact({
53517
- id: ONBOARDING_ARTIFACT_ID,
53518
- kind: "path",
53519
- title: ONBOARDING_ARTIFACT_TITLE,
53520
- screenID,
53521
- path: onboardingPath,
53522
- card: { width: 5 }
53523
- });
53524
- this.writeOnboardingArtifactSentinel();
53525
- } catch (error48) {
53526
- console.warn("Failed to install onboarding artifact; continuing startup.", error48);
53527
- }
53528
- }
53529
- writeOnboardingArtifactSentinel() {
53530
- (0, import_node_fs11.writeFileSync)(
53531
- getOnboardingArtifactSentinelPath(this.storagePath),
53532
- JSON.stringify({
53533
- version: ONBOARDING_ARTIFACT_SENTINEL_VERSION,
53534
- artifactID: ONBOARDING_ARTIFACT_ID,
53535
- installedAt: (/* @__PURE__ */ new Date()).toISOString()
53536
- }, null, JSON_INDENT_SPACES)
53537
- );
53538
- }
53539
- createDefaultScreen(input) {
53540
- this.createScreen({ name: input.name });
54316
+ /**
54317
+ * Installer-only whole-layout write: an unmarked slug's screen layout is
54318
+ * always written whole from the configured tree, healing partial or missing
54319
+ * arrangements on retry
54320
+ * (specs/arch/onboarding/installer.md#^layout-write-unmarked). Not reachable
54321
+ * from the public API, which validates layouts at the route boundary.
54322
+ */
54323
+ setScreenLayoutForInstall(screenID, layout) {
54324
+ const screen = this.requireScreen(screenID);
54325
+ screen.layout = layout;
54326
+ this.persistScreen(screen);
54327
+ this.rebuildArtifactScreensForScreen(screen);
53541
54328
  }
53542
54329
  initializeDisplayState() {
53543
54330
  this.activeScreenID = this.pickPreferredScreenID();
@@ -53545,11 +54332,11 @@ var ServerStore = class extends EventTarget {
53545
54332
  this.persistDisplayState();
53546
54333
  }
53547
54334
  ensureDirectories() {
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 });
54335
+ (0, import_node_fs13.mkdirSync)(import_node_path16.default.join(this.storagePath, "state"), { recursive: true });
54336
+ (0, import_node_fs13.mkdirSync)(this.screensDir, { recursive: true });
54337
+ (0, import_node_fs13.mkdirSync)(this.artifactsDir, { recursive: true });
54338
+ (0, import_node_fs13.mkdirSync)(getThemesDir(this.storagePath), { recursive: true });
54339
+ (0, import_node_fs13.mkdirSync)(getAgentArtifactsDir(this.storagePath), { recursive: true });
53553
54340
  }
53554
54341
  rebuildArtifactScreens() {
53555
54342
  this.artifactScreens.clear();
@@ -53568,12 +54355,12 @@ var ServerStore = class extends EventTarget {
53568
54355
  }
53569
54356
  }
53570
54357
  loadDisplayState() {
53571
- if (!(0, import_node_fs11.existsSync)(this.displayStatePath)) {
54358
+ if (!(0, import_node_fs13.existsSync)(this.displayStatePath)) {
53572
54359
  return false;
53573
54360
  }
53574
54361
  let raw;
53575
54362
  try {
53576
- raw = (0, import_node_fs11.readFileSync)(this.displayStatePath, "utf8");
54363
+ raw = (0, import_node_fs13.readFileSync)(this.displayStatePath, "utf8");
53577
54364
  } catch {
53578
54365
  return false;
53579
54366
  }
@@ -53591,9 +54378,9 @@ var ServerStore = class extends EventTarget {
53591
54378
  return false;
53592
54379
  }
53593
54380
  persistDisplayState() {
53594
- (0, import_node_fs11.writeFileSync)(
54381
+ (0, import_node_fs13.writeFileSync)(
53595
54382
  this.displayStatePath,
53596
- JSON.stringify(this.getDisplayState(), null, JSON_INDENT_SPACES)
54383
+ JSON.stringify(this.getDisplayState(), null, JSON_INDENT_SPACES2)
53597
54384
  );
53598
54385
  }
53599
54386
  get displayStatePath() {
@@ -53613,11 +54400,11 @@ var ServerStore = class extends EventTarget {
53613
54400
  return firstScreen.id;
53614
54401
  }
53615
54402
  loadOrCreateAuthToken() {
53616
- if ((0, import_node_fs11.existsSync)(this.tokenPath)) {
53617
- return (0, import_node_fs11.readFileSync)(this.tokenPath, "utf8").trim();
54403
+ if ((0, import_node_fs13.existsSync)(this.tokenPath)) {
54404
+ return (0, import_node_fs13.readFileSync)(this.tokenPath, "utf8").trim();
53618
54405
  }
53619
54406
  const token = createToken();
53620
- (0, import_node_fs11.writeFileSync)(this.tokenPath, `${token}
54407
+ (0, import_node_fs13.writeFileSync)(this.tokenPath, `${token}
53621
54408
  `);
53622
54409
  return token;
53623
54410
  }
@@ -53625,12 +54412,12 @@ var ServerStore = class extends EventTarget {
53625
54412
  if (!this.screens.has(screen.id)) {
53626
54413
  throw new Error(`Cannot persist screen ${screen.id}: not in live map`);
53627
54414
  }
53628
- (0, import_node_fs11.writeFileSync)(import_node_path14.default.join(this.screensDir, `${screen.id}.json`), JSON.stringify(screen, null, JSON_INDENT_SPACES));
54415
+ (0, import_node_fs13.writeFileSync)(import_node_path16.default.join(this.screensDir, `${screen.id}.json`), JSON.stringify(screen, null, JSON_INDENT_SPACES2));
53629
54416
  }
53630
54417
  readArtifactFile(filePath, expectedID) {
53631
54418
  let raw;
53632
54419
  try {
53633
- raw = (0, import_node_fs11.readFileSync)(filePath, "utf8");
54420
+ raw = (0, import_node_fs13.readFileSync)(filePath, "utf8");
53634
54421
  } catch (error48) {
53635
54422
  throw this.invalidMetadataFile(filePath, "unreadable", error48);
53636
54423
  }
@@ -53652,7 +54439,7 @@ var ServerStore = class extends EventTarget {
53652
54439
  `id ${result.data.id} does not match filename ${expectedID}`
53653
54440
  );
53654
54441
  }
53655
- if (result.data.kind === "path" && !import_node_path14.default.isAbsolute(result.data.path)) {
54442
+ if (result.data.kind === "path" && !import_node_path16.default.isAbsolute(result.data.path)) {
53656
54443
  throw this.invalidMetadataFile(filePath, "path must be absolute");
53657
54444
  }
53658
54445
  return result.data;
@@ -53669,7 +54456,7 @@ Review docs/storage.md for the current schema, and either update the file to mat
53669
54456
  return cause !== void 0 ? new Error(message, { cause }) : new Error(message);
53670
54457
  }
53671
54458
  writeArtifact(artifact) {
53672
- (0, import_node_fs11.writeFileSync)(getArtifactLiveMetadataPath(this.storagePath, artifact.id), JSON.stringify(artifact, null, JSON_INDENT_SPACES));
54459
+ (0, import_node_fs13.writeFileSync)(getArtifactLiveMetadataPath(this.storagePath, artifact.id), JSON.stringify(artifact, null, JSON_INDENT_SPACES2));
53673
54460
  }
53674
54461
  get screensDir() {
53675
54462
  return getScreensDir(this.storagePath);
@@ -53681,6 +54468,12 @@ Review docs/storage.md for the current schema, and either update the file to mat
53681
54468
  return getTokenPath(this.storagePath);
53682
54469
  }
53683
54470
  };
54471
+ function parseOnboardingMarker(raw) {
54472
+ if (typeof raw === "object" && raw !== null && typeof raw.slug === "string" && typeof raw.order === "number") {
54473
+ return { slug: raw.slug, order: raw.order };
54474
+ }
54475
+ return void 0;
54476
+ }
53684
54477
  function assertSameArtifactIDSet(existing, proposed, screenID) {
53685
54478
  const before = new Set(existing.flatMap(collectLayoutArtifactIDs));
53686
54479
  const after = new Set(proposed.flatMap(collectLayoutArtifactIDs));
@@ -53705,7 +54498,7 @@ function collectLayoutArtifactIDs(node) {
53705
54498
  }
53706
54499
 
53707
54500
  // src/index.ts
53708
- var import_meta3 = {};
54501
+ var import_meta2 = {};
53709
54502
  var DAEMON_NAME = "com.television.server";
53710
54503
  var TELEMETRY_LAUNCH_MODE_ENV = "TELEVISION_LAUNCH_MODE";
53711
54504
  var SKILL_INSTALL_TELEMETRY_TIMEOUT_MS2 = 1e3;
@@ -53759,24 +54552,24 @@ function createDirectiveError(message) {
53759
54552
  return new CLIDirectiveError(ensureHelpPointer(message));
53760
54553
  }
53761
54554
  function getDevPackageDir() {
53762
- return import_node_path15.default.resolve(import_node_path15.default.dirname((0, import_node_url3.fileURLToPath)(import_meta3.url)), "..");
54555
+ return import_node_path17.default.resolve(import_node_path17.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url)), "..");
53763
54556
  }
53764
54557
  function resolveVercelSkillsInstallerBin() {
53765
54558
  if (typeof require === "function" && typeof require.resolve === "function") {
53766
54559
  return require.resolve("skills/bin/cli.mjs");
53767
54560
  }
53768
- const localRequire = (0, import_node_module.createRequire)(import_node_path15.default.join(getDevPackageDir(), "package.json"));
54561
+ const localRequire = (0, import_node_module.createRequire)(import_node_path17.default.join(getDevPackageDir(), "package.json"));
53769
54562
  return localRequire.resolve("skills/bin/cli.mjs");
53770
54563
  }
53771
54564
  function readCLIVersion() {
53772
- if ("0.1.178".length > 0) {
53773
- return "0.1.178";
54565
+ if ("0.1.180".length > 0) {
54566
+ return "0.1.180";
53774
54567
  }
53775
- const devPackageJsonPath = import_node_path15.default.join(getDevPackageDir(), "package.json");
53776
- if (!(0, import_node_fs12.existsSync)(devPackageJsonPath)) {
54568
+ const devPackageJsonPath = import_node_path17.default.join(getDevPackageDir(), "package.json");
54569
+ if (!(0, import_node_fs14.existsSync)(devPackageJsonPath)) {
53777
54570
  throw new Error("Could not resolve package.json for repo-local CLI version.");
53778
54571
  }
53779
- return JSON.parse((0, import_node_fs12.readFileSync)(devPackageJsonPath, "utf8")).version;
54572
+ return JSON.parse((0, import_node_fs14.readFileSync)(devPackageJsonPath, "utf8")).version;
53780
54573
  }
53781
54574
  function inspectTelemetryBuildConfig(env = {}, options = {}) {
53782
54575
  const project = resolvePostHogProject(env, options);
@@ -53841,7 +54634,7 @@ function formatCLIError(error48, argv = []) {
53841
54634
  const status = typeof error48.status === "number" ? Number(error48.status) : void 0;
53842
54635
  if (status === HTTP_UNAUTHORIZED_STATUS2) {
53843
54636
  return ensureHelpPointer(
53844
- `Television server at ${serverURL} rejected the request as unauthorized. Check the token in ${import_node_path15.default.join(storagePathFromArgv(argv) ?? getTelevisionStoragePath(), "state", "token")}.`
54637
+ `Television server at ${serverURL} rejected the request as unauthorized. Check the token in ${import_node_path17.default.join(storagePathFromArgv(argv) ?? getTelevisionStoragePath(), "state", "token")}.`
53845
54638
  );
53846
54639
  }
53847
54640
  if (status !== void 0) {
@@ -53884,63 +54677,63 @@ function resolveStaticDir() {
53884
54677
  if (!process.argv[1]) {
53885
54678
  return void 0;
53886
54679
  }
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;
54680
+ const entryDir = import_node_path17.default.dirname((0, import_node_fs14.realpathSync)(process.argv[1]));
54681
+ const resolved = import_node_path17.default.resolve(entryDir, "./web");
54682
+ return (0, import_node_fs14.existsSync)(import_node_path17.default.join(resolved, "index.html")) ? resolved : void 0;
53890
54683
  }
53891
54684
  function resolveBundledViewsPath() {
53892
54685
  if (process.argv[1]) {
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;
54686
+ const entryDir = import_node_path17.default.dirname((0, import_node_fs14.realpathSync)(process.argv[1]));
54687
+ const resolved = import_node_path17.default.resolve(entryDir, "./views");
54688
+ return (0, import_node_fs14.existsSync)(resolved) ? resolved : void 0;
53896
54689
  }
53897
- const devViewsPath = import_node_path15.default.join(getDevPackageDir(), "dist/views");
53898
- return (0, import_node_fs12.existsSync)(devViewsPath) ? devViewsPath : void 0;
54690
+ const devViewsPath = import_node_path17.default.join(getDevPackageDir(), "dist/views");
54691
+ return (0, import_node_fs14.existsSync)(devViewsPath) ? devViewsPath : void 0;
53899
54692
  }
53900
54693
  function resolveCanonicalDir() {
53901
54694
  if (process.argv[1]) {
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;
54695
+ const entryDir = import_node_path17.default.dirname((0, import_node_fs14.realpathSync)(process.argv[1]));
54696
+ const resolved = import_node_path17.default.resolve(entryDir, "./canonical/v1");
54697
+ return (0, import_node_fs14.existsSync)(resolved) ? resolved : void 0;
53905
54698
  }
53906
- const devCanonicalPath = import_node_path15.default.resolve(
54699
+ const devCanonicalPath = import_node_path17.default.resolve(
53907
54700
  getDevPackageDir(),
53908
54701
  "../server/dist/canonical/v1"
53909
54702
  );
53910
- return (0, import_node_fs12.existsSync)(devCanonicalPath) ? devCanonicalPath : void 0;
54703
+ return (0, import_node_fs14.existsSync)(devCanonicalPath) ? devCanonicalPath : void 0;
53911
54704
  }
53912
- function resolveOnboardingArtifactSourcePath() {
54705
+ function resolveOnboardingContentPath() {
53913
54706
  if (process.argv[1]) {
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;
54707
+ const entryDir = import_node_path17.default.dirname((0, import_node_fs14.realpathSync)(process.argv[1]));
54708
+ const resolved = import_node_path17.default.resolve(entryDir, "./onboarding");
54709
+ return (0, import_node_fs14.existsSync)(resolved) ? resolved : void 0;
53917
54710
  }
53918
- const devPath = import_node_path15.default.resolve(
54711
+ const devPath = import_node_path17.default.resolve(
53919
54712
  getDevPackageDir(),
53920
- "../server/assets/television-onboarding"
54713
+ "../server/assets/onboarding-screens"
53921
54714
  );
53922
- return (0, import_node_fs12.existsSync)(devPath) ? devPath : void 0;
54715
+ return (0, import_node_fs14.existsSync)(devPath) ? devPath : void 0;
53923
54716
  }
53924
54717
  function resolveBundledSkillsRoot() {
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)) {
54718
+ const builtPath = typeof process.argv[1] === "string" ? import_node_path17.default.resolve(import_node_path17.default.dirname((0, import_node_fs14.realpathSync)(process.argv[1])), "./skills") : void 0;
54719
+ if (builtPath && (0, import_node_fs14.existsSync)(builtPath)) {
53927
54720
  return builtPath;
53928
54721
  }
53929
- const devPath = import_node_path15.default.resolve(getDevPackageDir(), "../skills/dist");
53930
- return (0, import_node_fs12.existsSync)(devPath) ? devPath : void 0;
54722
+ const devPath = import_node_path17.default.resolve(getDevPackageDir(), "../skills/dist");
54723
+ return (0, import_node_fs14.existsSync)(devPath) ? devPath : void 0;
53931
54724
  }
53932
54725
  function copyBundledSkillsToDestination(bundledSkillsRoot, destinationRoot) {
53933
- if ((0, import_node_fs12.existsSync)(destinationRoot) && !(0, import_node_fs12.statSync)(destinationRoot).isDirectory()) {
54726
+ if ((0, import_node_fs14.existsSync)(destinationRoot) && !(0, import_node_fs14.statSync)(destinationRoot).isDirectory()) {
53934
54727
  throw new Error(`Skills destination is not a directory: ${destinationRoot}`);
53935
54728
  }
53936
- (0, import_node_fs12.mkdirSync)(destinationRoot, { recursive: true });
54729
+ (0, import_node_fs14.mkdirSync)(destinationRoot, { recursive: true });
53937
54730
  const copied = [];
53938
- const entries = (0, import_node_fs12.readdirSync)(bundledSkillsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).sort((a, b2) => a.name.localeCompare(b2.name));
54731
+ const entries = (0, import_node_fs14.readdirSync)(bundledSkillsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).sort((a, b2) => a.name.localeCompare(b2.name));
53939
54732
  for (const entry of entries) {
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 });
54733
+ const sourcePath = import_node_path17.default.join(bundledSkillsRoot, entry.name);
54734
+ const destinationPath = import_node_path17.default.join(destinationRoot, entry.name);
54735
+ (0, import_node_fs14.rmSync)(destinationPath, { recursive: true, force: true });
54736
+ (0, import_node_fs14.cpSync)(sourcePath, destinationPath, { recursive: true });
53944
54737
  copied.push({ name: entry.name, sourcePath, destinationPath });
53945
54738
  }
53946
54739
  return copied;
@@ -54022,19 +54815,17 @@ function formatCommanderError(argv, error48) {
54022
54815
  return null;
54023
54816
  }
54024
54817
  function readAuthToken(storagePath) {
54025
- const tokenPath = import_node_path15.default.join(storagePath, "state", "token");
54026
- if (!(0, import_node_fs12.existsSync)(tokenPath)) {
54818
+ const tokenPath = import_node_path17.default.join(storagePath, "state", "token");
54819
+ if (!(0, import_node_fs14.existsSync)(tokenPath)) {
54027
54820
  return void 0;
54028
54821
  }
54029
- const token = (0, import_node_fs12.readFileSync)(tokenPath, "utf8").trim();
54822
+ const token = (0, import_node_fs14.readFileSync)(tokenPath, "utf8").trim();
54030
54823
  return token.length > 0 ? token : void 0;
54031
54824
  }
54032
54825
  function readOrCreateAuthToken(storagePath) {
54033
- const onboardingArtifactSourcePath = resolveOnboardingArtifactSourcePath();
54034
54826
  return new ServerStore({
54035
54827
  storagePath,
54036
- installOnboardingArtifact: false,
54037
- ...onboardingArtifactSourcePath ? { onboardingArtifactSourcePath } : {}
54828
+ installOnboardingScreens: false
54038
54829
  }).authToken;
54039
54830
  }
54040
54831
  function buildDaemonServeArgs(options = {}) {
@@ -54067,11 +54858,14 @@ function createEnvironment(environment) {
54067
54858
  stderr: environment.stderr ?? process.stderr,
54068
54859
  createClient: environment.createClient ?? ((serverURL, token) => new TelevisionClient(serverURL, { token })),
54069
54860
  createServer: environment.createServer ?? ((options) => new Server({
54861
+ // `tv serve` always enables the onboarding installer, passing the
54862
+ // resolved content root when one resolved
54863
+ // (specs/arch/onboarding/content.md CLI path resolution).
54070
54864
  store: new ServerStore({
54071
54865
  storagePath: options.storagePath ?? getTelevisionStoragePath(),
54072
54866
  ...options.bundledViewsPath ? { bundledViewsPath: options.bundledViewsPath } : {},
54073
- ...options.onboardingArtifactSourcePath ? { onboardingArtifactSourcePath: options.onboardingArtifactSourcePath } : {},
54074
- installOnboardingArtifact: options.onboardingArtifactSourcePath !== void 0
54867
+ ...options.onboardingContentPath ? { onboardingContentPath: options.onboardingContentPath } : {},
54868
+ installOnboardingScreens: true
54075
54869
  }),
54076
54870
  listen: options.listen,
54077
54871
  port: options.port,
@@ -54097,7 +54891,7 @@ function createEnvironment(environment) {
54097
54891
  resolveStaticDir: environment.resolveStaticDir ?? (() => resolveStaticDir()),
54098
54892
  resolveCanonicalDir: environment.resolveCanonicalDir ?? (() => resolveCanonicalDir()),
54099
54893
  resolveBundledViewsPath: environment.resolveBundledViewsPath ?? (() => resolveBundledViewsPath()),
54100
- resolveOnboardingArtifactSourcePath: environment.resolveOnboardingArtifactSourcePath ?? (() => resolveOnboardingArtifactSourcePath()),
54894
+ resolveOnboardingContentPath: environment.resolveOnboardingContentPath ?? (() => resolveOnboardingContentPath()),
54101
54895
  resolveBundledSkillsRoot: environment.resolveBundledSkillsRoot ?? (() => resolveBundledSkillsRoot()),
54102
54896
  resolveHomeDir: environment.resolveHomeDir ?? (() => import_node_os5.default.homedir()),
54103
54897
  runSkillsInstaller: environment.runSkillsInstaller ?? (async (args) => {
@@ -54168,7 +54962,7 @@ function createProgram(env, argv = []) {
54168
54962
  throw error48;
54169
54963
  }
54170
54964
  if (opts.persist) {
54171
- const storagePath = opts.storagePath ?? getTelevisionStoragePath();
54965
+ const storagePath = import_node_path17.default.resolve(opts.storagePath ?? getTelevisionStoragePath());
54172
54966
  const profile2 = resolveACPAgentProfile(process.env);
54173
54967
  const daemonEnv = buildPersistedACPEnvironment(process.env, { developerHome: env.resolveHomeDir() });
54174
54968
  if (process.env.TELEVISION_PORT !== void 0) daemonEnv.TELEVISION_PORT = process.env.TELEVISION_PORT;
@@ -54229,6 +55023,7 @@ function createProgram(env, argv = []) {
54229
55023
  log(storagePathForLogs, "server startup refused before binding", { argv, error: error48 });
54230
55024
  throw error48;
54231
55025
  }
55026
+ const onboardingContentPath = env.resolveOnboardingContentPath();
54232
55027
  const server = env.createServer({
54233
55028
  listen: opts.listen,
54234
55029
  auth,
@@ -54237,7 +55032,7 @@ function createProgram(env, argv = []) {
54237
55032
  staticDir: env.resolveStaticDir(),
54238
55033
  canonicalDir: env.resolveCanonicalDir(),
54239
55034
  bundledViewsPath: env.resolveBundledViewsPath(),
54240
- onboardingArtifactSourcePath: env.resolveOnboardingArtifactSourcePath(),
55035
+ ...onboardingContentPath !== void 0 ? { onboardingContentPath } : {},
54241
55036
  launchMode: resolveTelemetryLaunchMode(process.env),
54242
55037
  ...opts.installedByAgent === void 0 ? {} : { installedByAgent: opts.installedByAgent },
54243
55038
  ...profile ? { acpProfile: profile } : {}
@@ -54441,7 +55236,7 @@ function createProgram(env, argv = []) {
54441
55236
  if (!bundledTelevisionSkillsCollectionRoot) {
54442
55237
  throw new Error("Could not resolve the bundled Television skills root.");
54443
55238
  }
54444
- const destinationRoot = import_node_path15.default.resolve(inputPath);
55239
+ const destinationRoot = import_node_path17.default.resolve(inputPath);
54445
55240
  const copied = copyBundledSkillsToDestination(bundledTelevisionSkillsCollectionRoot, destinationRoot);
54446
55241
  writeLine(env.stdout, `Copied ${copied.length} bundled Television skill(s):`);
54447
55242
  for (const skill of copied) {
@@ -54476,6 +55271,7 @@ function createProgram(env, argv = []) {
54476
55271
  const client = createAuthenticatedClient(opts);
54477
55272
  const health = await client.health();
54478
55273
  result.healthy = true;
55274
+ result.version = health.version ?? "unknown (pre-0.1.179)";
54479
55275
  result.bindAddresses = health.bindAddresses;
54480
55276
  result.port = health.port;
54481
55277
  result.telemetry = await client.telemetry.status();
@@ -54535,7 +55331,7 @@ if (!isVitestRuntime()) {
54535
55331
  resolveBundledSkillsRoot,
54536
55332
  resolveBundledViewsPath,
54537
55333
  resolveCanonicalDir,
54538
- resolveOnboardingArtifactSourcePath,
55334
+ resolveOnboardingContentPath,
54539
55335
  resolveStaticDir,
54540
55336
  runCLI
54541
55337
  });