@sealant/mend 0.36.0-next.684 → 0.36.0-next.708

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 (92) hide show
  1. package/dist/main.js +253 -20
  2. package/man/mend-accounts.1 +1 -1
  3. package/man/mend-adopt.1 +1 -1
  4. package/man/mend-attach.1 +1 -1
  5. package/man/mend-codex.1 +1 -1
  6. package/man/mend-completions.1 +1 -1
  7. package/man/mend-connect-pi.1 +1 -1
  8. package/man/mend-connect.1 +1 -1
  9. package/man/mend-continue.1 +1 -1
  10. package/man/mend-doctor.1 +1 -1
  11. package/man/mend-dotfiles-repo.1 +1 -1
  12. package/man/mend-dotfiles-sync.1 +1 -1
  13. package/man/mend-dotfiles.1 +1 -1
  14. package/man/mend-env-cluster.1 +1 -1
  15. package/man/mend-env-load.1 +1 -1
  16. package/man/mend-env-show.1 +1 -1
  17. package/man/mend-folder-create.1 +1 -1
  18. package/man/mend-folder-list.1 +1 -1
  19. package/man/mend-folder-push.1 +1 -1
  20. package/man/mend-folder-rm.1 +1 -1
  21. package/man/mend-git-author.1 +1 -1
  22. package/man/mend-help.1 +1 -1
  23. package/man/mend-invite.1 +1 -1
  24. package/man/mend-keys-init.1 +1 -1
  25. package/man/mend-keys-mode.1 +1 -1
  26. package/man/mend-keys-share.1 +1 -1
  27. package/man/mend-keys-show.1 +1 -1
  28. package/man/mend-land.1 +1 -1
  29. package/man/mend-login.1 +1 -1
  30. package/man/mend-logout.1 +1 -1
  31. package/man/mend-logs.1 +1 -1
  32. package/man/mend-man.1 +1 -1
  33. package/man/mend-members.1 +1 -1
  34. package/man/mend-memory-import.1 +1 -1
  35. package/man/mend-memory-rm.1 +1 -1
  36. package/man/mend-memory-show.1 +1 -1
  37. package/man/mend-memory.1 +1 -1
  38. package/man/mend-models.1 +1 -1
  39. package/man/mend-operator-exposure.1 +2 -2
  40. package/man/mend-operator-gate.1 +1 -1
  41. package/man/mend-operator-grant-owner.1 +1 -1
  42. package/man/mend-operator-org-create.1 +1 -1
  43. package/man/mend-operator-org-invite-owner.1 +1 -1
  44. package/man/mend-operator-org-list.1 +1 -1
  45. package/man/mend-operator-org-rename.1 +1 -1
  46. package/man/mend-operator-reset-link.1 +1 -1
  47. package/man/mend-pair.1 +1 -1
  48. package/man/mend-projects.1 +1 -1
  49. package/man/mend-pull.1 +1 -1
  50. package/man/mend-refresh.1 +1 -1
  51. package/man/mend-rejoin.1 +1 -1
  52. package/man/mend-resume.1 +1 -1
  53. package/man/mend-run.1 +1 -1
  54. package/man/mend-secrets-add.1 +1 -1
  55. package/man/mend-secrets-rm.1 +1 -1
  56. package/man/mend-secrets.1 +1 -1
  57. package/man/mend-server-logs.1 +1 -1
  58. package/man/mend-server-restart.1 +1 -1
  59. package/man/mend-server-setup.1 +13 -2
  60. package/man/mend-server-start.1 +1 -1
  61. package/man/mend-server-status.1 +1 -1
  62. package/man/mend-server-stop.1 +1 -1
  63. package/man/mend-server-upgrade.1 +1 -1
  64. package/man/mend-server.1 +1 -1
  65. package/man/mend-service-add.1 +1 -1
  66. package/man/mend-service-connect.1 +1 -1
  67. package/man/mend-service-init.1 +1 -1
  68. package/man/mend-service-list.1 +1 -1
  69. package/man/mend-service-logs.1 +1 -1
  70. package/man/mend-service-restart.1 +1 -1
  71. package/man/mend-service-run.1 +1 -1
  72. package/man/mend-service-stop.1 +1 -1
  73. package/man/mend-session-share.1 +1 -1
  74. package/man/mend-sessions.1 +1 -1
  75. package/man/mend-shell.1 +1 -1
  76. package/man/mend-skills-push.1 +1 -1
  77. package/man/mend-skills.1 +1 -1
  78. package/man/mend-snake.1 +1 -1
  79. package/man/mend-ssh-keys-remove.1 +1 -1
  80. package/man/mend-ssh-keys.1 +1 -1
  81. package/man/mend-ssh-setup.1 +1 -1
  82. package/man/mend-ssh.1 +1 -1
  83. package/man/mend-stop.1 +1 -1
  84. package/man/mend-ui.1 +1 -1
  85. package/man/mend-uninstall.1 +1 -1
  86. package/man/mend-version.1 +1 -1
  87. package/man/mend-wait.1 +1 -1
  88. package/man/mend-workspace-replace.1 +1 -1
  89. package/man/mend-worktrees-rm.1 +1 -1
  90. package/man/mend-worktrees.1 +1 -1
  91. package/man/mend.1 +1 -1
  92. package/package.json +2 -2
package/dist/main.js CHANGED
@@ -1280,7 +1280,15 @@ var isTenancy = (value) => TENANCIES.some((tenancy) => tenancy === value);
1280
1280
  var EDGE_IMAGE = "caddy:2.10-alpine";
1281
1281
  var EDGE_COMPOSE_FILE = "compose.edge.yaml";
1282
1282
  var POSTURE_COMPOSE_FILE = "compose.posture.yaml";
1283
- var DECLARABLE_ITEMS = ["core-private", "edge-tls", "workspace-ssh"];
1283
+ var T3_GATEWAY_COMPOSE_FILE = "compose.t3.yaml";
1284
+ var T3_GATEWAY_CONTAINER_PORT = 3120;
1285
+ var DEFAULT_T3_GATEWAY_PORT = 3120;
1286
+ var DECLARABLE_ITEMS = [
1287
+ "core-private",
1288
+ "edge-tls",
1289
+ "workspace-ssh",
1290
+ "t3code-gateway"
1291
+ ];
1284
1292
  var isDeclarableItem = (value) => DECLARABLE_ITEMS.some((item) => item === value);
1285
1293
  var publishedAddress = (address, port) => `${net2.isIP(address) === 6 ? `[${address}]` : address}:${port}`;
