clay-server 2.17.0-beta.2 → 2.17.0-beta.4

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 (3) hide show
  1. package/README.md +1 -1
  2. package/bin/cli.js +70 -27
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -168,7 +168,7 @@ Yes. Create as many as you need. A code reviewer, a writing partner, a project m
168
168
 
169
169
  ## HTTPS
170
170
 
171
- HTTPS is enabled by default using a builtin wildcard certificate for `*.d.clay.studio`. No setup required. Your browser connects to a URL like:
171
+ HTTPS is enabled by default using a builtin wildcard certificate for `*.d.clay.studio`. No setup required. Available from `v2.17.0-beta.2`. Your browser connects to a URL like:
172
172
 
173
173
  ```
174
174
  https://192-168-1-50.d.clay.studio:2633
package/bin/cli.js CHANGED
@@ -53,6 +53,7 @@ var args = process.argv.slice(2);
53
53
  var port = _isDev ? 2635 : 2633;
54
54
  var useHttps = true;
55
55
  var forceMkcert = false;
56
+ var forceBuiltin = false;
56
57
  var skipUpdate = false;
57
58
  var debugMode = false;
58
59
  var autoYes = false;
@@ -84,6 +85,8 @@ for (var i = 0; i < args.length; i++) {
84
85
  useHttps = false;
85
86
  } else if (args[i] === "--local-cert") {
86
87
  forceMkcert = true;
88
+ } else if (args[i] === "--builtin-cert") {
89
+ forceBuiltin = true;
87
90
  } else if (args[i] === "--no-update" || args[i] === "--skip-update") {
88
91
  skipUpdate = true;
89
92
  } else if (args[i] === "--dev") {
@@ -128,7 +131,8 @@ for (var i = 0; i < args.length; i++) {
128
131
  console.log(" -p, --port <port> Port to listen on (default: 2633)");
129
132
  console.log(" --host <address> Address to bind to (default: 0.0.0.0)");
130
133
  console.log(" --no-https Disable HTTPS (enabled by default)");
131
- console.log(" --local-cert Use local certificate (mkcert) instead of builtin");
134
+ console.log(" --local-cert Use local certificate (mkcert), suppress migration notice");
135
+ console.log(" --builtin-cert Use builtin certificate even if mkcert is installed");
132
136
  console.log(" --no-update Skip auto-update check on startup");
133
137
  console.log(" --debug Enable debug panel in the web UI");
134
138
  console.log(" -y, --yes Skip interactive prompts (accept defaults)");
@@ -599,10 +603,11 @@ function toClayStudioUrl(ip, port, protocol) {
599
603
  }
600
604
 
601
605
  function ensureCerts(ip) {
602
- // Check builtin cert first (unless --local-cert flag is set)
603
- if (!forceMkcert) {
606
+ // --builtin-cert: skip mkcert entirely, go straight to builtin
607
+ if (forceBuiltin) {
604
608
  var builtin = getBuiltinCert();
605
609
  if (builtin) return builtin;
610
+ return null;
606
611
  }
607
612
 
608
613
  var homeDir = os.homedir();
@@ -619,24 +624,30 @@ function ensureCerts(ip) {
619
624
  fs.copyFileSync(legacyCert, certPath);
620
625
  }
621
626
 
627
+ var mkcertInstalled = hasMkcert();
628
+
622
629
  var caRoot = null;
623
- try {
624
- caRoot = path.join(
625
- execSync("mkcert -CAROOT", { encoding: "utf8" }).trim(),
626
- "rootCA.pem"
627
- );
628
- if (!fs.existsSync(caRoot)) caRoot = null;
629
- } catch (e) {}
630
+ if (mkcertInstalled) {
631
+ try {
632
+ caRoot = path.join(
633
+ execSync("mkcert -CAROOT", { encoding: "utf8" }).trim(),
634
+ "rootCA.pem"
635
+ );
636
+ if (!fs.existsSync(caRoot)) caRoot = null;
637
+ } catch (e) {}
638
+ }
630
639
 
631
640
  // Collect all IPv4 addresses (Tailscale + LAN)
632
641
  var allIPs = getAllIPs();
633
642
 
634
643
  if (fs.existsSync(keyPath) && fs.existsSync(certPath)) {
635
644
  var needRegen = false;
645
+ var isMkcertCert = false;
636
646
  try {
637
647
  var certText = execFileSync("openssl", ["x509", "-in", certPath, "-text", "-noout"], { encoding: "utf8" });
638
648
  // If cert is from an external CA (e.g. Tailscale/Let's Encrypt), never regenerate
639
649
  if (certText.indexOf("mkcert") === -1) return { key: keyPath, cert: certPath, caRoot: caRoot };
650
+ isMkcertCert = true;
640
651
  for (var i = 0; i < allIPs.length; i++) {
641
652
  if (certText.indexOf(allIPs[i]) === -1) {
642
653
  needRegen = true;
@@ -644,24 +655,41 @@ function ensureCerts(ip) {
644
655
  }
645
656
  }
646
657
  } catch (e) { needRegen = true; }
647
- if (!needRegen) return { key: keyPath, cert: certPath, caRoot: caRoot };
658
+ // mkcert cert but mkcert uninstalled: CA is gone, cert is untrusted. Skip it.
659
+ if (isMkcertCert && !mkcertInstalled) needRegen = true;
660
+ if (!needRegen) {
661
+ return { key: keyPath, cert: certPath, caRoot: caRoot, mkcertDetected: mkcertInstalled && !forceMkcert };
662
+ }
648
663
  }
649
664
 
650
- fs.mkdirSync(certDir, { recursive: true });
665
+ // mkcert installed: generate local cert (legacy behavior)
666
+ if (mkcertInstalled) {
667
+ fs.mkdirSync(certDir, { recursive: true });
668
+
669
+ var domains = ["localhost", "127.0.0.1", "::1"];
670
+ for (var i = 0; i < allIPs.length; i++) {
671
+ if (domains.indexOf(allIPs[i]) === -1) domains.push(allIPs[i]);
672
+ }
673
+
674
+ try {
675
+ var mkcertArgs = ["-key-file", keyPath, "-cert-file", certPath].concat(domains);
676
+ execFileSync("mkcert", mkcertArgs, { stdio: "pipe" });
677
+ } catch (err) {
678
+ // mkcert generation failed, fall through to builtin
679
+ }
651
680
 
652
- var domains = ["localhost", "127.0.0.1", "::1"];
653
- for (var i = 0; i < allIPs.length; i++) {
654
- if (domains.indexOf(allIPs[i]) === -1) domains.push(allIPs[i]);
681
+ if (fs.existsSync(keyPath) && fs.existsSync(certPath)) {
682
+ return { key: keyPath, cert: certPath, caRoot: caRoot, mkcertDetected: !forceMkcert };
683
+ }
655
684
  }
656
685
 
657
- try {
658
- var mkcertArgs = ["-key-file", keyPath, "-cert-file", certPath].concat(domains);
659
- execFileSync("mkcert", mkcertArgs, { stdio: "pipe" });
660
- } catch (err) {
661
- return null;
686
+ // Fallback: builtin cert (unless --local-cert forces mkcert-only)
687
+ if (!forceMkcert) {
688
+ var builtin = getBuiltinCert();
689
+ if (builtin) return builtin;
662
690
  }
663
691
 
664
- return { key: keyPath, cert: certPath, caRoot: caRoot };
692
+ return null;
665
693
  }
666
694
 
667
695
  // --- Logo ---
@@ -1436,12 +1464,14 @@ async function forkDaemon(mode, keepAwake, extraProjects, addCwd, wantOsUsers) {
1436
1464
  var ip = getLocalIP();
1437
1465
  var hasTls = false;
1438
1466
  var hasBuiltinCert = false;
1467
+ var mkcertDetected = false;
1439
1468
 
1440
1469
  if (useHttps) {
1441
1470
  var certPaths = ensureCerts(ip);
1442
1471
  if (certPaths) {
1443
1472
  hasTls = true;
1444
1473
  if (certPaths.builtin) hasBuiltinCert = true;
1474
+ if (certPaths.mkcertDetected) mkcertDetected = true;
1445
1475
  } else {
1446
1476
  log(sym.warn + " " + a.yellow + "HTTPS unavailable" + a.reset + a.dim + " · mkcert not installed" + a.reset);
1447
1477
  }
@@ -1516,6 +1546,7 @@ async function forkDaemon(mode, keepAwake, extraProjects, addCwd, wantOsUsers) {
1516
1546
  pinHash: mode === "multi" && cliPin ? generateAuthToken(cliPin) : null,
1517
1547
  tls: hasTls,
1518
1548
  builtinCert: hasBuiltinCert,
1549
+ mkcertDetected: mkcertDetected,
1519
1550
  debug: debugMode,
1520
1551
  keepAwake: keepAwake,
1521
1552
  dangerouslySkipPermissions: dangerouslySkipPermissions,
@@ -1595,7 +1626,8 @@ async function forkDaemon(mode, keepAwake, extraProjects, addCwd, wantOsUsers) {
1595
1626
  : protocol + "://" + ip + ":" + config.port;
1596
1627
  console.log(" " + sym.done + " Daemon started (PID " + config.pid + ")");
1597
1628
  console.log(" " + sym.done + " " + url);
1598
- if (config.builtinCert) console.log(" " + sym.done + " d.clay.studio is only used for HTTPS certificates. All traffic stays on your local network. https://github.com/chadbyte/clay/tree/main/clay-dns");
1629
+ if (config.builtinCert) console.log(" " + sym.done + " d.clay.studio provides HTTPS certificates only. Your traffic never leaves your network.");
1630
+ if (config.mkcertDetected) console.log(" " + sym.warn + " Clay now ships with a builtin HTTPS certificate. To use it, pass --builtin-cert or uninstall mkcert.");
1599
1631
  console.log(" " + sym.done + " Headless mode — exiting CLI");
1600
1632
  process.exit(0);
1601
1633
  return;
@@ -1612,12 +1644,14 @@ async function devMode(mode, keepAwake, existingPinHash) {
1612
1644
  var ip = getLocalIP();
1613
1645
  var hasTls = false;
1614
1646
  var hasBuiltinCert = false;
1647
+ var mkcertDetected = false;
1615
1648
 
1616
1649
  if (useHttps) {
1617
1650
  var certPaths = ensureCerts(ip);
1618
1651
  if (certPaths) {
1619
1652
  hasTls = true;
1620
1653
  if (certPaths.builtin) hasBuiltinCert = true;
1654
+ if (certPaths.mkcertDetected) mkcertDetected = true;
1621
1655
  }
1622
1656
  }
1623
1657
 
@@ -1681,6 +1715,7 @@ async function devMode(mode, keepAwake, existingPinHash) {
1681
1715
  pinHash: existingPinHash || null,
1682
1716
  tls: hasTls,
1683
1717
  builtinCert: hasBuiltinCert,
1718
+ mkcertDetected: mkcertDetected,
1684
1719
  debug: true,
1685
1720
  keepAwake: keepAwake || false,
1686
1721
  dangerouslySkipPermissions: dangerouslySkipPermissions,
@@ -1830,6 +1865,7 @@ async function restartDaemonWithTLS(config, callback) {
1830
1865
  return;
1831
1866
  }
1832
1867
  var hasBuiltinCert = !!(certPaths && certPaths.builtin);
1868
+ var mkcertDetected = !!(certPaths && certPaths.mkcertDetected);
1833
1869
 
1834
1870
  // Shut down old daemon
1835
1871
  stopDaemonWatcher();
@@ -1854,6 +1890,7 @@ async function restartDaemonWithTLS(config, callback) {
1854
1890
  pinHash: config.pinHash || null,
1855
1891
  tls: true,
1856
1892
  builtinCert: hasBuiltinCert,
1893
+ mkcertDetected: mkcertDetected,
1857
1894
  debug: config.debug || false,
1858
1895
  keepAwake: config.keepAwake || false,
1859
1896
  dangerouslySkipPermissions: config.dangerouslySkipPermissions || false,
@@ -1952,7 +1989,7 @@ function showMainMenu(config, ip) {
1952
1989
  function afterQr() {
1953
1990
  // Status line
1954
1991
  log(" " + a.dim + "clay" + a.reset + " " + a.dim + "v" + currentVersion + a.reset + a.dim + " — " + url + a.reset);
1955
- if (config.builtinCert) log(" " + a.dim + "d.clay.studio is only used for HTTPS certificates. All traffic stays on your local network. https://github.com/chadbyte/clay/tree/main/clay-dns" + a.reset);
1992
+ if (config.builtinCert) log(" " + a.dim + "d.clay.studio provides HTTPS certificates only. Your traffic never leaves your network." + a.reset);
1956
1993
  var parts = [];
1957
1994
  parts.push(a.bold + projs.length + a.reset + a.dim + (projs.length === 1 ? " project" : " projects"));
1958
1995
  parts.push(a.reset + a.bold + totalSessions + a.reset + a.dim + (totalSessions === 1 ? " session" : " sessions"));
@@ -1963,6 +2000,13 @@ function showMainMenu(config, ip) {
1963
2000
  log(" Press " + a.bold + "o" + a.reset + " to open in browser");
1964
2001
  log("");
1965
2002
 
2003
+ if (config.mkcertDetected) {
2004
+ log(" " + sym.warn + " " + a.yellow + "Clay now ships with a builtin HTTPS certificate." + a.reset);
2005
+ log(" " + a.dim + "No more CA setup on each device." + a.reset);
2006
+ log(" " + a.dim + "To use it, pass --builtin-cert or uninstall mkcert." + a.reset);
2007
+ log("");
2008
+ }
2009
+
1966
2010
  showMenuItems();
1967
2011
  }
1968
2012
 
@@ -2032,9 +2076,8 @@ function showMainMenu(config, ip) {
2032
2076
  }
2033
2077
  }, {
2034
2078
  hint: [
2035
- "claude-relay has been renamed to clay-server · npx clay-server",
2036
2079
  "Run npx clay-server in other directories to add more projects.",
2037
- "★ github.com/chadbyte/claude-relay — Press s to star the repo",
2080
+ "★ github.com/chadbyte/clay — Press s to star the repo",
2038
2081
  ],
2039
2082
  keys: [
2040
2083
  { key: "o", onKey: function () {
@@ -2042,7 +2085,7 @@ function showMainMenu(config, ip) {
2042
2085
  showMainMenu(config, ip);
2043
2086
  }},
2044
2087
  { key: "s", onKey: function () {
2045
- openUrl("https://github.com/chadbyte/claude-relay");
2088
+ openUrl("https://github.com/chadbyte/clay");
2046
2089
  showMainMenu(config, ip);
2047
2090
  }},
2048
2091
  ],
@@ -2727,7 +2770,7 @@ var currentVersion = require("../package.json").version;
2727
2770
  : protocol + "://" + ip + ":" + config.port;
2728
2771
  console.log(" " + sym.done + " Daemon already running (PID " + config.pid + ")");
2729
2772
  console.log(" " + sym.done + " " + url);
2730
- if (config.builtinCert) console.log(" " + sym.done + " d.clay.studio is only used for HTTPS certificates. All traffic stays on your local network. https://github.com/chadbyte/clay/tree/main/clay-dns");
2773
+ if (config.builtinCert) console.log(" " + sym.done + " d.clay.studio provides HTTPS certificates only. Your traffic never leaves your network.");
2731
2774
  process.exit(0);
2732
2775
  return;
2733
2776
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clay-server",
3
- "version": "2.17.0-beta.2",
3
+ "version": "2.17.0-beta.4",
4
4
  "description": "Web UI for Claude Code. Any device. Push notifications.",
5
5
  "bin": {
6
6
  "clay-server": "./bin/cli.js",