1286
1294
  var parseEdgeHost = (value) => {
@@ -1307,6 +1315,7 @@ var postureEnvironment = (posture) => {
1307
1315
  };
1308
1316
  var postureEnvLines = (posture) => [
1309
1317
  ...posture.edgeHost === void 0 ? [] : [`MEND_EDGE_HOST=${posture.edgeHost}`],
1318
+ ...posture.t3GatewayPort === void 0 ? [] : [`MEND_T3_GATEWAY_PORT=${posture.t3GatewayPort}`],
1310
1319
  ...postureEnvironment(posture).map(([key, value]) => `${key}=${value}`)
1311
1320
  ];
1312
1321
  var renderPostureOverlay = (posture) => {
@@ -1326,10 +1335,33 @@ var renderPostureOverlay = (posture) => {
1326
1335
  ""
1327
1336
  ].join("\n");
1328
1337
  };
1338
+ var T3_GATEWAY_VOLUME = "mend-t3-gateway";
1339
+ var T3_GATEWAY_IMAGE_LABEL = "dev.sealant.mend.t3-gateway";
1340
+ var T3_GATEWAY_STATE_DIR = "/opt/mend-t3-gateway/state";
1341
+ var renderT3GatewayOverlay = (posture) => {
1342
+ if (posture.t3GatewayPort === void 0) return void 0;
1343
+ return [
1344
+ "# Written by mend server setup --t3-gateway: the t3code gateway (docs/adr/0012), its own",
1345
+ "# listener beside Mend's, published on loopback only. Reaching it from elsewhere is an",
1346
+ "# exposure the operator declares (docs/adr/0004). mend server setup --no-t3-gateway removes it.",
1347
+ "services:",
1348
+ " mend:",
1349
+ " environment:",
1350
+ ' MEND_T3_GATEWAY_ENABLED: "true"',
1351
+ " ports:",
1352
+ ` - "127.0.0.1:\${MEND_T3_GATEWAY_PORT:?set MEND_T3_GATEWAY_PORT in server.env}:${T3_GATEWAY_CONTAINER_PORT}"`,
1353
+ " volumes:",
1354
+ ` - ${T3_GATEWAY_VOLUME}:${T3_GATEWAY_STATE_DIR}`,
1355
+ "volumes:",
1356
+ ` ${T3_GATEWAY_VOLUME}:`,
1357
+ ""
1358
+ ].join("\n");
1359
+ };
1329
1360
  var composeOverlays = (posture) => [
1330
1361
  ...posture.edgeHost === void 0 ? [] : [EDGE_COMPOSE_FILE],
1331
1362
  ...renderPostureOverlay(posture) === void 0 ? [] : [POSTURE_COMPOSE_FILE],
1332
- ...runsMirrors(posture.mirrors) ? [MIRRORS_COMPOSE_FILE] : []
1363
+ ...runsMirrors(posture.mirrors) ? [MIRRORS_COMPOSE_FILE] : [],
1364
+ ...posture.t3GatewayPort === void 0 ? [] : [T3_GATEWAY_COMPOSE_FILE]
1333
1365
  ];
1334
1366
  var record = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? new Map(Object.entries(value)) : null;
1335
1367
  var healthPosture = (body) => {
@@ -1353,6 +1385,9 @@ var healthPosture = (body) => {
1353
1385
  };
1354
1386
  var declaredPostureLines = (posture) => [
1355
1387
  ...posture.edgeHost === void 0 ? [] : [`edge \xB7 ${posture.edgeHost} \xB7 ${EDGE_IMAGE} on 80 and 443 \xB7 Mend's own port on loopback`],
1388
+ ...posture.t3GatewayPort === void 0 ? [] : [
1389
+ `t3code gateway \xB7 on \xB7 127.0.0.1:${posture.t3GatewayPort} \xB7 loopback only \xB7 reaching it from elsewhere is an exposure you declare`
1390
+ ],
1356
1391
  `exposure \xB7 declared ${posture.exposure ?? "private"}${posture.exposure === void 0 ? " \xB7 the default, not set on this install" : ""}`,
1357
1392
  `tenancy \xB7 declared ${posture.tenancy ?? "single"}${posture.tenancy === void 0 ? " \xB7 the default, not set on this install" : ""}`,
1358
1393
  ...posture.sshBind === void 0 || posture.sshPort === void 0 ? [] : [
@@ -3161,7 +3196,7 @@ var COMMANDS = [
3161
3196
  summary: "how this instance is exposed, as declared and as observed",
3162
3197
  synopsis: [],
3163
3198
  description: [
3164
- "Operator only. States MEND_EXPOSURE as declared (loopback, private or public) and one line per item of the public exposure gate, with how it was established: observed (this server read it), carried (this build contains it, and the server cannot see it in effect), declared (you stated it and the server cannot check it), or open. MEND_EXPOSURE=public refuses to start while an item that blocks a start is open: every item the server can observe, and workspace-ssh until you declare it. Items it cannot observe say what would verify them; once you have verified core-private, edge-tls or workspace-ssh (SSH published apart from the web port) from outside, name it in MEND_EXPOSURE_DECLARED, or with mend server setup --declare. The report is what was observed; it is not a statement that the instance is fit to expose."
3199
+ "Operator only. States MEND_EXPOSURE as declared (loopback, private or public) and one line per item of the public exposure gate, with how it was established: observed (this server read it), carried (this build contains it, and the server cannot see it in effect), declared (you stated it and the server cannot check it), or open. MEND_EXPOSURE=public refuses to start while an item that blocks a start is open: every item the server can observe, and workspace-ssh until you declare it. Items it cannot observe say what would verify them; once you have verified core-private, edge-tls, workspace-ssh (SSH published apart from the web port) or (while it is enabled) t3code-gateway from outside, name it in MEND_EXPOSURE_DECLARED, or with mend server setup --declare. The report is what was observed; it is not a statement that the instance is fit to expose."
3165
3200
  ],
3166
3201
  see: ["operator gate", "doctor"]
3167
3202
  },
@@ -3247,12 +3282,13 @@ var COMMANDS = [
3247
3282
  section: "this machine",
3248
3283
  summary: "install or repair the local Mend server",
3249
3284
  synopsis: [
3250
- "[--context <name>] [--version <version|latest>] [--bind <ip>] [--ssh-bind <ip>] [--url <origin>] [--origin <origin>...] [--port <n>] [--ssh-port <n>] [--edge <host> | --no-edge] [--exposure <loopback|private|public>] [--tenancy <single|multi>] [--declare <item>...] [--npm-mirror | --no-npm-mirror] [--npm-mirror-max-size <size>] [--docker-mirror | --no-docker-mirror] [--docker-mirror-max-size <size>] [--docker-hub-username <name> --docker-hub-token-stdin --docker-hub-public-only | --no-docker-hub-login] [--docker-socket <path>] [--assets-dir <dir>] [--offline]"
3285
+ "[--context <name>] [--version <version|latest>] [--bind <ip>] [--ssh-bind <ip>] [--url <origin>] [--origin <origin>...] [--port <n>] [--ssh-port <n>] [--edge <host> | --no-edge] [--exposure <loopback|private|public>] [--tenancy <single|multi>] [--declare <item>...] [--t3-gateway [--t3-gateway-port <n>] | --no-t3-gateway] [--npm-mirror | --no-npm-mirror] [--npm-mirror-max-size <size>] [--docker-mirror | --no-docker-mirror] [--docker-mirror-max-size <size>] [--docker-hub-username <name> --docker-hub-token-stdin --docker-hub-public-only | --no-docker-hub-login] [--docker-socket <path>] [--assets-dir <dir>] [--offline]"
3251
3286
  ],
3252
3287
  description: [
3253
3288
  "Checks a local Unix-socket Docker context and the Compose plugin, downloads the compose and Postgres initialization assets for one Mend release, preserves existing data and secrets, and starts the server. Re-running repairs the same pinned version. A changed --version is refused; use mend server upgrade. Updating this CLI never updates an existing server pin.",
3254
3289
  "The default listens only on localhost at http://localhost:3105. Non-local access requires both --bind and --url. Every extra browser origin must be named with --origin; setup never guesses from the request Host header or network interfaces.",
3255
3290
  "--edge <host> runs a TLS edge in front of Mend: Caddy on ports 80 and 443 of every interface, which obtains and renews a certificate for the host and proxies to Mend's web tier. Mend's own port stays on loopback and the browser origin is https://<host>. The edge's compose overlay and Caddyfile are written into the generation beside compose.yaml, so start, restart and upgrade run them every time. --no-edge takes it away again, and the edge's container with it. A fresh install cannot start with the edge: until the first account exists, registration is open to whoever reaches the origin first, so set up on localhost, create the account, then add the edge.",
3291
+ "--t3-gateway turns on the t3code gateway (docs/adr/0012): t3code's desktop, mobile and web clients add it as an environment, pair with a code from mend pair, and see this Mend's projects and sessions. It runs in the Mend container, confined to a root and a uid of its own, on a listener of its own published on 127.0.0.1 only (port 3120, or --t3-gateway-port): reaching it from another machine is an exposure you put in front of it and declare. Setup refuses it on a Mend image that has no gateway, and says whether it answered. It is kept across reruns and upgrades; --no-t3-gateway turns it off, and its state stays in its own volume, mend-t3-gateway. Off, nothing of it runs.",
3256
3292
  "--exposure declares how the instance is reached, and --tenancy whether one organization or many use it. Both are written into the generation and kept across reruns and upgrades. public needs the edge and an existing first account. With multi, or with public, the multi mode gate's settings follow: MEND_SOURCE_POLICY=tenant and MEND_CAPTURE_REQUIRE_SIZES=true, and public sets MEND_URL_BEARERS=refuse. The server still decides whether it starts, and mend server status shows what it reports.",
3257
3293
  "Two mirrors run beside Mend unless turned off: an npm mirror (nginx caching npmjs.org, capped at 10g by default, least recently used out) and a Docker mirror (a pull-through cache of Docker Hub, capped at 20g by default: over the cap its cache is cleared). Both leave 5g free on their disk: below that, nginx evicts and the Docker mirror pauses, and sessions pull from Docker Hub directly. Neither publishes a host port. Sessions install npm packages and pull Docker Hub images through them; a project's own npm settings win, and a mirror that is down sends sessions upstream instead. Both are kept across reruns and upgrades, and an upgrade adds them to an install from before them. The Docker mirror pulls anonymously unless given a Docker Hub login: --docker-hub-username with the access token piped on standard input, kept in server.env only. The mirror has no login of its own, so every session that reaches it can pull whatever that token can read: setup takes a login only with --docker-hub-public-only, your statement that the token's access permission is Public Repo Read-only. Mend cannot check a token's scope.",
3258
3294
  "Docker Desktop on Linux and macOS, and OrbStack on macOS, expose client-side proxy sockets. Containers use the daemon-side /var/run/docker.sock. --docker-socket overrides detection and is retained on reruns.",
@@ -3287,6 +3323,15 @@ var COMMANDS = [
3287
3323
  text: "run the Caddy TLS edge for this DNS name on 80 and 443; the origin becomes https://<host>, --bind stays on loopback, and the first account must already exist"
3288
3324
  },
3289
3325
  { flag: "--no-edge", text: "take a saved edge away; the origin returns to http://localhost" },
3326
+ {
3327
+ flag: "--t3-gateway",
3328
+ text: "run the t3code gateway, published on 127.0.0.1:3120 only; kept across reruns and upgrades"
3329
+ },
3330
+ {
3331
+ flag: "--t3-gateway-port <n>",
3332
+ text: "the gateway's port on 127.0.0.1; implies --t3-gateway"
3333
+ },
3334
+ { flag: "--no-t3-gateway", text: "turn the t3code gateway off; its state stays" },
3290
3335
  {
3291
3336
  flag: "--exposure <v>",
3292
3337
  text: "declare loopback, private or public; kept across reruns and upgrades. public needs --edge and an existing first account"
@@ -6835,7 +6880,8 @@ var optionalFileKeys = [
6835
6880
  "caddyfile",
6836
6881
  "mirrors",
6837
6882
  "npmMirrorConf",
6838
- "dockerMirrorGuard"
6883
+ "dockerMirrorGuard",
6884
+ "t3Gateway"
6839
6885
  ];
6840
6886
  var fileNames = {
6841
6887
  identity: "identity.env",
@@ -6848,7 +6894,8 @@ var fileNames = {
6848
6894
  caddyfile: "Caddyfile",
6849
6895
  mirrors: "compose.mirrors.yaml",
6850
6896
  npmMirrorConf: "npm-mirror.conf",
6851
- dockerMirrorGuard: "docker-mirror-guard.sh"
6897
+ dockerMirrorGuard: "docker-mirror-guard.sh",
6898
+ t3Gateway: "compose.t3.yaml"
6852
6899
  };
6853
6900
  var fileModes = {
6854
6901
  identity: 384,
@@ -6861,7 +6908,8 @@ var fileModes = {
6861
6908
  caddyfile: 420,
6862
6909
  mirrors: 384,
6863
6910
  npmMirrorConf: 420,
6864
- dockerMirrorGuard: 420
6911
+ dockerMirrorGuard: 420,
6912
+ t3Gateway: 384
6865
6913
  };
6866
6914
  var allFiles = (files) => [...fileKeys, ...optionalFileKeys].map((key) => [key, files[key]]);
6867
6915
  var parseLockOwner = (raw) => {
@@ -6968,6 +7016,7 @@ var readActive = (paths) => {
6968
7016
  const mirrors = optional("mirrors");
6969
7017
  const npmMirrorConf = optional("npmMirrorConf");
6970
7018
  const dockerMirrorGuard = optional("dockerMirrorGuard");
7019
+ const t3Gateway = optional("t3Gateway");
6971
7020
  const files = {
6972
7021
  identity: fs14.readFileSync(path15.join(directory, fileNames.identity), "utf8"),
6973
7022
  config: fs14.readFileSync(path15.join(directory, fileNames.config), "utf8"),
@@ -6979,7 +7028,8 @@ var readActive = (paths) => {
6979
7028
  ...caddyfile === void 0 ? {} : { caddyfile },
6980
7029
  ...mirrors === void 0 ? {} : { mirrors },
6981
7030
  ...npmMirrorConf === void 0 ? {} : { npmMirrorConf },
6982
- ...dockerMirrorGuard === void 0 ? {} : { dockerMirrorGuard }
7031
+ ...dockerMirrorGuard === void 0 ? {} : { dockerMirrorGuard },
7032
+ ...t3Gateway === void 0 ? {} : { t3Gateway }
6983
7033
  };
6984
7034
  if (readIdentity(paths) !== files.identity) {
6985
7035
  throw new ServerStoreError(
@@ -7539,7 +7589,10 @@ var SETUP_FLAGS = /* @__PURE__ */ new Set([
7539
7589
  "--docker-hub-username",
7540
7590
  "--docker-hub-token-stdin",
7541
7591
  "--docker-hub-public-only",
7542
- "--no-docker-hub-login"
7592
+ "--no-docker-hub-login",
7593
+ "--t3-gateway",
7594
+ "--t3-gateway-port",
7595
+ "--no-t3-gateway"
7543
7596
  ]);
7544
7597
  var SWITCHES = /* @__PURE__ */ new Set([
7545
7598
  "--offline",
@@ -7550,7 +7603,9 @@ var SWITCHES = /* @__PURE__ */ new Set([
7550
7603
  "--no-docker-mirror",
7551
7604
  "--docker-hub-token-stdin",
7552
7605
  "--docker-hub-public-only",
7553
- "--no-docker-hub-login"
7606
+ "--no-docker-hub-login",
7607
+ "--t3-gateway",
7608
+ "--no-t3-gateway"
7554
7609
  ]);
7555
7610
  var parseExposure = (value) => {
7556
7611
  if (!isExposure(value))
@@ -7663,6 +7718,10 @@ var parseSetupOptions = (args) => {
7663
7718
  throw setupError(
7664
7719
  `--docker-hub-username and ${noDockerHubLogin ? "--no-docker-hub-login" : "--no-docker-mirror"} contradict each other.`
7665
7720
  );
7721
+ const t3GatewayPort = flagValue3("--t3-gateway-port");
7722
+ if (values.has("--no-t3-gateway") && (values.has("--t3-gateway") || t3GatewayPort !== void 0)) {
7723
+ throw setupError("--no-t3-gateway contradicts --t3-gateway and --t3-gateway-port.");
7724
+ }
7666
7725
  return {
7667
7726
  context: flagValue3("--context"),
7668
7727
  version: version === void 0 ? void 0 : parseVersion(version),
@@ -7686,7 +7745,10 @@ var parseSetupOptions = (args) => {
7686
7745
  dockerMirrorMaxSize,
7687
7746
  dockerHubUsername,
7688
7747
  dockerHubTokenStdin,
7689
- noDockerHubLogin
7748
+ noDockerHubLogin,
7749
+ t3Gateway: values.has("--t3-gateway"),
7750
+ t3GatewayPort: t3GatewayPort === void 0 ? void 0 : parsePort(t3GatewayPort, "--t3-gateway-port"),
7751
+ noT3Gateway: values.has("--no-t3-gateway")
7690
7752
  };
7691
7753
  };
7692
7754
  var resolveMirrors = (saved, options) => {
@@ -7844,6 +7906,15 @@ var validateExposure = (existing, options) => {
7844
7906
  const edgeHost = options.noEdge ? void 0 : options.edge ?? existing?.edgeHost;
7845
7907
  const exposure = options.exposure ?? existing?.exposure;
7846
7908
  const tenancy = options.tenancy ?? existing?.tenancy;
7909
+ const t3GatewayPort = options.noT3Gateway ? void 0 : options.t3GatewayPort ?? existing?.t3GatewayPort ?? (options.t3Gateway ? DEFAULT_T3_GATEWAY_PORT : void 0);
7910
+ if (t3GatewayPort !== void 0 && [appPort, sshPort].includes(t3GatewayPort)) {
7911
+ throw setupError(
7912
+ `--t3-gateway-port ${t3GatewayPort} is Mend's own --port or --ssh-port: the gateway needs a port of its own.`
7913
+ );
7914
+ }
7915
+ if (t3GatewayPort !== void 0 && edgeHost !== void 0 && [80, 443].includes(t3GatewayPort)) {
7916
+ throw setupError("With an edge, --t3-gateway-port must not be 80 or 443: the edge has them.");
7917
+ }
7847
7918
  const declared = options.declared ?? existing?.declared ?? [];
7848
7919
  checkPosture(bind, sshBind ?? bind, { appPort, sshPort }, edgeHost, exposure, declared);
7849
7920
  const appUrl = resolveAppUrl(existing, options, appPort, edgeHost);
@@ -7864,7 +7935,8 @@ var validateExposure = (existing, options) => {
7864
7935
  ...edgeHost === void 0 ? {} : { edgeHost },
7865
7936
  ...exposure === void 0 ? {} : { exposure },
7866
7937
  ...tenancy === void 0 ? {} : { tenancy },
7867
- ...declared.length === 0 ? {} : { declared }
7938
+ ...declared.length === 0 ? {} : { declared },
7939
+ ...t3GatewayPort === void 0 ? {} : { t3GatewayPort }
7868
7940
  };
7869
7941
  };
7870
7942
  var parseServerConfig = (raw) => {
@@ -7910,6 +7982,7 @@ var parseServerConfig = (raw) => {
7910
7982
  );
7911
7983
  }
7912
7984
  const declared = Array.isArray(declaredField) ? declaredField.filter((item) => isDeclarableItem(String(item))) : [];
7985
+ const t3GatewayPort = fields.has("t3GatewayPort") ? requiredInteger(fields, "t3GatewayPort") : void 0;
7913
7986
  const config = {
7914
7987
  schemaVersion: requiredInteger(fields, "schemaVersion"),
7915
7988
  assetContract: requiredString(fields, "assetContract"),
@@ -7932,7 +8005,8 @@ var parseServerConfig = (raw) => {
7932
8005
  ...exposure === void 0 ? {} : { exposure },
7933
8006
  ...tenancy === void 0 ? {} : { tenancy },
7934
8007
  ...declared.length === 0 ? {} : { declared },
7935
- ...fields.has("mirrors") ? { mirrors: parseMirrorsField(fields.get("mirrors")) } : {}
8008
+ ...fields.has("mirrors") ? { mirrors: parseMirrorsField(fields.get("mirrors")) } : {},
8009
+ ...t3GatewayPort === void 0 ? {} : { t3GatewayPort }
7936
8010
  };
7937
8011
  if (config.schemaVersion !== CONFIG_SCHEMA_VERSION || config.assetContract !== ASSET_CONTRACT && !LEGACY_ASSET_CONTRACTS.has(config.assetContract)) {
7938
8012
  throw setupError(
@@ -7943,6 +8017,8 @@ var parseServerConfig = (raw) => {
7943
8017
  parsePort(String(config.sshPort), "Server config sshPort");
7944
8018
  if (config.registryPort !== void 0)
7945
8019
  parsePort(String(config.registryPort), "Server config registryPort");
8020
+ if (config.t3GatewayPort !== void 0)
8021
+ parsePort(String(config.t3GatewayPort), "Server config t3GatewayPort");
7946
8022
  validateExposure(null, {
7947
8023
  context: void 0,
7948
8024
  version: void 0,
@@ -7966,7 +8042,10 @@ var parseServerConfig = (raw) => {
7966
8042
  dockerMirrorMaxSize: void 0,
7967
8043
  dockerHubUsername: void 0,
7968
8044
  dockerHubTokenStdin: false,
7969
- noDockerHubLogin: false
8045
+ noDockerHubLogin: false,
8046
+ t3Gateway: false,
8047
+ t3GatewayPort: config.t3GatewayPort,
8048
+ noT3Gateway: false
7970
8049
  });
7971
8050
  return config;
7972
8051
  };
@@ -8360,12 +8439,22 @@ var validateOverlays = (config, files) => {
8360
8439
  }
8361
8440
  for (const line of postureEnvLines(config)) {
8362
8441
  const key = line.slice(0, line.indexOf("="));
8363
- if (key !== "MEND_EDGE_HOST" && !(files.posture ?? "").includes(` ${key}: \${${key}`)) {
8442
+ if (key !== "MEND_EDGE_HOST" && key !== "MEND_T3_GATEWAY_PORT" && !(files.posture ?? "").includes(` ${key}: \${${key}`)) {
8364
8443
  throw setupError(
8365
8444
  `Server generation is corrupt: compose.posture.yaml does not hand ${key} to Mend.`
8366
8445
  );
8367
8446
  }
8368
8447
  }
8448
+ if (config.t3GatewayPort === void 0 !== (files.t3Gateway === void 0)) {
8449
+ throw setupError(
8450
+ "Server generation is corrupt: compose.t3.yaml does not match the persisted server config."
8451
+ );
8452
+ }
8453
+ if (files.t3Gateway !== void 0 && (!files.t3Gateway.includes('MEND_T3_GATEWAY_ENABLED: "true"') || !files.t3Gateway.includes('"127.0.0.1:${MEND_T3_GATEWAY_PORT'))) {
8454
+ throw setupError(
8455
+ "Server generation is corrupt: compose.t3.yaml is not the gateway overlay on loopback."
8456
+ );
8457
+ }
8369
8458
  if (config.edgeHost === void 0 !== (files.edge === void 0) || config.edgeHost === void 0 !== (files.caddyfile === void 0)) {
8370
8459
  throw setupError(
8371
8460
  "Server generation is corrupt: compose.edge.yaml and Caddyfile do not match the persisted server config."
@@ -8478,7 +8567,8 @@ var readServerInstallationFacts = async (configDir) => {
8478
8567
  ...generation.files.posture === void 0 ? [] : [{ name: "compose.posture.yaml", content: generation.files.posture }],
8479
8568
  ...generation.files.mirrors === void 0 ? [] : [{ name: MIRRORS_COMPOSE_FILE, content: generation.files.mirrors }],
8480
8569
  ...generation.files.npmMirrorConf === void 0 ? [] : [{ name: NPM_MIRROR_CONF_NAME, content: generation.files.npmMirrorConf }],
8481
- ...generation.files.dockerMirrorGuard === void 0 ? [] : [{ name: DOCKER_MIRROR_GUARD_NAME, content: generation.files.dockerMirrorGuard }]
8570
+ ...generation.files.dockerMirrorGuard === void 0 ? [] : [{ name: DOCKER_MIRROR_GUARD_NAME, content: generation.files.dockerMirrorGuard }],
8571
+ ...generation.files.t3Gateway === void 0 ? [] : [{ name: "compose.t3.yaml", content: generation.files.t3Gateway }]
8482
8572
  ],
8483
8573
  envKeys: envKeyNames(generation.files.env)
8484
8574
  };
@@ -8491,6 +8581,7 @@ var readServerInstallationFacts = async (configDir) => {
8491
8581
  var generationFiles = (config, secrets, assets, identity = renderIdentity(secrets)) => {
8492
8582
  const posture = renderPostureOverlay(config);
8493
8583
  const mirrors = renderMirrorsOverlay(config.mirrors);
8584
+ const t3Gateway = renderT3GatewayOverlay(config);
8494
8585
  return {
8495
8586
  identity,
8496
8587
  config: `${JSON.stringify(config, null, 2)}
@@ -8498,6 +8589,7 @@ var generationFiles = (config, secrets, assets, identity = renderIdentity(secret
8498
8589
  env: renderSecrets(secrets, config),
8499
8590
  ...assets,
8500
8591
  ...posture === void 0 ? {} : { posture },
8592
+ ...t3Gateway === void 0 ? {} : { t3Gateway },
8501
8593
  ...config.edgeHost === void 0 ? {} : { edge: EDGE_COMPOSE_OVERLAY, caddyfile: EDGE_CADDYFILE },
8502
8594
  ...mirrors === void 0 ? {} : { mirrors },
8503
8595
  ...config.mirrors === void 0 || config.mirrors.npm === null ? {} : { npmMirrorConf: NPM_MIRROR_CONF },
@@ -8511,6 +8603,18 @@ var healthOrigin = (config) => {
8511
8603
  return `http://${host}:${config.appPort}`;
8512
8604
  };
8513
8605
  var reachableLine = (config) => config.edgeHost === void 0 ? `Mend ${config.serverVersion} is reachable at ${config.appUrl}` : `Mend ${config.serverVersion} answers at ${healthOrigin(config)} on this machine \xB7 the edge is set up for ${config.appUrl}`;
8606
+ var T3_GATEWAY_OBSERVE_ATTEMPTS = 15;
8607
+ var observeT3Gateway = async (runtime, port) => {
8608
+ const url = `http://127.0.0.1:${port}/.well-known/t3/environment`;
8609
+ for (let attempt2 = 0; attempt2 < T3_GATEWAY_OBSERVE_ATTEMPTS; attempt2 += 1) {
8610
+ const response = await runtime.fetchText(url, 2e3);
8611
+ if (response.error === void 0 && response.status === 200) {
8612
+ return `The t3code gateway answered at 127.0.0.1:${port}, observed from this machine; it is published there only. In t3code, add it as an environment at http://127.0.0.1:${port} and pair with a code from mend pair; reaching it from elsewhere is an exposure you put in front of it and declare (docs/adr/0004).`;
8613
+ }
8614
+ if (attempt2 < T3_GATEWAY_OBSERVE_ATTEMPTS - 1) await runtime.sleep(2e3);
8615
+ }
8616
+ return `The t3code gateway did not answer at 127.0.0.1:${port} from this machine within about a minute. Mend runs without it; mend server logs shows what it said, and mend server status looks again.`;
8617
+ };
8514
8618
  var probeHealth = async (runtime, appUrl, expectedVersion) => {
8515
8619
  const healthUrl = `${appUrl}/api/health`;
8516
8620
  let lastFailure = "request did not complete";
@@ -8639,6 +8743,22 @@ var checkLocalImages = async (runtime, installation, policy = "local") => {
8639
8743
  `Image ${image} must carry org.opencontainers.image.version=${config.serverVersion}.`
8640
8744
  );
8641
8745
  }
8746
+ if (config.t3GatewayPort !== void 0) {
8747
+ const gateway = await runtime.run("docker", [
8748
+ "--context",
8749
+ config.dockerContext,
8750
+ "image",
8751
+ "inspect",
8752
+ image,
8753
+ "--format",
8754
+ `{{index .Config.Labels "${T3_GATEWAY_IMAGE_LABEL}"}}`
8755
+ ]);
8756
+ if (gateway.status !== 0 || gateway.stdout.trim() !== "1") {
8757
+ throw setupError(
8758
+ `Mend ${config.serverVersion} has no t3code gateway (its image carries no ${T3_GATEWAY_IMAGE_LABEL} label). Upgrade to a version that has one with mend server upgrade --version <version>, then turn it on; or run mend server setup --no-t3-gateway`
8759
+ );
8760
+ }
8761
+ }
8642
8762
  const postgres = await inspectImage(
8643
8763
  runtime,
8644
8764
  config.dockerContext,
@@ -8965,6 +9085,11 @@ var setupServer = async (args, runtime, store) => {
8965
9085
  ...savedSecrets ?? createSecrets(runtime),
8966
9086
  ...dockerHubToken === void 0 ? {} : { dockerHubToken }
8967
9087
  };
9088
+ if (config.t3GatewayPort !== void 0 && config.t3GatewayPort !== existing?.config.t3GatewayPort && config.dockerEndpoint.startsWith("unix://") && runtime.portTaken !== void 0 && await runtime.portTaken(config.t3GatewayPort)) {
9089
+ throw setupError(
9090
+ `127.0.0.1:${config.t3GatewayPort} is already in use on this machine, so the t3code gateway cannot be published there and Mend would not start. Free it, or pick another with --t3-gateway-port <n>`
9091
+ );
9092
+ }
8968
9093
  const generation = persistSetup(store, config, secrets, assets);
8969
9094
  const installation = {
8970
9095
  directory: generation.directory,
@@ -8994,6 +9119,14 @@ var setupServer = async (args, runtime, store) => {
8994
9119
  if (edgeStarted !== null) runtime.writeLine(edgeStarted);
8995
9120
  const sshPublication = await sshPublicationLine(runtime, config);
8996
9121
  if (sshPublication !== null) runtime.writeLine(sshPublication);
9122
+ if (config.t3GatewayPort !== void 0) {
9123
+ runtime.writeLine(await observeT3Gateway(runtime, config.t3GatewayPort));
9124
+ }
9125
+ if (existing?.config.t3GatewayPort !== void 0 && config.t3GatewayPort === void 0) {
9126
+ runtime.writeLine(
9127
+ `The t3code gateway is off. Its state (pairings and the device tokens they hold, queued messages) stays in its volume and comes back if you turn it on again; to remove it: docker --context ${config.dockerContext} volume rm mend_${T3_GATEWAY_VOLUME}`
9128
+ );
9129
+ }
8997
9130
  if (existing?.config.edgeHost !== void 0 && config.edgeHost === void 0) {
8998
9131
  runtime.writeLine(
8999
9132
  `The edge for ${existing.config.edgeHost} is gone. Its certificate volumes stay until you remove them: docker --context ${config.dockerContext} volume rm mend_mend-edge-data mend_mend-edge-config`
@@ -9627,6 +9760,15 @@ var serverStatus = async (runtime, installation) => {
9627
9760
  }
9628
9761
  for (const line of await mirrorStatusLines(runtime, installation, runningServices))
9629
9762
  runtime.writeLine(line);
9763
+ if (config.t3GatewayPort !== void 0 && runningServices.includes("mend")) {
9764
+ const gateway = await runtime.fetchText(
9765
+ `http://127.0.0.1:${config.t3GatewayPort}/.well-known/t3/environment`,
9766
+ 2e3
9767
+ );
9768
+ runtime.writeLine(
9769
+ gateway.error === void 0 && gateway.status === 200 ? `t3code gateway \xB7 observed answering at 127.0.0.1:${config.t3GatewayPort} from this machine` : `t3code gateway \xB7 not observed at 127.0.0.1:${config.t3GatewayPort} from this machine \xB7 mend server logs shows what it said`
9770
+ );
9771
+ }
9630
9772
  if (!runningServices.includes("mend")) {
9631
9773
  runtime.writeLine("Mend is stopped. No health claim was made.");
9632
9774
  return;
@@ -9743,6 +9885,7 @@ var nodeServerRuntime = () => {
9743
9885
  dockerDaemonFacts: hostDockerDaemonFacts,
9744
9886
  readLogin: (configDir) => savedLogin(configDir, environment),
9745
9887
  probeSsh: probeSshFromHere,
9888
+ portTaken: portTakenHere,
9746
9889
  readStdin: async () => {
9747
9890
  const chunks = [];
9748
9891
  for await (const chunk of process.stdin)
@@ -9774,6 +9917,11 @@ var sshBannerAt = async (host, port, timeoutMs) => {
9774
9917
  socket.destroy();
9775
9918
  }
9776
9919
  };
9920
+ var portTakenHere = (port) => new Promise((resolve8) => {
9921
+ const server = net3.createServer();
9922
+ server.once("error", (error) => resolve8(error.code === "EADDRINUSE"));
9923
+ server.listen(port, "127.0.0.1", () => server.close(() => resolve8(false)));
9924
+ });
9777
9925
  var probeSshFromHere = async (bind, port) => {
9778
9926
  const unspecified = bind === "0.0.0.0" || bind === "::";
9779
9927
  const addresses = unspecified ? Object.values(os10.networkInterfaces()).flatMap((entries) => entries ?? []).filter(
@@ -10748,11 +10896,65 @@ var writeWorkspaceSshConfig = (configFile, target, identityFile) => {
10748
10896
  try {
10749
10897
  fs18.mkdirSync(path18.dirname(configFile), { recursive: true, mode: 448 });
10750
10898
  fs18.chmodSync(path18.dirname(configFile), 448);
10751
- fs18.writeFileSync(configFile, reconciled.value, { mode: 384 });
10752
- fs18.chmodSync(configFile, 384);
10899
+ replaceFileAtomically(configFile, reconciled.value, 384);
10753
10900
  return success(void 0);
10754
10901
  } catch (cause) {
10755
- return failure(new WorkspaceSshError("config", `Could not write ${configFile}.`, cause));
10902
+ return failure(
10903
+ new WorkspaceSshError(
10904
+ "config",
10905
+ `Could not write ${configFile}${cause instanceof Error ? `: ${cause.message}` : "."}`,
10906
+ cause
10907
+ )
10908
+ );
10909
+ }
10910
+ };
10911
+ var linkTarget = (file) => {
10912
+ let current = file;
10913
+ for (let hops = 0; hops < 40; hops += 1) {
10914
+ let stat;
10915
+ try {
10916
+ stat = fs18.lstatSync(current);
10917
+ } catch {
10918
+ if (current !== file && !fs18.existsSync(path18.dirname(current))) {
10919
+ throw new Error(
10920
+ `${file} is a symlink to ${current}, whose directory does not exist. Create it, or replace the link with a file; Mend left the link as it is.`
10921
+ );
10922
+ }
10923
+ return current;
10924
+ }
10925
+ if (!stat.isSymbolicLink()) return current;
10926
+ current = path18.resolve(path18.dirname(current), fs18.readlinkSync(current));
10927
+ }
10928
+ throw new Error(`${file} is a chain of symlinks too long to follow; Mend left it as it is.`);
10929
+ };
10930
+ var replaceFileAtomically = (file, contents, mode) => {
10931
+ const destination = linkTarget(file);
10932
+ const temporary = path18.join(
10933
+ path18.dirname(destination),
10934
+ `.${path18.basename(destination)}.mend-${process.pid}-${createHash3("sha256").update(`${Date.now()}:${Math.random()}`).digest("hex").slice(0, 12)}`
10935
+ );
10936
+ let descriptor = null;
10937
+ try {
10938
+ descriptor = fs18.openSync(temporary, "wx", mode);
10939
+ fs18.writeFileSync(descriptor, contents);
10940
+ fs18.fsyncSync(descriptor);
10941
+ fs18.closeSync(descriptor);
10942
+ descriptor = null;
10943
+ fs18.chmodSync(temporary, mode);
10944
+ fs18.renameSync(temporary, destination);
10945
+ } catch (cause) {
10946
+ if (descriptor !== null) fs18.closeSync(descriptor);
10947
+ fs18.rmSync(temporary, { force: true });
10948
+ throw cause;
10949
+ }
10950
+ try {
10951
+ const directory = fs18.openSync(path18.dirname(destination), "r");
10952
+ try {
10953
+ fs18.fsyncSync(directory);
10954
+ } finally {
10955
+ fs18.closeSync(directory);
10956
+ }
10957
+ } catch {
10756
10958
  }
10757
10959
  };
10758
10960
 
@@ -11112,6 +11314,17 @@ var describeUninstall = async (runtime, scope) => {
11112
11314
  dockerContext: read.value.config.dockerContext,
11113
11315
  edgeHost: read.value.config.edgeHost ?? null,
11114
11316
  mirrors: mirrorServices(read.value.config.mirrors),
11317
+ t3GatewayVolume: read.value.config.t3GatewayPort !== void 0 || (await runtime.server.run(
11318
+ "docker",
11319
+ dockerArgs(
11320
+ read.value.config.dockerContext,
11321
+ "volume",
11322
+ "inspect",
11323
+ `mend_${T3_GATEWAY_VOLUME}`,
11324
+ "--format",
11325
+ "{{json .}}"
11326
+ )
11327
+ )).status === 0,
11115
11328
  generations: countEntries(path20.join(configDir, "generations")),
11116
11329
  backups: countEntries(path20.join(configDir, "backups"))
11117
11330
  };
@@ -11145,7 +11358,9 @@ var planLines = (plan, configDir) => {
11145
11358
  const edge = [...edgeHost === null ? [] : ["edge"], ...mirrors];
11146
11359
  const edgeVolumes = [
11147
11360
  ...edgeHost === null ? [] : ["mend-edge-data", "mend-edge-config"],
11148
- ...mirrors.map((service) => `mend-${service}`)
11361
+ ...mirrors.map((service) => `mend-${service}`),
11362
+ // The t3code gateway's state, with paired people's device tokens, when it is there.
11363
+ ...plan.server.t3GatewayVolume === true ? [T3_GATEWAY_VOLUME] : []
11149
11364
  ];
11150
11365
  lines.push(
11151
11366
  ` containers ${["mend", "postgres", "garage", ...edge].join(", ")} \xB7 volumes ${[MEND_DOCKER_NAMESPACE_WITH_GARAGE.store, ...secondaryVolumesOf(MEND_DOCKER_NAMESPACE_WITH_GARAGE), "mend-config", "mend-ssh", "mend-postgres", ...edgeVolumes].join(", ")} \xB7 image ghcr.io/sealant-sh/mend:${version}${edgeHost === null ? "" : ` \xB7 the edge for ${edgeHost}`}`
@@ -11211,6 +11426,24 @@ var removeServer = async (runtime, failures, leftovers) => {
11211
11426
  server.writeLine(
11212
11427
  `removed containers ${["mend", "postgres", "garage", ...mirrorServices(installation.config.mirrors)].join(", ")} and the Compose-owned volumes`
11213
11428
  );
11429
+ const gatewayVolume = `mend_${T3_GATEWAY_VOLUME}`;
11430
+ const gatewayLeft = await server.run(
11431
+ "docker",
11432
+ dockerArgs(context, "volume", "inspect", gatewayVolume, "--format", "{{json .}}")
11433
+ );
11434
+ if (gatewayLeft.status === 0) {
11435
+ const gone = await server.run(
11436
+ "docker",
11437
+ dockerArgs(context, "volume", "rm", gatewayVolume)
11438
+ );
11439
+ if (gone.status === 0) {
11440
+ server.writeLine(`removed volume ${gatewayVolume}, the t3code gateway's state`);
11441
+ } else {
11442
+ failures.push(
11443
+ `could not remove volume ${gatewayVolume} (the t3code gateway's state, with paired device tokens): ${(gone.error ?? gone.stderr.trim()) || "no output"}`
11444
+ );
11445
+ }
11446
+ }
11214
11447
  const namespace = installation.config.bucket === "garage" ? MEND_DOCKER_NAMESPACE_WITH_GARAGE : MEND_DOCKER_NAMESPACE;
11215
11448
  const dataVolumes = [namespace.store, ...secondaryVolumesOf(namespace)];
11216
11449
  const identity = store.readIdentity();
@@ -1,4 +1,4 @@
1
- .TH MEND-ACCOUNTS 1 "" "mend 0.36.0\-next.684" "mend manual"
1
+ .TH MEND-ACCOUNTS 1 "" "mend 0.36.0\-next.708" "mend manual"
2
2
  .SH NAME
3
3
  mend\-accounts \- your connected accounts on the platform
4
4
  .SH SYNOPSIS
package/man/mend-adopt.1 CHANGED
@@ -1,4 +1,4 @@
1
- .TH MEND-ADOPT 1 "" "mend 0.36.0\-next.684" "mend manual"
1
+ .TH MEND-ADOPT 1 "" "mend 0.36.0\-next.708" "mend manual"
2
2
  .SH NAME
3
3
  mend\-adopt \- adopt a repository into the store
4
4
  .SH SYNOPSIS
package/man/mend-attach.1 CHANGED
@@ -1,4 +1,4 @@
1
- .TH MEND-ATTACH 1 "" "mend 0.36.0\-next.684" "mend manual"
1
+ .TH MEND-ATTACH 1 "" "mend 0.36.0\-next.708" "mend manual"
2
2
  .SH NAME
3
3
  mend\-attach \- reattach this terminal to a running session
4
4
  .SH SYNOPSIS
package/man/mend-codex.1 CHANGED
@@ -1,4 +1,4 @@
1
- .TH MEND-CODEX 1 "" "mend 0.36.0\-next.684" "mend manual"
1
+ .TH MEND-CODEX 1 "" "mend 0.36.0\-next.708" "mend manual"
2
2
  .SH NAME
3
3
  mend\-codex \- launch codex, claude, opencode or pi in a recorded worktree
4
4
  .SH SYNOPSIS
@@ -1,4 +1,4 @@
1
- .TH MEND-COMPLETIONS 1 "" "mend 0.36.0\-next.684" "mend manual"
1
+ .TH MEND-COMPLETIONS 1 "" "mend 0.36.0\-next.708" "mend manual"
2
2
  .SH NAME
3
3
  mend\-completions \- print the TAB\-completion hook
4
4
  .SH SYNOPSIS
@@ -1,4 +1,4 @@
1
- .TH MEND-CONNECT-PI 1 "" "mend 0.36.0\-next.684" "mend manual"
1
+ .TH MEND-CONNECT-PI 1 "" "mend 0.36.0\-next.708" "mend manual"
2
2
  .SH NAME
3
3
  mend\-connect\-pi \- send your pi setup to every pi session of yours
4
4
  .SH SYNOPSIS
@@ -1,4 +1,4 @@
1
- .TH MEND-CONNECT 1 "" "mend 0.36.0\-next.684" "mend manual"
1
+ .TH MEND-CONNECT 1 "" "mend 0.36.0\-next.708" "mend manual"
2
2
  .SH NAME
3
3
  mend\-connect \- send this machine's provider credential to the platform
4
4
  .SH SYNOPSIS
@@ -1,4 +1,4 @@
1
- .TH MEND-CONTINUE 1 "" "mend 0.36.0\-next.684" "mend manual"
1
+ .TH MEND-CONTINUE 1 "" "mend 0.36.0\-next.708" "mend manual"
2
2
  .SH NAME
3
3
  mend\-continue \- resume a session with its pending review follow\-up
4
4
  .SH SYNOPSIS
package/man/mend-doctor.1 CHANGED
@@ -1,4 +1,4 @@
1
- .TH MEND-DOCTOR 1 "" "mend 0.36.0\-next.684" "mend manual"
1
+ .TH MEND-DOCTOR 1 "" "mend 0.36.0\-next.708" "mend manual"
2
2
  .SH NAME
3
3
  mend\-doctor \- check this machine's setup, or bundle it for a bug report
4
4
  .SH SYNOPSIS
@@ -1,4 +1,4 @@
1
- .TH MEND-DOTFILES-REPO 1 "" "mend 0.36.0\-next.684" "mend manual"
1
+ .TH MEND-DOTFILES-REPO 1 "" "mend 0.36.0\-next.708" "mend manual"
2
2
  .SH NAME
3
3
  mend\-dotfiles\-repo \- set or clear the repository the server clones at launch
4
4
  .SH SYNOPSIS
@@ -1,4 +1,4 @@
1
- .TH MEND-DOTFILES-SYNC 1 "" "mend 0.36.0\-next.684" "mend manual"
1
+ .TH MEND-DOTFILES-SYNC 1 "" "mend 0.36.0\-next.708" "mend manual"
2
2
  .SH NAME
3
3
  mend\-dotfiles\-sync \- capture config files from this machine into your store
4
4
  .SH SYNOPSIS
@@ -1,4 +1,4 @@
1
- .TH MEND-DOTFILES 1 "" "mend 0.36.0\-next.684" "mend manual"
1
+ .TH MEND-DOTFILES 1 "" "mend 0.36.0\-next.708" "mend manual"
2
2
  .SH NAME
3
3
  mend\-dotfiles \- your dotfiles on the server: repo and synced files
4
4
  .SH SYNOPSIS
@@ -1,4 +1,4 @@
1
- .TH MEND-ENV-CLUSTER 1 "" "mend 0.36.0\-next.684" "mend manual"
1
+ .TH MEND-ENV-CLUSTER 1 "" "mend 0.36.0\-next.708" "mend manual"
2
2
  .SH NAME
3
3
  mend\-env\-cluster \- bind Kubernetes secrets and configmaps to the workspaces
4
4
  .SH SYNOPSIS
@@ -1,4 +1,4 @@
1
- .TH MEND-ENV-LOAD 1 "" "mend 0.36.0\-next.684" "mend manual"
1
+ .TH MEND-ENV-LOAD 1 "" "mend 0.36.0\-next.708" "mend manual"
2
2
  .SH NAME
3
3
  mend\-env\-load \- load a .env into the project
4
4
  .SH SYNOPSIS
@@ -1,4 +1,4 @@
1
- .TH MEND-ENV-SHOW 1 "" "mend 0.36.0\-next.684" "mend manual"
1
+ .TH MEND-ENV-SHOW 1 "" "mend 0.36.0\-next.708" "mend manual"
2
2
  .SH NAME
3
3
  mend\-env\-show \- what the project store holds: names only, never values
4
4
  .SH SYNOPSIS