@sealant/mend 0.36.0-next.643 → 0.36.0-next.646

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 (91) hide show
  1. package/README.md +4 -1
  2. package/dist/{chunk-2TDRYRGO.js → chunk-ASHAV3UV.js} +259 -0
  3. package/dist/{dashboard-2HF3KTTU.js → dashboard-4J2WMT3G.js} +134 -17
  4. package/dist/main.js +646 -461
  5. package/man/mend-accounts.1 +1 -1
  6. package/man/mend-adopt.1 +1 -1
  7. package/man/mend-attach.1 +1 -1
  8. package/man/mend-codex.1 +3 -1
  9. package/man/mend-completions.1 +1 -1
  10. package/man/mend-connect-pi.1 +1 -1
  11. package/man/mend-connect.1 +3 -1
  12. package/man/mend-continue.1 +1 -1
  13. package/man/mend-doctor.1 +1 -1
  14. package/man/mend-dotfiles-repo.1 +1 -1
  15. package/man/mend-dotfiles-sync.1 +1 -1
  16. package/man/mend-dotfiles.1 +1 -1
  17. package/man/mend-env-cluster.1 +1 -1
  18. package/man/mend-env-load.1 +1 -1
  19. package/man/mend-env-show.1 +1 -1
  20. package/man/mend-folder-create.1 +1 -1
  21. package/man/mend-folder-list.1 +1 -1
  22. package/man/mend-folder-push.1 +1 -1
  23. package/man/mend-folder-rm.1 +1 -1
  24. package/man/mend-git-author.1 +1 -1
  25. package/man/mend-help.1 +1 -1
  26. package/man/mend-invite.1 +1 -1
  27. package/man/mend-keys-init.1 +1 -1
  28. package/man/mend-keys-mode.1 +1 -1
  29. package/man/mend-keys-share.1 +1 -1
  30. package/man/mend-keys-show.1 +1 -1
  31. package/man/mend-land.1 +1 -1
  32. package/man/mend-login.1 +1 -1
  33. package/man/mend-logout.1 +1 -1
  34. package/man/mend-man.1 +1 -1
  35. package/man/mend-members.1 +1 -1
  36. package/man/mend-memory-import.1 +1 -1
  37. package/man/mend-memory-rm.1 +1 -1
  38. package/man/mend-memory-show.1 +1 -1
  39. package/man/mend-memory.1 +1 -1
  40. package/man/mend-models.1 +1 -1
  41. package/man/mend-operator-exposure.1 +1 -1
  42. package/man/mend-operator-gate.1 +1 -1
  43. package/man/mend-operator-grant-owner.1 +1 -1
  44. package/man/mend-operator-org-create.1 +1 -1
  45. package/man/mend-operator-org-invite-owner.1 +1 -1
  46. package/man/mend-operator-org-list.1 +1 -1
  47. package/man/mend-operator-org-rename.1 +1 -1
  48. package/man/mend-operator-reset-link.1 +1 -1
  49. package/man/mend-pair.1 +1 -1
  50. package/man/mend-projects.1 +1 -1
  51. package/man/mend-pull.1 +1 -1
  52. package/man/mend-refresh.1 +1 -1
  53. package/man/mend-rejoin.1 +1 -1
  54. package/man/mend-resume.1 +1 -1
  55. package/man/mend-run.1 +1 -1
  56. package/man/mend-secrets-add.1 +1 -1
  57. package/man/mend-secrets-rm.1 +1 -1
  58. package/man/mend-secrets.1 +1 -1
  59. package/man/mend-server-logs.1 +1 -1
  60. package/man/mend-server-restart.1 +1 -1
  61. package/man/mend-server-setup.1 +1 -1
  62. package/man/mend-server-start.1 +1 -1
  63. package/man/mend-server-status.1 +1 -1
  64. package/man/mend-server-stop.1 +1 -1
  65. package/man/mend-server-upgrade.1 +1 -1
  66. package/man/mend-server.1 +1 -1
  67. package/man/mend-service-add.1 +1 -1
  68. package/man/mend-service-connect.1 +1 -1
  69. package/man/mend-service-init.1 +1 -1
  70. package/man/mend-service-list.1 +1 -1
  71. package/man/mend-service-logs.1 +1 -1
  72. package/man/mend-service-restart.1 +1 -1
  73. package/man/mend-service-run.1 +1 -1
  74. package/man/mend-service-stop.1 +1 -1
  75. package/man/mend-session-share.1 +13 -3
  76. package/man/mend-sessions.1 +3 -1
  77. package/man/mend-shell.1 +1 -1
  78. package/man/mend-skills-push.1 +1 -1
  79. package/man/mend-skills.1 +1 -1
  80. package/man/mend-snake.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-workspace-replace.1 +24 -0
  88. package/man/mend-worktrees-rm.1 +1 -1
  89. package/man/mend-worktrees.1 +1 -1
  90. package/man/mend.1 +5 -2
  91. package/package.json +2 -2
package/dist/main.js CHANGED
@@ -13,14 +13,17 @@ import {
13
13
  PI_PROFILE_AGENT_PATH,
14
14
  PI_PROFILE_LOCAL_PACKAGES,
15
15
  PI_PROFILE_MAX_FILE_BYTES,
16
+ REPLACE_WORKSPACE_ACTION,
16
17
  WORKTREE_REMOVAL_FORCE_HINT,
17
18
  agentIsLive,
18
19
  agentMemoryNameOf,
19
20
  agentOutcome,
20
21
  agentStartingFacts,
21
22
  agentStartingLine,
23
+ askYesNo,
22
24
  captureLineOf,
23
25
  claudeGrantFacts,
26
+ confirmPlan,
24
27
  createSseParser,
25
28
  csiUKeysOf,
26
29
  cwdFacts,
@@ -29,12 +32,14 @@ import {
29
32
  gitCurrentBranch,
30
33
  gitOriginUrl,
31
34
  gitTopLevel,
35
+ hasPersonFacts,
32
36
  hostUserNamespacesFix,
33
37
  hostUserNamespacesOf,
34
38
  isDetachChunk,
35
39
  isPasteChunk,
36
40
  landingFactLine,
37
41
  landingFactsFromWire,
42
+ launcherNameOf,
38
43
  matchProjectByCwd,
39
44
  narrowCredential,
40
45
  noAnswerError,
@@ -43,16 +48,27 @@ import {
43
48
  normalizeRemoteUrl,
44
49
  parseLaunchArgs,
45
50
  pasteBytes,
51
+ replaceConfirmLines,
46
52
  repositoryCloneUrlIssue,
47
53
  sameGrant,
48
54
  servicesHoldOf,
49
55
  sessionDisplayName,
56
+ sessionWorkspaceLines,
57
+ sharedControlConfirm,
58
+ sharedControlConfirmLines,
59
+ sharedControlLine,
60
+ sharedControlQuestion,
50
61
  spoken,
51
62
  terminalReadOnlyLine,
52
63
  trackBracketedPaste,
53
64
  validatePiProfile,
54
- validateSecretFilePath
55
- } from "./chunk-2TDRYRGO.js";
65
+ validateSecretFilePath,
66
+ workspaceLineList,
67
+ workspaceReadsOf,
68
+ workspaceRetirementLine,
69
+ worktreeJoinLine,
70
+ worktreeListsPeople
71
+ } from "./chunk-ASHAV3UV.js";
56
72
 
57
73
  // src/main.ts
58
74
  import { spawn as spawn3, spawnSync as spawnSync6 } from "node:child_process";
@@ -1705,7 +1721,8 @@ var COMMANDS = [
1705
1721
  ],
1706
1722
  description: [
1707
1723
  "Sessions run on the platform, so the platform needs your provider login. It is stored under your own user and used only for your work. Nothing is shared with other users.",
1708
- "Claude and Codex get a login of Mend's own. Both rotate their refresh token, so two copies of one login fight and the one that refreshes second is signed out, and Mend's server refreshes on a schedule. So this logs in through the provider's own flow and your own login stays as it is: Claude in the browser, Codex with a device code, both sent and not kept here. Run it again whenever Mend says a login needs reconnecting. GitHub sends gh's token."
1724
+ "Claude and Codex get a login of Mend's own. Both rotate their refresh token, so two copies of one login fight and the one that refreshes second is signed out, and Mend's server refreshes on a schedule. So this logs in through the provider's own flow and your own login stays as it is: Claude in the browser, Codex with a device code, both sent and not kept here. Run it again whenever Mend says a login needs reconnecting. GitHub sends gh's token.",
1725
+ "In a per-person workspace each person's processes use their own GitHub login, in their own home: git over HTTPS to GitHub reads it through Mend's credential helper, and no GITHUB_TOKEN is set in the environment. A command that needs the token takes it for itself: GITHUB_TOKEN=$(/run/mend/bin/mend-git-credential token) <command>."
1709
1726
  ],
1710
1727
  options: [
1711
1728
  {
@@ -1774,6 +1791,7 @@ var COMMANDS = [
1774
1791
  description: [
1775
1792
  "mend codex, mend claude, mend opencode and mend pi are the same command with a different harness. The session runs in a workspace on the platform, in its own git worktree, and everything it does is recorded. This terminal attaches to it.",
1776
1793
  "The worktree's name is asked first. --name skips the ask; an existing name joins that worktree as a new session. --worktree joins only and fails if the name is unknown. A quoted prompt becomes the first message.",
1794
+ "When another person's session is running in the worktree you join, the launch says so before the session starts: you share its workspace, everything you run runs as you, on your own logins, and either of you can read the other's files, logins included.",
1777
1795
  "Detach with Ctrl+] and the session keeps running. Reattach from any terminal with mend attach, or from the phone.",
1778
1796
  tunnelText,
1779
1797
  "Ctrl+V with an image on this machine's clipboard sends the image to the session and pastes its path; codex and claude read it. Needs wl-paste on Wayland, xclip on X11, nothing extra on macOS.",
@@ -1998,6 +2016,7 @@ var COMMANDS = [
1998
2016
  synopsis: ["[--all] [--project <p>] [--json | --json=v2]"],
1999
2017
  description: [
2000
2018
  "One line per session: harness, worktree, status, and what the review found. Live sessions by default.",
2019
+ "Under a live session, a line each when there is something to say about its workspace: who else is live in it (Shared workspace with Anna), the waiting line while a turn waits for another person's work, and the line of a workspace that started before Mend 0.36 and waits to be replaced. The change's owner also reads how to replace it, and what would stop.",
2001
2020
  "The JSON is stable for integrations. --json is the v1 flat list; --json=v2 groups sessions by worktree, the same shape mend worktrees prints."
2002
2021
  ],
2003
2022
  options: [
@@ -2036,6 +2055,21 @@ var COMMANDS = [
2036
2055
  ],
2037
2056
  see: ["worktrees", "land", "stop"]
2038
2057
  },
2058
+ {
2059
+ name: "workspace replace",
2060
+ section: "sessions",
2061
+ summary: "replace a workspace that started before Mend 0.36",
2062
+ synopsis: ["<session> [--yes]"],
2063
+ description: [
2064
+ `${REPLACE_WORKSPACE_ACTION}, from a terminal. A workspace that shares one home, as every workspace started before Mend 0.36 does, takes only its launcher's sessions and turns once its worktree runs each person as themselves, until it is replaced. Mend replaces it on its own when nothing would stop; otherwise the change's owner does, here or on the web.`,
2065
+ "It prints what was checked, and when: Mend's records, and the processes in the workspace and its running containers once they have been checked. Then what would stop, one line each: terminal sessions (they end resumable), shells, Services started by hand, processes Mend did not start, running containers and anything that could not be checked. Mend starts the launching session's mend.toml Services again.",
2066
+ "The replacement names what it showed you: when more would stop by the time you answer, the server refuses, nothing is stopped, and its words are printed as they are; run it again to look at the list again. An agent turn in flight is never stopped: the server refuses the same way. The workspace goes once its last save is done.",
2067
+ "A prefix of the session id is enough. mend sessions shows which sessions wait for this."
2068
+ ],
2069
+ options: [{ flag: "--yes", text: "replace without asking; required without a terminal" }],
2070
+ examples: [{ command: "mend workspace replace 3f2a", text: "" }],
2071
+ see: ["sessions", "stop"]
2072
+ },
2039
2073
  {
2040
2074
  name: "projects",
2041
2075
  section: "sessions",
@@ -2572,9 +2606,18 @@ var COMMANDS = [
2572
2606
  name: "session share",
2573
2607
  section: "organization",
2574
2608
  summary: "let everyone who can see a session steer it, or stop",
2575
- synopsis: ["<session> on|off"],
2609
+ synopsis: ["<session> on|off [--yes]"],
2576
2610
  description: [
2577
- "The session's owner turns shared control on or off; an organization owner may turn it off. While it is on, anyone who can see the project sends turns, answers approvals and interrupts, using your provider logins and Git access. They can read the terminal; only the owner types in it, opens a shell or starts a Service. Every act is recorded with who did it. A prefix of the session id is enough."
2611
+ "The session's owner turns shared control on or off; an organization owner may turn it off. While it is on, anyone who can see the project sends turns, answers approvals and interrupts. They can read the terminal; only the owner types in it, opens a shell or starts a Service. Every act is recorded with who did it. A prefix of the session id is enough.",
2612
+ "Turning it on asks first, in every worktree, in the words true to it; --yes answers for a script, and is required without a terminal. Turning it off asks nothing.",
2613
+ `In a worktree that runs each person as themselves, it asks: ${sharedControlConfirm(true).body}`,
2614
+ `Otherwise it asks: ${sharedControlConfirm(false).body}`
2615
+ ],
2616
+ options: [
2617
+ {
2618
+ flag: "--yes",
2619
+ text: "turn it on without asking; required without a terminal"
2620
+ }
2578
2621
  ],
2579
2622
  examples: [{ command: "mend session share 3f2a on", text: "" }],
2580
2623
  see: ["sessions"]
@@ -3703,7 +3746,7 @@ var TIMEOUT_MS = 3e3;
3703
3746
  var MARKS = { ok: "\u2713", todo: "\u25CB", failed: "\u2717" };
3704
3747
  var LABEL_WIDTH = 11;
3705
3748
  var day = (at) => at.toISOString().slice(0, 10);
3706
- var formatCheck = (check, paint6 = (_state, mark) => mark) => `${paint6(check.state, MARKS[check.state])} ${check.label.padEnd(LABEL_WIDTH)} ${check.detail}${check.fix === null ? "" : ` \u2192 ${check.fix}`}`;
3749
+ var formatCheck = (check, paint7 = (_state, mark) => mark) => `${paint7(check.state, MARKS[check.state])} ${check.label.padEnd(LABEL_WIDTH)} ${check.detail}${check.fix === null ? "" : ` \u2192 ${check.fix}`}`;
3707
3750
  var getJson = async (config, route) => {
3708
3751
  try {
3709
3752
  const response = await fetch(`${config.url}/api${route}`, {
@@ -4103,7 +4146,7 @@ var dotfilesRepositoryFacts = (repository) => [
4103
4146
  ].join(" \xB7 ");
4104
4147
 
4105
4148
  // src/env.ts
4106
- var formatLoadReport = (report, paint6) => {
4149
+ var formatLoadReport = (report, paint7) => {
4107
4150
  const width = Math.max(
4108
4151
  0,
4109
4152
  ...report.loaded.map((entry) => entry.name.length),
@@ -4112,12 +4155,12 @@ var formatLoadReport = (report, paint6) => {
4112
4155
  const lines = [];
4113
4156
  for (const entry of report.loaded) {
4114
4157
  lines.push(
4115
- ` ${entry.name.padEnd(width)} ${entry.lane === "secret" ? "secret" : "configuration"} ${paint6.dim(`\xB7 ${entry.action}${entry.lane === "configuration" ? " \xB7 plaintext" : ""}`)}`
4158
+ ` ${entry.name.padEnd(width)} ${entry.lane === "secret" ? "secret" : "configuration"} ${paint7.dim(`\xB7 ${entry.action}${entry.lane === "configuration" ? " \xB7 plaintext" : ""}`)}`
4116
4159
  );
4117
4160
  }
4118
4161
  for (const entry of report.rejected) {
4119
4162
  lines.push(
4120
- ` ${entry.name.padEnd(width)} ${paint6.warn("rejected")} ${paint6.dim(`\xB7 ${entry.reason}`)}`
4163
+ ` ${entry.name.padEnd(width)} ${paint7.warn("rejected")} ${paint7.dim(`\xB7 ${entry.reason}`)}`
4121
4164
  );
4122
4165
  }
4123
4166
  return lines;
@@ -4866,7 +4909,7 @@ var contiguousIn = (efforts, scale) => {
4866
4909
  return from >= 0 && efforts.every((effort, index) => scale[from + index] === effort);
4867
4910
  };
4868
4911
  var effortRange = (efforts, scale) => efforts.length === 0 ? "none" : efforts.length <= 2 || !contiguousIn(efforts, scale) ? efforts.join(", ") : `${efforts[0]} \u2026 ${efforts.at(-1)}`;
4869
- var modelCatalogLines = (catalogs, dim7 = (text) => text) => {
4912
+ var modelCatalogLines = (catalogs, dim8 = (text) => text) => {
4870
4913
  if (catalogs.length === 0)
4871
4914
  return ["no models listed \xB7 the server's harness_models table is empty"];
4872
4915
  const lines = [];
@@ -4874,7 +4917,7 @@ var modelCatalogLines = (catalogs, dim7 = (text) => text) => {
4874
4917
  if (index > 0) lines.push("");
4875
4918
  const efforts = effortRange(catalog.efforts, catalog.efforts);
4876
4919
  lines.push(
4877
- `${catalog.harness} ${dim7(`effort ${efforts}${catalog.fastCapable ? " \xB7 --fast" : ""}`)}`
4920
+ `${catalog.harness} ${dim8(`effort ${efforts}${catalog.fastCapable ? " \xB7 --fast" : ""}`)}`
4878
4921
  );
4879
4922
  const idWidth = Math.max(...catalog.models.map((model) => model.id.length));
4880
4923
  for (const model of catalog.models) {
@@ -4884,10 +4927,10 @@ var modelCatalogLines = (catalogs, dim7 = (text) => text) => {
4884
4927
  facts.push(`effort ${effortRange(model.efforts, catalog.efforts)}`);
4885
4928
  }
4886
4929
  lines.push(
4887
- ` ${model.id.padEnd(idWidth)} ${model.label}${facts.length === 0 ? "" : ` ${dim7(facts.join(" \xB7 "))}`}`
4930
+ ` ${model.id.padEnd(idWidth)} ${model.label}${facts.length === 0 ? "" : ` ${dim8(facts.join(" \xB7 "))}`}`
4888
4931
  );
4889
4932
  }
4890
- if (catalog.models.length === 0) lines.push(` ${dim7("no models listed \xB7 the harness picks")}`);
4933
+ if (catalog.models.length === 0) lines.push(` ${dim8("no models listed \xB7 the harness picks")}`);
4891
4934
  }
4892
4935
  return lines;
4893
4936
  };
@@ -5058,10 +5101,13 @@ var folderCommand = async (api2, args) => {
5058
5101
  return fail4(`unknown folder command "${verb}" \xB7 mend help folder`);
5059
5102
  }
5060
5103
  };
5061
- var sessionShareCommand = async (api2, args) => {
5062
- const [prefix, state] = args.filter((arg) => !arg.startsWith("--"));
5104
+ var sessionShareCommand = async (api2, args, io = {
5105
+ interactive: process.stdin.isTTY === true && process.stdout.isTTY === true,
5106
+ ask: askYesNo
5107
+ }) => {
5108
+ const [prefix, state] = args.filter((arg) => !arg.startsWith("-"));
5063
5109
  if (prefix === void 0 || state !== "on" && state !== "off") {
5064
- return fail4("usage: mend session share <session> on|off");
5110
+ return fail4("usage: mend session share <session> on|off [--yes]");
5065
5111
  }
5066
5112
  const sessions = await api2(
5067
5113
  "GET",
@@ -5073,10 +5119,28 @@ var sessionShareCommand = async (api2, args) => {
5073
5119
  return fail4(`"${prefix}" matches ${matches.length} sessions; type more of the id`);
5074
5120
  const [session] = matches;
5075
5121
  if (session === void 0) return fail4(`no live session starts with "${prefix}"`);
5076
- await api2("PUT", `/sessions/${session.id}/shared-control`, { enabled: state === "on" });
5077
- say4(
5078
- state === "on" ? `${green4("\u2713")} shared control on \xB7 ${session.harness} ${dim4(session.id.slice(0, 8))} \xB7 everyone who can see the project steers it on your credentials` : `${green4("\u2713")} shared control off \xB7 ${session.harness} ${dim4(session.id.slice(0, 8))}`
5122
+ if (state === "off") {
5123
+ await api2("PUT", `/sessions/${session.id}/shared-control`, { enabled: false });
5124
+ say4(`${green4("\u2713")} shared control off \xB7 ${session.harness} ${dim4(session.id.slice(0, 8))}`);
5125
+ return;
5126
+ }
5127
+ const plan = confirmPlan(args, io.interactive);
5128
+ if (plan === "refuse") return fail4("non-interactive \xB7 pass --yes to turn shared control on");
5129
+ const detail = await api2(
5130
+ "GET",
5131
+ `/sessions/${session.id}`
5079
5132
  );
5133
+ const turnsOnSendersLogin = detail.control?.turnsOnSendersLogin === true;
5134
+ if (plan === "ask") {
5135
+ for (const line of sharedControlConfirmLines(turnsOnSendersLogin)) say4(line);
5136
+ if (!await io.ask(sharedControlQuestion(turnsOnSendersLogin))) {
5137
+ say4(dim4("shared control stays off"));
5138
+ return;
5139
+ }
5140
+ }
5141
+ await api2("PUT", `/sessions/${session.id}/shared-control`, { enabled: true });
5142
+ say4(`${green4("\u2713")} shared control on \xB7 ${session.harness} ${dim4(session.id.slice(0, 8))}`);
5143
+ say4(dim4(sharedControlLine(turnsOnSendersLogin)));
5080
5144
  };
5081
5145
  var renderGate = (items) => {
5082
5146
  const width = Math.max(...items.map((item) => item.id.length));
@@ -9689,6 +9753,65 @@ var upgradeUrl = async (input) => {
9689
9753
  return url;
9690
9754
  };
9691
9755
 
9756
+ // src/workspace-replace.ts
9757
+ var paint5 = (code) => (text) => process.stdout.isTTY === true ? `\x1B[${code}m${text}\x1B[0m` : text;
9758
+ var dim6 = paint5("2");
9759
+ var green6 = paint5("32");
9760
+ var say6 = (line) => process.stdout.write(`${line}
9761
+ `);
9762
+ var fail6 = (message) => {
9763
+ process.stderr.write(`mend: ${message}
9764
+ `);
9765
+ process.exit(1);
9766
+ };
9767
+ var WORKSPACE_REPLACE_USAGE = "usage: mend workspace replace <session> [--yes]";
9768
+ var terminalIo = () => ({
9769
+ interactive: process.stdin.isTTY === true && process.stdout.isTTY === true,
9770
+ ask: askYesNo
9771
+ });
9772
+ var workspaceCommand = async (api2, tryApi, args, io = terminalIo()) => {
9773
+ const [verb, prefix] = args.filter((arg) => !arg.startsWith("-"));
9774
+ if (verb !== "replace" || prefix === void 0) return fail6(WORKSPACE_REPLACE_USAGE);
9775
+ const sessions = await api2("GET", "/sessions?retained=1");
9776
+ const matches = sessions.filter((session2) => session2.id.startsWith(prefix));
9777
+ if (matches.length > 1) {
9778
+ return fail6(`"${prefix}" matches ${matches.length} sessions; type more of the id`);
9779
+ }
9780
+ const [session] = matches;
9781
+ if (session === void 0) return fail6(`no live session starts with "${prefix}"`);
9782
+ const retirement = await tryApi(
9783
+ "GET",
9784
+ `/sessions/${session.id}/workspace-retirement`
9785
+ ).catch(() => null);
9786
+ if (retirement !== null) {
9787
+ const members = await tryApi(
9788
+ "GET",
9789
+ "/organization/members"
9790
+ ).catch(() => []);
9791
+ say6(
9792
+ dim6(
9793
+ workspaceRetirementLine(
9794
+ retirement,
9795
+ launcherNameOf(retirement.launcher, session.livePeople ?? [], members)
9796
+ )
9797
+ )
9798
+ );
9799
+ for (const line of replaceConfirmLines(retirement)) say6(line);
9800
+ const plan = confirmPlan(args, io.interactive);
9801
+ if (plan === "refuse") return fail6("non-interactive \xB7 pass --yes to replace the workspace");
9802
+ if (plan === "ask" && !await io.ask("replace it?")) {
9803
+ say6(dim6("nothing replaced"));
9804
+ return;
9805
+ }
9806
+ }
9807
+ await api2("POST", `/sessions/${session.id}/workspace-retirement/replace`, {
9808
+ seen: retirement?.fingerprint ?? ""
9809
+ });
9810
+ say6(
9811
+ `${green6("\u2713")} ${workspaceRetirementLine({ state: "retiring", preRelease: retirement?.preRelease ?? true, reason: null }, "")} ${dim6(`\xB7 ${session.harness} ${session.id.slice(0, 8)}`)}`
9812
+ );
9813
+ };
9814
+
9692
9815
  // src/worktree-remove.ts
9693
9816
  var parseWorktreesRmArgs = (args) => {
9694
9817
  let name = null;
@@ -9787,7 +9910,7 @@ var loadConfig = () => {
9787
9910
  try {
9788
9911
  fileConfig = JSON.parse(fs20.readFileSync(CONFIG_PATH, "utf8"));
9789
9912
  } catch {
9790
- fail6(`could not parse ${CONFIG_PATH}`);
9913
+ fail7(`could not parse ${CONFIG_PATH}`);
9791
9914
  }
9792
9915
  }
9793
9916
  const configuredUrl = process.env["MEND_URL"] ?? fileConfig.url ?? null;
@@ -9798,7 +9921,7 @@ var loadConfig = () => {
9798
9921
  deviceId: fileConfig.deviceId ?? null
9799
9922
  };
9800
9923
  };
9801
- var fail6 = (message) => {
9924
+ var fail7 = (message) => {
9802
9925
  process.stderr.write(`mend: ${message}
9803
9926
  `);
9804
9927
  process.exit(1);
@@ -9807,18 +9930,18 @@ var parseMendUrl = (value) => {
9807
9930
  try {
9808
9931
  return new URL(value);
9809
9932
  } catch {
9810
- return fail6(`"${value}" is not a valid Mend URL`);
9933
+ return fail7(`"${value}" is not a valid Mend URL`);
9811
9934
  }
9812
9935
  };
9813
- var paint5 = (code) => (text) => process.stdout.isTTY ? `\x1B[${code}m${text}\x1B[0m` : text;
9814
- var dim6 = paint5("2");
9815
- var green6 = paint5("32");
9816
- var amber2 = paint5("33");
9817
- var cobalt2 = paint5("34");
9818
- var say6 = (line) => process.stdout.write(`${line}
9936
+ var paint6 = (code) => (text) => process.stdout.isTTY ? `\x1B[${code}m${text}\x1B[0m` : text;
9937
+ var dim7 = paint6("2");
9938
+ var green7 = paint6("32");
9939
+ var amber2 = paint6("33");
9940
+ var cobalt2 = paint6("34");
9941
+ var say7 = (line) => process.stdout.write(`${line}
9819
9942
  `);
9820
9943
  var detachKeyEnabled = process.env["MEND_DETACH_KEY"] !== "none";
9821
- var detachHint = () => detachKeyEnabled ? ` \xB7 detach: ${dim6("Ctrl+]")}` : "";
9944
+ var detachHint = () => detachKeyEnabled ? ` \xB7 detach: ${dim7("Ctrl+]")}` : "";
9822
9945
  var herdrAgentOf = (harness) => {
9823
9946
  if (harness === "codex" || harness === "claude" || harness === "opencode") return harness;
9824
9947
  return null;
@@ -9886,6 +10009,7 @@ var request = async (config, method, route, body) => {
9886
10009
  }
9887
10010
  throw new MendRequestError("http", message, response.status);
9888
10011
  }
10012
+ if (text === "") return JSON.parse("null");
9889
10013
  try {
9890
10014
  return JSON.parse(text);
9891
10015
  } catch {
@@ -9896,7 +10020,7 @@ var api = async (config, method, route, body) => {
9896
10020
  try {
9897
10021
  return await request(config, method, route, body);
9898
10022
  } catch (error) {
9899
- return fail6(error instanceof Error ? error.message : String(error));
10023
+ return fail7(error instanceof Error ? error.message : String(error));
9900
10024
  }
9901
10025
  };
9902
10026
  var download = (config) => async (route) => {
@@ -9907,10 +10031,10 @@ var download = (config) => async (route) => {
9907
10031
  try {
9908
10032
  response = await fetch(`${config.url}/api${route}`, { headers });
9909
10033
  } catch (error) {
9910
- return fail6(noAnswerError(error, config.url, `GET ${route}`, Date.now() - started).message);
10034
+ return fail7(noAnswerError(error, config.url, `GET ${route}`, Date.now() - started).message);
9911
10035
  }
9912
10036
  if (response.status === 401) {
9913
- return fail6(
10037
+ return fail7(
9914
10038
  config.token === null ? `not signed in to ${config.url} \u2014 run: mend login` : `unauthorized at ${config.url} \u2014 the saved token was rejected; run: mend login`
9915
10039
  );
9916
10040
  }
@@ -9961,7 +10085,7 @@ var withSpinner = async (label, work) => {
9961
10085
  const seconds2 = Math.round((Date.now() - started) / 1e3);
9962
10086
  const text = typeof label === "string" ? label : label();
9963
10087
  process.stdout.write(
9964
- `\r\x1B[2K ${frames[frame % frames.length]} ${text} ${dim6(`${seconds2}s`)} `
10088
+ `\r\x1B[2K ${frames[frame % frames.length]} ${text} ${dim7(`${seconds2}s`)} `
9965
10089
  );
9966
10090
  frame += 1;
9967
10091
  }, 120);
@@ -9990,7 +10114,7 @@ var followStarting = async (config, sessionId, label, start) => {
9990
10114
  read: () => request(config, "GET", `/sessions/${sessionId}`),
9991
10115
  onLine: (next) => {
9992
10116
  line = next === "starting" ? label : next;
9993
- if (process.stdout.isTTY !== true) say6(dim6(` ${next}`));
10117
+ if (process.stdout.isTTY !== true) say7(dim7(` ${next}`));
9994
10118
  },
9995
10119
  sleep: sleep3,
9996
10120
  now: Date.now
@@ -10006,13 +10130,13 @@ var startedOrExit = (config, sessionId, outcome) => {
10006
10130
  case "live":
10007
10131
  return outcome.session;
10008
10132
  case "refused":
10009
- return fail6(outcome.message);
10133
+ return fail7(outcome.message);
10010
10134
  case "settled":
10011
- return fail6(
10135
+ return fail7(
10012
10136
  `session ${id8} \xB7 ${startingLineOf(outcome.session)} before its agent ran \xB7 ${config.url}/sessions/${sessionId}`
10013
10137
  );
10014
10138
  case "unreachable":
10015
- return fail6(
10139
+ return fail7(
10016
10140
  `${outcome.message} \xB7 the session may still be starting \xB7 follow it: mend attach ${id8}`
10017
10141
  );
10018
10142
  }
@@ -10023,7 +10147,7 @@ var adopt = async (config, args) => {
10023
10147
  const name = nameFlag !== -1 && args[nameFlag + 1] !== void 0 ? String(args[nameFlag + 1]) : null;
10024
10148
  const authFlagIndex = args.indexOf("--auth");
10025
10149
  if (args.includes("--private") && args.includes("--shared")) {
10026
- return fail6("--private and --shared pick one visibility; pass one of them");
10150
+ return fail7("--private and --shared pick one visibility; pass one of them");
10027
10151
  }
10028
10152
  const visibility = args.includes("--shared") ? "shared" : "private";
10029
10153
  const positional = args.filter(
@@ -10031,16 +10155,16 @@ var adopt = async (config, args) => {
10031
10155
  );
10032
10156
  const source = positional[0] ?? gitOriginUrl(process.cwd());
10033
10157
  if (source === null) {
10034
- return fail6(
10158
+ return fail7(
10035
10159
  "No Git URL was given and this repository has no origin. Run mend adopt <git-url>."
10036
10160
  );
10037
10161
  }
10038
10162
  const sourceIssue = repositoryCloneUrlIssue(source);
10039
- if (sourceIssue !== null) return fail6(sourceIssue);
10163
+ if (sourceIssue !== null) return fail7(sourceIssue);
10040
10164
  const projectName = name ?? normalizeProjectName(path21.basename(source, ".git"));
10041
10165
  const auth = authFlagIndex !== -1 && args[authFlagIndex + 1] !== void 0 ? String(args[authFlagIndex + 1]) : null;
10042
10166
  if (auth !== null && auth !== "ambient" && auth !== "mend-key" && auth !== "bridge") {
10043
- return fail6(`--auth takes "ambient", "mend-key", or "bridge", not "${auth}"`);
10167
+ return fail7(`--auth takes "ambient", "mend-key", or "bridge", not "${auth}"`);
10044
10168
  }
10045
10169
  const project2 = await api(config, "POST", "/projects", {
10046
10170
  name: projectName,
@@ -10048,25 +10172,25 @@ var adopt = async (config, args) => {
10048
10172
  visibility,
10049
10173
  ...auth === null ? {} : { gitAuthMode: auth }
10050
10174
  });
10051
- say6(`${green6("\u2713")} adopted \xB7 ${project2.name} \xB7 ${dim6(project2.storePath)}`);
10052
- say6(`${dim6(" default branch")} ${project2.defaultBranch}`);
10053
- say6(
10054
- `${dim6(" visible to")} ${visibility === "private" ? "only you" : "everyone in the organization"}`
10175
+ say7(`${green7("\u2713")} adopted \xB7 ${project2.name} \xB7 ${dim7(project2.storePath)}`);
10176
+ say7(`${dim7(" default branch")} ${project2.defaultBranch}`);
10177
+ say7(
10178
+ `${dim7(" visible to")} ${visibility === "private" ? "only you" : "everyone in the organization"}`
10055
10179
  );
10056
10180
  if (project2.gitAuthMode === "mend-key") {
10057
- say6(`${dim6(" git auth")} mend key ${dim6("(your Mend key signed this clone)")}`);
10181
+ say7(`${dim7(" git auth")} mend key ${dim7("(your Mend key signed this clone)")}`);
10058
10182
  } else if (project2.gitAuthMode === "bridge") {
10059
- say6(`${dim6(" git auth")} bridge ${dim6("(signed through the connected `mend keys share`)")}`);
10183
+ say7(`${dim7(" git auth")} bridge ${dim7("(signed through the connected `mend keys share`)")}`);
10060
10184
  }
10061
- say6(
10062
- `${dim6(" sessions start with:")} mend codex ${dim6("(from anywhere \u2014")} --project ${project2.name}${dim6(")")}`
10185
+ say7(
10186
+ `${dim7(" sessions start with:")} mend codex ${dim7("(from anywhere \u2014")} --project ${project2.name}${dim7(")")}`
10063
10187
  );
10064
10188
  const repoRoot = positional[0] === void 0 ? cwdFacts(process.cwd()).repoRoot : null;
10065
10189
  const memory = repoRoot === null ? null : claudeMemoryDirFor(repoRoot);
10066
10190
  if (memory !== null) {
10067
10191
  const count = scanClaudeMemory(memory).files.length;
10068
- say6(
10069
- `${dim6(" claude memory")} ${count} file${count === 1 ? "" : "s"} on this machine ${dim6("\u2192 mend memory import")}`
10192
+ say7(
10193
+ `${dim7(" claude memory")} ${count} file${count === 1 ? "" : "s"} on this machine ${dim7("\u2192 mend memory import")}`
10070
10194
  );
10071
10195
  }
10072
10196
  };
@@ -10074,30 +10198,30 @@ var findProject = async (config, explicit, adoptCwd = false) => {
10074
10198
  const projects = await api(config, "GET", "/projects");
10075
10199
  if (explicit !== null) {
10076
10200
  const named = projects.find((p) => p.name === explicit);
10077
- if (named === void 0) return fail6(`no adopted project named "${explicit}"`);
10201
+ if (named === void 0) return fail7(`no adopted project named "${explicit}"`);
10078
10202
  return named;
10079
10203
  }
10080
10204
  const cwd = process.cwd();
10081
10205
  const project2 = matchProjectByCwd(projects, cwdFacts(cwd));
10082
10206
  if (project2 !== void 0) return project2;
10083
10207
  if (!adoptCwd) {
10084
- return fail6(
10208
+ return fail7(
10085
10209
  `no adopted project matches ${cwd} \u2014 run "mend adopt" here first, or name one with --project`
10086
10210
  );
10087
10211
  }
10088
10212
  const facts = cwdFacts(cwd);
10089
10213
  if (facts.repoRoot === null || facts.originUrl === null) {
10090
- return fail6(
10214
+ return fail7(
10091
10215
  `${cwd} does not match an adopted project with a Git origin \u2014 run "mend adopt <git-url>" first`
10092
10216
  );
10093
10217
  }
10094
10218
  const sourceIssue = repositoryCloneUrlIssue(facts.originUrl);
10095
- if (sourceIssue !== null) return fail6(sourceIssue);
10219
+ if (sourceIssue !== null) return fail7(sourceIssue);
10096
10220
  const adopted = await api(config, "POST", "/projects", {
10097
10221
  name: normalizeProjectName(path21.basename(facts.repoRoot)),
10098
10222
  source: facts.originUrl
10099
10223
  });
10100
- say6(`${green6("\u2713")} adopted \xB7 ${adopted.name} \xB7 ${dim6(adopted.storePath)}`);
10224
+ say7(`${green7("\u2713")} adopted \xB7 ${adopted.name} \xB7 ${dim7(adopted.storePath)}`);
10101
10225
  return adopted;
10102
10226
  };
10103
10227
  var resolvedBackgroundSessions = async (config, project2) => {
@@ -10124,48 +10248,96 @@ var askWorktreeName = async () => {
10124
10248
  const readline = await import("node:readline/promises");
10125
10249
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
10126
10250
  try {
10127
- const answer = (await rl.question(` worktree name ${dim6("(enter for auto)")}: `)).trim();
10251
+ const answer = (await rl.question(` worktree name ${dim7("(enter for auto)")}: `)).trim();
10128
10252
  return answer === "" ? null : normalizeProjectName(answer);
10129
10253
  } finally {
10130
10254
  rl.close();
10131
10255
  }
10132
10256
  };
10257
+ var viewerIdOf = (config) => request(config, "GET", "/organization").then(
10258
+ (view) => view.userId,
10259
+ () => null
10260
+ );
10261
+ var workspaceLinesOf = async (config, sessions) => {
10262
+ const live = sessions.filter((session) => LIVE_STATUSES.has(session.status));
10263
+ if (!hasPersonFacts(live)) return /* @__PURE__ */ new Map();
10264
+ const viewerRead = live.some((session) => (session.livePeople ?? []).length > 0) ? viewerIdOf(config) : Promise.resolve(null);
10265
+ const facts = await Promise.all(
10266
+ live.map(async (session) => {
10267
+ const reads = workspaceReadsOf(session);
10268
+ const [wait, retirement] = await Promise.all([
10269
+ reads.waiting ? request(
10270
+ config,
10271
+ "GET",
10272
+ `/sessions/${session.id}/waiting`
10273
+ ).catch(() => null) : null,
10274
+ reads.retirement ? request(
10275
+ config,
10276
+ "GET",
10277
+ `/sessions/${session.id}/workspace-retirement`
10278
+ ).catch(() => null) : null
10279
+ ]);
10280
+ return { session, wait, retirement };
10281
+ })
10282
+ );
10283
+ const viewer = await viewerRead;
10284
+ const members = facts.some((fact) => fact.retirement !== null) ? await request(config, "GET", "/organization/members").catch(
10285
+ () => []
10286
+ ) : [];
10287
+ return new Map(
10288
+ facts.map(({ session, wait, retirement }) => [
10289
+ session.id,
10290
+ workspaceLineList(
10291
+ sessionWorkspaceLines({
10292
+ sessionId: session.id,
10293
+ livePeople: session.livePeople ?? [],
10294
+ viewer,
10295
+ wait,
10296
+ retirement,
10297
+ members
10298
+ })
10299
+ )
10300
+ ])
10301
+ );
10302
+ };
10133
10303
  var launch = async (config, harness, args) => {
10134
10304
  const parsed = parseLaunchArgs(args);
10135
- if (parsed.error !== null) return fail6(parsed.error);
10305
+ if (parsed.error !== null) return fail7(parsed.error);
10136
10306
  const structured = parsed.prompt !== null || parsed.model !== null || parsed.effort !== null || parsed.ask || parsed.fast;
10137
10307
  if (harness === "run" && structured) {
10138
- return fail6(`mend run takes no prompt or harness flags \xB7 ${usageOf("run")}`);
10308
+ return fail7(`mend run takes no prompt or harness flags \xB7 ${usageOf("run")}`);
10139
10309
  }
10140
10310
  if (harness === "run" && parsed.autoLand !== null) {
10141
- return fail6(
10311
+ return fail7(
10142
10312
  "mend run takes no landing flags \u2014 a command has no turns to land after; land it with mend land"
10143
10313
  );
10144
10314
  }
10145
10315
  if (harness === "run" && (parsed.detach || parsed.foreground)) {
10146
- return fail6(
10316
+ return fail7(
10147
10317
  "mend run takes no lifecycle flags \u2014 it tails the record; Ctrl+C stops watching, not the command"
10148
10318
  );
10149
10319
  }
10150
10320
  const argv = harness === "run" ? parsed.custom : HARNESS_COMMANDS[harness] ?? [];
10151
10321
  if (argv.length === 0) {
10152
- return fail6(harness === "run" ? usageOf("run") : `unknown harness ${harness}`);
10322
+ return fail7(harness === "run" ? usageOf("run") : `unknown harness ${harness}`);
10153
10323
  }
10154
10324
  const project2 = await findProject(config, parsed.project, true);
10155
- say6(
10156
- `${green6("\u2713")} project ${project2.name} ${dim6(`\xB7 ${project2.defaultBranch}${parsed.project === null ? " \xB7 from cwd" : ""}`)}`
10325
+ say7(
10326
+ `${green7("\u2713")} project ${project2.name} ${dim7(`\xB7 ${project2.defaultBranch}${parsed.project === null ? " \xB7 from cwd" : ""}`)}`
10157
10327
  );
10158
10328
  let worktreeName;
10329
+ let projectView = null;
10159
10330
  if (parsed.worktree !== null) {
10160
10331
  const detail = await api(config, "GET", `/projects/${project2.id}`);
10332
+ projectView = detail;
10161
10333
  const existing = detail.worktrees ?? [];
10162
10334
  if (detail.worktrees === void 0) {
10163
- return fail6("this server predates shared worktrees \u2014 use --name instead");
10335
+ return fail7("this server predates shared worktrees \u2014 use --name instead");
10164
10336
  }
10165
10337
  const match = existing.find((worktree) => worktree.name === parsed.worktree) ?? (existing.filter((worktree) => worktree.name.startsWith(parsed.worktree ?? "")).length === 1 ? existing.find((worktree) => worktree.name.startsWith(parsed.worktree ?? "")) : void 0);
10166
10338
  if (match === void 0) {
10167
10339
  const names = existing.map((worktree) => worktree.name).join(", ");
10168
- return fail6(
10340
+ return fail7(
10169
10341
  `no worktree matches "${parsed.worktree}" in ${project2.name}${names === "" ? "" : ` \u2014 have: ${names}`}`
10170
10342
  );
10171
10343
  }
@@ -10174,17 +10346,19 @@ var launch = async (config, harness, args) => {
10174
10346
  worktreeName = harness === "run" ? parsed.name : parsed.name ?? await askWorktreeName();
10175
10347
  }
10176
10348
  if (worktreeName !== null) {
10177
- const detail = await api(config, "GET", `/projects/${project2.id}`).catch(
10178
- () => null
10179
- );
10349
+ const detail = projectView ?? await api(config, "GET", `/projects/${project2.id}`).catch(() => null);
10180
10350
  const joined = detail?.worktrees?.find((worktree) => worktree.name === worktreeName);
10181
10351
  if (joined !== void 0) {
10182
10352
  const members = (detail?.sessions ?? []).filter(
10183
10353
  (candidate) => candidate.worktreeId === joined.id
10184
10354
  ).length;
10185
- say6(
10186
- `${green6("\u2713")} joins worktree ${joined.name} ${dim6(`\xB7 ${members} session${members === 1 ? "" : "s"} \xB7 branch ${joined.branch}`)}`
10355
+ say7(
10356
+ `${green7("\u2713")} joins worktree ${joined.name} ${dim7(`\xB7 ${members} session${members === 1 ? "" : "s"} \xB7 branch ${joined.branch}`)}`
10187
10357
  );
10358
+ const rows = detail?.sessions ?? [];
10359
+ const viewer = worktreeListsPeople(rows, joined.id) ? await viewerIdOf(config) : null;
10360
+ const joinLine = worktreeJoinLine(rows, joined.id, viewer);
10361
+ if (joinLine !== null) say7(`${amber2("\xB7")} ${joinLine}`);
10188
10362
  }
10189
10363
  }
10190
10364
  const lifecycle = harness === "run" ? "background" : parsed.detach ? "detach" : parsed.foreground ? "foreground" : await resolvedBackgroundSessions(config, project2) ? "background" : "foreground";
@@ -10209,14 +10383,14 @@ var launch = async (config, harness, args) => {
10209
10383
  ...parsed.autoLand === null ? {} : { autoLand: parsed.autoLand }
10210
10384
  });
10211
10385
  createdSessionId = session.id;
10212
- say6(`${green6("\u2713")} worktree ${session.worktree} ${dim6(`\xB7 branch ${session.branch}`)}`);
10386
+ say7(`${green7("\u2713")} worktree ${session.worktree} ${dim7(`\xB7 branch ${session.branch}`)}`);
10213
10387
  const landing = autoLandLine(parsed.autoLand, project2);
10214
- if (landing !== null) say6(landing);
10388
+ if (landing !== null) say7(landing);
10215
10389
  const baseWord = session.baseRef === null ? "" : `${session.baseRef} `;
10216
- say6(
10217
- `${green6("\u2713")} base ${baseWord}${dim6(session.baseSha.slice(0, 12))} \xB7 session ${dim6(session.id.slice(0, 8))}`
10390
+ say7(
10391
+ `${green7("\u2713")} base ${baseWord}${dim7(session.baseSha.slice(0, 12))} \xB7 session ${dim7(session.id.slice(0, 8))}`
10218
10392
  );
10219
- say6(`${cobalt2(" watch")} \xB7 ${config.url}/sessions/${session.id}`);
10393
+ say7(`${cobalt2(" watch")} \xB7 ${config.url}/sessions/${session.id}`);
10220
10394
  if (harness === "run") {
10221
10395
  return supervisedRun(config, session, argv);
10222
10396
  }
@@ -10234,14 +10408,14 @@ var launch = async (config, harness, args) => {
10234
10408
  request(config, "POST", `/sessions/${session.id}/launch`, launchBody)
10235
10409
  );
10236
10410
  if (lifecycle === "detach") {
10237
- say6(`${green6("\u2713 recording")} \xB7 running detached`);
10238
- say6(`${cobalt2(" attach")} \xB7 mend attach ${session.id.slice(0, 8)}`);
10411
+ say7(`${green7("\u2713 recording")} \xB7 running detached`);
10412
+ say7(`${cobalt2(" attach")} \xB7 mend attach ${session.id.slice(0, 8)}`);
10239
10413
  return;
10240
10414
  }
10241
- say6(`${green6("\u2713 recording")} \xB7 workspace mounts the worktree${detachHint()}`);
10415
+ say7(`${green7("\u2713 recording")} \xB7 workspace mounts the worktree${detachHint()}`);
10242
10416
  const tunnels = attachTunnels(config, parsed.noTunnel);
10243
10417
  await tunnels?.start(session.id);
10244
- say6("");
10418
+ say7("");
10245
10419
  attachOwnsSignals = true;
10246
10420
  await attachOrExit(config, session.id, session.harness, lifecycle, tunnels);
10247
10421
  exitAfterSessionEnd(config, session.id);
@@ -10251,7 +10425,7 @@ var autoLandLine = (override, project2) => {
10251
10425
  if (override && project2.autoLand === "off") {
10252
10426
  return `${amber2("\xB7")} automatic landing \xB7 off for ${project2.name} \xB7 the project's setting wins over --land`;
10253
10427
  }
10254
- return `${green6("\u2713")} automatic landing \xB7 ${override ? "on" : "off"} for this session ${dim6("\xB7 from this terminal, land with mend land")}`;
10428
+ return `${green7("\u2713")} automatic landing \xB7 ${override ? "on" : "off"} for this session ${dim7("\xB7 from this terminal, land with mend land")}`;
10255
10429
  };
10256
10430
  var ATTACH_CONNECT_TIMEOUT_MS = (() => {
10257
10431
  const configured = Number(process.env["MEND_ATTACH_TIMEOUT_MS"]);
@@ -10448,8 +10622,8 @@ var attachTty = async (config, sessionId, harness, from, processId, options) =>
10448
10622
  watching = true;
10449
10623
  const members = await request(config, "GET", "/organization/members").catch(() => []);
10450
10624
  process.stdout.write(
10451
- `\r\x1B[2K${dim6(watchNotice(ownerNameOf(detail?.session.ownerUserId, members)))}\r
10452
- ${dim6(`read-only \xB7 ${detachKeyEnabled ? "Ctrl+] or " : ""}Ctrl+C detaches`)}\r
10625
+ `\r\x1B[2K${dim7(watchNotice(ownerNameOf(detail?.session.ownerUserId, members)))}\r
10626
+ ${dim7(`read-only \xB7 ${detachKeyEnabled ? "Ctrl+] or " : ""}Ctrl+C detaches`)}\r
10453
10627
  \r
10454
10628
  `
10455
10629
  );
@@ -10522,51 +10696,51 @@ var stopSessionQuickly = async (config, sessionId) => {
10522
10696
  var stopAndExit = async (config, sessionId) => {
10523
10697
  const id8 = sessionId.slice(0, 8);
10524
10698
  if (await stopSessionQuickly(config, sessionId)) {
10525
- say6(`${green6("\u2713")} stopped \xB7 ${id8}`);
10526
- say6(`${cobalt2(" review")} \xB7 ${config.url}/sessions/${sessionId}`);
10699
+ say7(`${green7("\u2713")} stopped \xB7 ${id8}`);
10700
+ say7(`${cobalt2(" review")} \xB7 ${config.url}/sessions/${sessionId}`);
10527
10701
  process.exit(0);
10528
10702
  }
10529
- say6(`${amber2("could not stop")} \u2014 the session may still run \xB7 mend stop ${id8}`);
10703
+ say7(`${amber2("could not stop")} \u2014 the session may still run \xB7 mend stop ${id8}`);
10530
10704
  process.exit(1);
10531
10705
  };
10532
10706
  var noAnswerLine = (config, id8) => `${amber2("no answer")} \u2014 ${config.url} did not open the terminal within ${spoken(ATTACH_CONNECT_TIMEOUT_MS)}; the session keeps running \xB7 try again: mend attach ${id8} \xB7 check the server: mend doctor`;
10533
10707
  var finishAttach = async (config, sessionId, outcome, mode = "background") => {
10534
10708
  const id8 = sessionId.slice(0, 8);
10535
10709
  if (outcome === "unavailable") {
10536
- return fail6(`tty attach unavailable: could not connect to ${config.url}`);
10710
+ return fail7(`tty attach unavailable: could not connect to ${config.url}`);
10537
10711
  }
10538
10712
  if (outcome === "no-answer") {
10539
- say6("");
10540
- say6(noAnswerLine(config, id8));
10713
+ say7("");
10714
+ say7(noAnswerLine(config, id8));
10541
10715
  if (mode === "foreground") return stopAndExit(config, sessionId);
10542
10716
  process.exit(1);
10543
10717
  }
10544
10718
  if (outcome === "detached") {
10545
- say6("");
10546
- say6(`${amber2("detached")} \u2014 the session keeps running; reattach: mend attach ${id8}`);
10719
+ say7("");
10720
+ say7(`${amber2("detached")} \u2014 the session keeps running; reattach: mend attach ${id8}`);
10547
10721
  process.exit(0);
10548
10722
  }
10549
10723
  if (outcome === "interrupted") {
10550
- say6("");
10724
+ say7("");
10551
10725
  if (mode === "foreground") return stopAndExit(config, sessionId);
10552
- say6(`${amber2("detached")} \u2014 the session keeps running; reattach: mend attach ${id8}`);
10726
+ say7(`${amber2("detached")} \u2014 the session keeps running; reattach: mend attach ${id8}`);
10553
10727
  process.exit(0);
10554
10728
  }
10555
10729
  if (outcome === "dropped") {
10556
- say6("");
10730
+ say7("");
10557
10731
  if (mode === "foreground") {
10558
10732
  let live;
10559
10733
  try {
10560
10734
  const detail = await request(config, "GET", `/sessions/${sessionId}`);
10561
10735
  live = agentIsLive(detail.session, detail.currentAgent);
10562
10736
  } catch {
10563
- say6(`${amber2("could not stop")} \u2014 the session may still run \xB7 mend stop ${id8}`);
10737
+ say7(`${amber2("could not stop")} \u2014 the session may still run \xB7 mend stop ${id8}`);
10564
10738
  process.exit(1);
10565
10739
  }
10566
10740
  if (!live) return;
10567
10741
  return stopAndExit(config, sessionId);
10568
10742
  }
10569
- say6(`${amber2("disconnected")} \u2014 the session keeps running; reattach: mend attach ${id8}`);
10743
+ say7(`${amber2("disconnected")} \u2014 the session keeps running; reattach: mend attach ${id8}`);
10570
10744
  process.exit(0);
10571
10745
  }
10572
10746
  };
@@ -10581,9 +10755,9 @@ var attachOrExit = async (config, sessionId, harness, mode = "background", tunne
10581
10755
  );
10582
10756
  var attachWithTunnels = (tunnels, work) => tunnels === null ? work() : tunnels.attached(work);
10583
10757
  var exitAfterSessionEnd = (config, sessionId) => {
10584
- say6("");
10585
- say6(`${green6("\u2713")} session ended`);
10586
- say6(`${cobalt2(" review")} \xB7 ${config.url}/sessions/${sessionId}`);
10758
+ say7("");
10759
+ say7(`${green7("\u2713")} session ended`);
10760
+ say7(`${cobalt2(" review")} \xB7 ${config.url}/sessions/${sessionId}`);
10587
10761
  process.exit(0);
10588
10762
  };
10589
10763
  var attach = async (config, args) => {
@@ -10595,18 +10769,18 @@ var attach = async (config, args) => {
10595
10769
  }
10596
10770
  const sessions = await api(config, "GET", "/sessions");
10597
10771
  const match = sessions.find((s) => s.id.startsWith(prefix));
10598
- if (match === void 0) return fail6(`no active session matches "${prefix}"`);
10772
+ if (match === void 0) return fail7(`no active session matches "${prefix}"`);
10599
10773
  return attachPicked(config, match, tunnels);
10600
10774
  };
10601
10775
  var attachPicked = async (config, session, tunnels) => {
10602
- say6(
10603
- `${green6("\u2713")} attaching to ${sessionDisplayName(session)} \xB7 ${session.harness} ${dim6(session.id.slice(0, 8))}${detachHint()}`
10776
+ say7(
10777
+ `${green7("\u2713")} attaching to ${sessionDisplayName(session)} \xB7 ${session.harness} ${dim7(session.id.slice(0, 8))}${detachHint()}`
10604
10778
  );
10605
10779
  if (session.status === "starting") {
10606
10780
  await startAndFollow(config, session.id, "starting \u2014 attaching once the agent runs\u2026", null);
10607
10781
  }
10608
10782
  await tunnels?.start(session.id);
10609
- say6("");
10783
+ say7("");
10610
10784
  const outcome = await attachWithTunnels(
10611
10785
  tunnels,
10612
10786
  () => attachTty(config, session.id, session.harness, 0n, void 0, {
@@ -10616,14 +10790,14 @@ var attachPicked = async (config, session, tunnels) => {
10616
10790
  if (outcome === "unavailable") {
10617
10791
  const detail = await api(config, "GET", `/sessions/${session.id}`);
10618
10792
  if (detail.currentAgent?.kind === "agent-protocol" && agentIsLive(detail.session, detail.currentAgent)) {
10619
- say6(`${amber2("taking over")} from the protocol session`);
10793
+ say7(`${amber2("taking over")} from the protocol session`);
10620
10794
  await startAndFollow(
10621
10795
  config,
10622
10796
  session.id,
10623
10797
  "reopening as a terminal \u2014 same conversation\u2026",
10624
10798
  request(config, "POST", `/sessions/${session.id}/handoff`, { to: "pty" })
10625
10799
  );
10626
- say6("");
10800
+ say7("");
10627
10801
  await attachOrExit(config, session.id, session.harness, "background", tunnels);
10628
10802
  return exitAfterSessionEnd(config, session.id);
10629
10803
  }
@@ -10648,7 +10822,7 @@ var stopCommand = async (config, args) => {
10648
10822
  return;
10649
10823
  }
10650
10824
  if (!all && prefix === void 0) {
10651
- return fail6(usageOf("stop"));
10825
+ return fail7(usageOf("stop"));
10652
10826
  }
10653
10827
  const [sessions, projects] = await Promise.all([
10654
10828
  api(config, "GET", "/sessions"),
@@ -10657,21 +10831,21 @@ var stopCommand = async (config, args) => {
10657
10831
  let scoped = sessions;
10658
10832
  if (projectName !== null) {
10659
10833
  const project2 = projects.find((p) => p.name === projectName);
10660
- if (project2 === void 0) return fail6(`no project named "${projectName}"`);
10834
+ if (project2 === void 0) return fail7(`no project named "${projectName}"`);
10661
10835
  scoped = sessions.filter((s) => s.projectId === project2.id);
10662
10836
  }
10663
10837
  let targets;
10664
10838
  if (all) {
10665
10839
  targets = scoped;
10666
10840
  if (targets.length === 0) {
10667
- say6("no active sessions");
10841
+ say7("no active sessions");
10668
10842
  return;
10669
10843
  }
10670
10844
  } else {
10671
10845
  const matches = scoped.filter((s) => s.id.startsWith(prefix ?? ""));
10672
- if (matches.length === 0) return fail6(`no active session matches "${prefix}"`);
10846
+ if (matches.length === 0) return fail7(`no active session matches "${prefix}"`);
10673
10847
  if (matches.length > 1) {
10674
- return fail6(`session prefix "${prefix}" is ambiguous \u2014 use more of the id`);
10848
+ return fail7(`session prefix "${prefix}" is ambiguous \u2014 use more of the id`);
10675
10849
  }
10676
10850
  targets = matches;
10677
10851
  }
@@ -10680,24 +10854,24 @@ var stopCommand = async (config, args) => {
10680
10854
  var stopSessions = async (config, targets, summarise) => {
10681
10855
  for (const session of targets) {
10682
10856
  await api(config, "POST", `/sessions/${session.id}/stop`);
10683
- say6(
10684
- `${green6("\u2713")} stopped \xB7 ${session.harness} \xB7 ${dim6(session.id.slice(0, 8))} \xB7 ${session.branch}`
10857
+ say7(
10858
+ `${green7("\u2713")} stopped \xB7 ${session.harness} \xB7 ${dim7(session.id.slice(0, 8))} \xB7 ${session.branch}`
10685
10859
  );
10686
10860
  const after = await api(config, "GET", `/sessions/${session.id}`).catch(
10687
10861
  () => null
10688
10862
  );
10689
10863
  const hold = after === null ? null : servicesHoldOf(after.session, after.currentAgent, after.liveServices ?? 0);
10690
10864
  if (hold !== null) {
10691
- say6(`${amber2(" " + hold)} \xB7 mend stop --services ${session.id.slice(0, 8)}`);
10865
+ say7(`${amber2(" " + hold)} \xB7 mend stop --services ${session.id.slice(0, 8)}`);
10692
10866
  }
10693
10867
  const capture = after === null ? null : captureLineOf(after.session);
10694
10868
  if (capture !== null) {
10695
- say6(`${amber2(" " + capture)} \xB7 the workspace stops once nothing is pending`);
10869
+ say7(`${amber2(" " + capture)} \xB7 the workspace stops once nothing is pending`);
10696
10870
  }
10697
- say6(`${cobalt2(" review")} \xB7 ${config.url}/sessions/${session.id}`);
10871
+ say7(`${cobalt2(" review")} \xB7 ${config.url}/sessions/${session.id}`);
10698
10872
  }
10699
10873
  if (summarise) {
10700
- say6(`${green6("\u2713")} stopped ${targets.length} session${targets.length === 1 ? "" : "s"}`);
10874
+ say7(`${green7("\u2713")} stopped ${targets.length} session${targets.length === 1 ? "" : "s"}`);
10701
10875
  }
10702
10876
  };
10703
10877
  var stopServicesOf = async (config, session) => {
@@ -10707,18 +10881,18 @@ var stopServicesOf = async (config, session) => {
10707
10881
  `/sessions/${session.id}/services/stop`
10708
10882
  );
10709
10883
  if (result.stopped === 0) {
10710
- say6(`no live services \xB7 ${session.harness} \xB7 ${dim6(session.id.slice(0, 8))}`);
10884
+ say7(`no live services \xB7 ${session.harness} \xB7 ${dim7(session.id.slice(0, 8))}`);
10711
10885
  return;
10712
10886
  }
10713
- say6(
10714
- `${green6("\u2713")} stopped ${result.stopped} service${result.stopped === 1 ? "" : "s"} \xB7 ${session.harness} \xB7 ${dim6(session.id.slice(0, 8))} \xB7 ${session.branch}`
10887
+ say7(
10888
+ `${green7("\u2713")} stopped ${result.stopped} service${result.stopped === 1 ? "" : "s"} \xB7 ${session.harness} \xB7 ${dim7(session.id.slice(0, 8))} \xB7 ${session.branch}`
10715
10889
  );
10716
10890
  };
10717
10891
  var pickSessionInteractively = async (rows) => {
10718
- say6(dim6("more than one live session \u2014 pick one:"));
10892
+ say7(dim7("more than one live session \u2014 pick one:"));
10719
10893
  rows.forEach((row, index) => {
10720
- say6(
10721
- ` ${index + 1}. ${row.session.harness.padEnd(8)} ${dim6(row.session.id.slice(0, 8))} ${row.projectName} ${dim6(row.session.branch)} ${dim6(row.session.status)}`
10894
+ say7(
10895
+ ` ${index + 1}. ${row.session.harness.padEnd(8)} ${dim7(row.session.id.slice(0, 8))} ${row.projectName} ${dim7(row.session.branch)} ${dim7(row.session.status)}`
10722
10896
  );
10723
10897
  });
10724
10898
  const readline = await import("node:readline/promises");
@@ -10726,17 +10900,17 @@ var pickSessionInteractively = async (rows) => {
10726
10900
  const answer = await rl.question(" session #: ");
10727
10901
  rl.close();
10728
10902
  const chosen = rows[Number(answer.trim()) - 1];
10729
- if (chosen === void 0) return fail6(`"${answer.trim()}" is not one of the choices`);
10903
+ if (chosen === void 0) return fail7(`"${answer.trim()}" is not one of the choices`);
10730
10904
  return chosen.session;
10731
10905
  };
10732
10906
  var resolveLiveSession = async (config, prefix, command) => {
10733
10907
  const sessions = await api(config, "GET", "/sessions?retained=1");
10734
10908
  if (prefix !== void 0) {
10735
10909
  const matches = sessions.filter((s) => s.id.startsWith(prefix));
10736
- if (matches.length === 0) return fail6(`no live or retained session matches "${prefix}"`);
10910
+ if (matches.length === 0) return fail7(`no live or retained session matches "${prefix}"`);
10737
10911
  const exact = matches[0];
10738
10912
  if (matches.length > 1 || exact === void 0) {
10739
- return fail6(`session prefix "${prefix}" is ambiguous \u2014 use more of the id`);
10913
+ return fail7(`session prefix "${prefix}" is ambiguous \u2014 use more of the id`);
10740
10914
  }
10741
10915
  return exact;
10742
10916
  }
@@ -10745,11 +10919,11 @@ var resolveLiveSession = async (config, prefix, command) => {
10745
10919
  const candidates = project2 === void 0 ? sessions : sessions.filter((s) => s.projectId === project2.id);
10746
10920
  const only = candidates[0];
10747
10921
  if (only === void 0) {
10748
- return fail6("no live or retained session \u2014 start one with mend codex|claude|opencode|pi");
10922
+ return fail7("no live or retained session \u2014 start one with mend codex|claude|opencode|pi");
10749
10923
  }
10750
10924
  if (candidates.length === 1) return only;
10751
10925
  if (process.stdin.isTTY !== true) {
10752
- return fail6(`several live sessions \u2014 name one: mend ${command} <session-id-prefix>`);
10926
+ return fail7(`several live sessions \u2014 name one: mend ${command} <session-id-prefix>`);
10753
10927
  }
10754
10928
  const nameById = new Map(projects.map((p) => [p.id, p.name]));
10755
10929
  return pickSessionInteractively(
@@ -10762,30 +10936,30 @@ var resolveLiveSession = async (config, prefix, command) => {
10762
10936
  var shellCommand = async (config, args) => {
10763
10937
  const prefix = args.find((a) => !a.startsWith("--"));
10764
10938
  const session = await resolveLiveSession(config, prefix, "shell");
10765
- say6(
10766
- `${green6("\u2713")} shell in ${session.harness} session ${dim6(session.id.slice(0, 8))} \xB7 ${dim6(session.branch)}${detachHint()}`
10939
+ say7(
10940
+ `${green7("\u2713")} shell in ${session.harness} session ${dim7(session.id.slice(0, 8))} \xB7 ${dim7(session.branch)}${detachHint()}`
10767
10941
  );
10768
10942
  const shellProcess = await withSpinner(
10769
10943
  "opening a shell in the session workspace\u2026",
10770
10944
  api(config, "POST", `/sessions/${session.id}/shell`)
10771
10945
  );
10772
- say6("");
10946
+ say7("");
10773
10947
  const outcome = await attachTty(config, session.id, "shell", 0n, shellProcess.id, {
10774
10948
  handleSignals: true
10775
10949
  });
10776
10950
  if (outcome === "unavailable") {
10777
- return fail6(`tty attach unavailable: could not connect to ${config.url}`);
10951
+ return fail7(`tty attach unavailable: could not connect to ${config.url}`);
10778
10952
  }
10779
- say6("");
10953
+ say7("");
10780
10954
  if (outcome === "no-answer") {
10781
- say6(noAnswerLine(config, session.id.slice(0, 8)));
10955
+ say7(noAnswerLine(config, session.id.slice(0, 8)));
10782
10956
  process.exit(1);
10783
10957
  }
10784
10958
  if (outcome === "detached" || outcome === "interrupted" || outcome === "dropped") {
10785
- say6(`${amber2("detached")} \u2014 the shell keeps running and holds the workspace open`);
10959
+ say7(`${amber2("detached")} \u2014 the shell keeps running and holds the workspace open`);
10786
10960
  process.exit(0);
10787
10961
  }
10788
- say6(`${green6("\u2713")} shell ended`);
10962
+ say7(`${green7("\u2713")} shell ended`);
10789
10963
  process.exit(0);
10790
10964
  };
10791
10965
  var flattenService = (view) => {
@@ -10827,30 +11001,30 @@ var serviceUrl = (service) => service.browserUrl ?? (service.authority === null
10827
11001
  var printServiceAccess = (config, service, tunneling = false) => {
10828
11002
  const gate = "no Mend sign-in on this port \u2014 network reach is the only gate";
10829
11003
  if (serverIsLocal(config)) {
10830
- if (service.authority !== null) say6(` ${cobalt2(serviceUrl(service))} ${dim6(gate)}`);
11004
+ if (service.authority !== null) say7(` ${cobalt2(serviceUrl(service))} ${dim7(gate)}`);
10831
11005
  return;
10832
11006
  }
10833
11007
  if (service.protocol === "udp") {
10834
11008
  if (service.authority !== null) {
10835
- say6(` ${cobalt2(serviceUrl(service))} ${dim6(`on the server's network \xB7 ${gate}`)}`);
11009
+ say7(` ${cobalt2(serviceUrl(service))} ${dim7(`on the server's network \xB7 ${gate}`)}`);
10836
11010
  }
10837
11011
  return;
10838
11012
  }
10839
11013
  if (!tunneling) {
10840
11014
  const local = service.hostPort ?? service.workspacePort;
10841
- say6(
10842
- ` ${cobalt2(`mend service connect ${service.label}`)} ${dim6(`\u2192 127.0.0.1:${local} on this machine, authenticated as you`)}`
11015
+ say7(
11016
+ ` ${cobalt2(`mend service connect ${service.label}`)} ${dim7(`\u2192 127.0.0.1:${local} on this machine, authenticated as you`)}`
10843
11017
  );
10844
11018
  }
10845
11019
  if (service.authority !== null) {
10846
- say6(` ${dim6(`server-side listener ${service.authority} \xB7 ${gate}`)}`);
11020
+ say7(` ${dim7(`server-side listener ${service.authority} \xB7 ${gate}`)}`);
10847
11021
  }
10848
11022
  };
10849
11023
  var printWorkspaceTtlFailure = (service) => {
10850
11024
  if (service.workspaceTtlRenewalError === null) return;
10851
- say6(amber2(` workspace TTL renewal failed \xB7 ${service.workspaceTtlRenewalError}`));
10852
- say6(
10853
- dim6(
11025
+ say7(amber2(` workspace TTL renewal failed \xB7 ${service.workspaceTtlRenewalError}`));
11026
+ say7(
11027
+ dim7(
10854
11028
  ` last renewed ${service.workspaceTtlRenewedAt ?? "unknown"} \xB7 known expiry ${service.workspaceExpiresAt ?? "unknown"} \xB7 failed ${service.workspaceTtlRenewalFailedAt ?? "unknown"}`
10855
11029
  )
10856
11030
  );
@@ -10860,11 +11034,11 @@ var printServiceEndpoint = (config, service, tunneling = false) => {
10860
11034
  printWorkspaceTtlFailure(service);
10861
11035
  };
10862
11036
  var printService = (config, service) => {
10863
- const status = service.status === "reachable" ? green6(service.status) : amber2(service.status);
11037
+ const status = service.status === "reachable" ? green7(service.status) : amber2(service.status);
10864
11038
  const port = `:${service.workspacePort ?? "?"}${service.protocol === "udp" ? "/udp" : ""}`;
10865
11039
  const statusPad = " ".repeat(Math.max(1, 12 - service.status.length));
10866
- say6(
10867
- `${(service.label ?? service.id.slice(0, 8)).padEnd(14)} ${status}${statusPad}${dim6(port.padEnd(7))} ${dim6(service.id.slice(0, 8))}`
11040
+ say7(
11041
+ `${(service.label ?? service.id.slice(0, 8)).padEnd(14)} ${status}${statusPad}${dim7(port.padEnd(7))} ${dim7(service.id.slice(0, 8))}`
10868
11042
  );
10869
11043
  printServiceAccess(config, service);
10870
11044
  printWorkspaceTtlFailure(service);
@@ -10875,21 +11049,21 @@ var serviceAdd = async (config, args) => {
10875
11049
  const protocol = args.includes("--udp") ? "udp" : "tcp";
10876
11050
  const http = args.includes("--http");
10877
11051
  const https = args.includes("--https");
10878
- if (http && https) return fail6("Choose either --http or --https, not both.");
11052
+ if (http && https) return fail7("Choose either --http or --https, not both.");
10879
11053
  const browserScheme = https ? "https" : http ? "http" : null;
10880
11054
  if (protocol === "udp" && browserScheme !== null) {
10881
- return fail6("UDP Services cannot use --http or --https");
11055
+ return fail7("UDP Services cannot use --http or --https");
10882
11056
  }
10883
11057
  const positional = args.filter(
10884
11058
  (a, i) => !a.startsWith("--") && (nameFlag === -1 || i !== nameFlag + 1)
10885
11059
  );
10886
11060
  const portRaw = positional.find((a) => /^\d+$/.test(a));
10887
11061
  if (portRaw === void 0) {
10888
- return fail6(usageOf("service add"));
11062
+ return fail7(usageOf("service add"));
10889
11063
  }
10890
11064
  const port = Number(portRaw);
10891
11065
  if (!Number.isInteger(port) || port < 1 || port > 65535) {
10892
- return fail6(`"${portRaw}" is not a port`);
11066
+ return fail7(`"${portRaw}" is not a port`);
10893
11067
  }
10894
11068
  const prefix = positional.find((a) => a !== portRaw);
10895
11069
  const session = await resolveLiveSession(config, prefix, "service add");
@@ -10899,52 +11073,52 @@ var serviceAdd = async (config, args) => {
10899
11073
  protocol,
10900
11074
  browserScheme
10901
11075
  });
10902
- say6(`${green6("\u2713")} Service ${service.label ?? ""} \xB7 ${service.status}`);
11076
+ say7(`${green7("\u2713")} Service ${service.label ?? ""} \xB7 ${service.status}`);
10903
11077
  printServiceEndpoint(config, service);
10904
11078
  if (protocol === "udp") {
10905
- say6(dim6(` udp \u2014 a reply is the only reachability signal; silence just relays`));
11079
+ say7(dim7(` udp \u2014 a reply is the only reachability signal; silence just relays`));
10906
11080
  } else if (service.status !== "reachable") {
10907
- say6(dim6(` nothing answered on :${port} yet \u2014 the URL goes live when something listens`));
11081
+ say7(dim7(` nothing answered on :${port} yet \u2014 the URL goes live when something listens`));
10908
11082
  }
10909
11083
  };
10910
11084
  var serviceList = async (config) => {
10911
11085
  const services = await fetchServices(config);
10912
11086
  if (services.length === 0) {
10913
- say6(dim6("no live services \u2014 mend service add <port> adopts a listening one"));
11087
+ say7(dim7("no live services \u2014 mend service add <port> adopts a listening one"));
10914
11088
  return;
10915
11089
  }
10916
11090
  for (const service of services) printService(config, service);
10917
11091
  };
10918
11092
  var serviceStop = async (config, args) => {
10919
11093
  const needle = args.find((a) => !a.startsWith("--"));
10920
- if (needle === void 0) return fail6(usageOf("service stop"));
11094
+ if (needle === void 0) return fail7(usageOf("service stop"));
10921
11095
  const services = await fetchServices(config);
10922
11096
  const matches = services.filter(
10923
11097
  (service) => service.label === needle || service.id.startsWith(needle)
10924
11098
  );
10925
- if (matches.length === 0) return fail6(`no live service matches "${needle}"`);
11099
+ if (matches.length === 0) return fail7(`no live service matches "${needle}"`);
10926
11100
  const match = matches[0];
10927
11101
  if (matches.length > 1 || match === void 0) {
10928
- return fail6(`"${needle}" is ambiguous \u2014 use more of the id`);
11102
+ return fail7(`"${needle}" is ambiguous \u2014 use more of the id`);
10929
11103
  }
10930
11104
  const stoppedService = await mutateService(config, "POST", `/services/${match.id}/stop`);
10931
- say6(`${green6("\u2713")} stopped \xB7 ${stoppedService.label ?? stoppedService.id.slice(0, 8)}`);
11105
+ say7(`${green7("\u2713")} stopped \xB7 ${stoppedService.label ?? stoppedService.id.slice(0, 8)}`);
10932
11106
  };
10933
11107
  var findLiveService = async (config, needle) => {
10934
11108
  const services = await fetchServices(config);
10935
11109
  const matches = services.filter(
10936
11110
  (service) => service.label === needle || service.id.startsWith(needle)
10937
11111
  );
10938
- if (matches.length === 0) return fail6(`no live service matches "${needle}"`);
11112
+ if (matches.length === 0) return fail7(`no live service matches "${needle}"`);
10939
11113
  const match = matches[0];
10940
11114
  if (matches.length > 1 || match === void 0) {
10941
- return fail6(`"${needle}" is ambiguous \u2014 use more of the id`);
11115
+ return fail7(`"${needle}" is ambiguous \u2014 use more of the id`);
10942
11116
  }
10943
11117
  return match;
10944
11118
  };
10945
11119
  var willAutoConnect = (config, service, optOut) => !optOut && !serverIsLocal(config) && service.protocol !== "udp";
10946
11120
  var autoConnect = async (config, service) => {
10947
- say6(dim6(" remote server \u2014 tunneling the port here \xB7 Ctrl-C stops the tunnel, not the Service"));
11121
+ say7(dim7(" remote server \u2014 tunneling the port here \xB7 Ctrl-C stops the tunnel, not the Service"));
10948
11122
  await tunnelServices(config, [service], null);
10949
11123
  };
10950
11124
  var serviceRun = async (config, args) => {
@@ -10953,7 +11127,7 @@ var serviceRun = async (config, args) => {
10953
11127
  if (dashdash === -1) {
10954
11128
  const positionals = args.filter((a) => !a.startsWith("--"));
10955
11129
  const name2 = positionals.at(-1);
10956
- if (name2 === void 0) return fail6(usage2);
11130
+ if (name2 === void 0) return fail7(usage2);
10957
11131
  const prefix2 = positionals.length > 1 ? positionals[0] : void 0;
10958
11132
  const session2 = await resolveLiveSession(config, prefix2, "service run");
10959
11133
  const recipes = await api(
@@ -10964,7 +11138,7 @@ var serviceRun = async (config, args) => {
10964
11138
  const recipe = recipes.find((entry) => entry.name === name2);
10965
11139
  if (recipe === void 0) {
10966
11140
  const known = recipes.map((entry) => entry.name).join(", ");
10967
- return fail6(
11141
+ return fail7(
10968
11142
  recipes.length === 0 ? `no mend.toml recipes in this worktree \u2014 declare [service.${name2}] first` : `no recipe named "${name2}" \u2014 declared: ${known}`
10969
11143
  );
10970
11144
  }
@@ -10975,26 +11149,26 @@ var serviceRun = async (config, args) => {
10975
11149
  })
10976
11150
  );
10977
11151
  const tunneling2 = willAutoConnect(config, service2, args.includes("--no-connect"));
10978
- say6(`${green6("\u2713")} Service ${service2.label ?? ""} \xB7 ${service2.status}`);
11152
+ say7(`${green7("\u2713")} Service ${service2.label ?? ""} \xB7 ${service2.status}`);
10979
11153
  printServiceEndpoint(config, service2, tunneling2);
10980
- say6(dim6(` logs: mend service logs ${service2.label ?? service2.id.slice(0, 8)}`));
11154
+ say7(dim7(` logs: mend service logs ${service2.label ?? service2.id.slice(0, 8)}`));
10981
11155
  if (tunneling2) await autoConnect(config, service2);
10982
11156
  return;
10983
11157
  }
10984
11158
  const argv = args.slice(dashdash + 1);
10985
- if (argv.length === 0) return fail6(usage2);
11159
+ if (argv.length === 0) return fail7(usage2);
10986
11160
  const head = args.slice(0, dashdash);
10987
11161
  const portFlag = head.indexOf("--port");
10988
11162
  const port = portFlag === -1 ? Number.NaN : Number(head[portFlag + 1]);
10989
- if (!Number.isInteger(port) || port < 1 || port > 65535) return fail6(usage2);
11163
+ if (!Number.isInteger(port) || port < 1 || port > 65535) return fail7(usage2);
10990
11164
  const nameFlag = head.indexOf("--name");
10991
11165
  const name = nameFlag !== -1 && head[nameFlag + 1] !== void 0 ? String(head[nameFlag + 1]) : null;
10992
11166
  const protocol = head.includes("--udp") ? "udp" : "tcp";
10993
11167
  const http = head.includes("--http");
10994
11168
  const https = head.includes("--https");
10995
- if (http && https) return fail6(usage2);
11169
+ if (http && https) return fail7(usage2);
10996
11170
  const browserScheme = https ? "https" : http ? "http" : null;
10997
- if (protocol === "udp" && browserScheme !== null) return fail6(usage2);
11171
+ if (protocol === "udp" && browserScheme !== null) return fail7(usage2);
10998
11172
  const prefix = head.find(
10999
11173
  (a, i) => !a.startsWith("--") && i !== portFlag + 1 && i !== nameFlag + 1
11000
11174
  );
@@ -11010,9 +11184,9 @@ var serviceRun = async (config, args) => {
11010
11184
  })
11011
11185
  );
11012
11186
  const tunneling = willAutoConnect(config, service, head.includes("--no-connect"));
11013
- say6(`${green6("\u2713")} Service ${service.label ?? ""} \xB7 ${service.status}`);
11187
+ say7(`${green7("\u2713")} Service ${service.label ?? ""} \xB7 ${service.status}`);
11014
11188
  printServiceEndpoint(config, service, tunneling);
11015
- say6(dim6(` logs: mend service logs ${service.label ?? service.id.slice(0, 8)}`));
11189
+ say7(dim7(` logs: mend service logs ${service.label ?? service.id.slice(0, 8)}`));
11016
11190
  if (tunneling) await autoConnect(config, service);
11017
11191
  };
11018
11192
  var serviceLogs = async (config, args) => {
@@ -11020,32 +11194,32 @@ var serviceLogs = async (config, args) => {
11020
11194
  const from = fromFlag === -1 ? "0" : args[fromFlag + 1];
11021
11195
  const needle = firstPositional(args, ["--from"]);
11022
11196
  if (needle === void 0 || from === void 0 || !/^(0|[1-9]\d*)$/.test(from)) {
11023
- return fail6(usageOf("service logs"));
11197
+ return fail7(usageOf("service logs"));
11024
11198
  }
11025
11199
  const everything = await fetchServiceViews(config, true);
11026
11200
  const matches = everything.filter(
11027
11201
  (view2) => view2.service.name === needle || view2.service.id.startsWith(needle) || view2.attempts.some((attempt3) => attempt3.id.startsWith(needle))
11028
11202
  );
11029
- if (matches.length === 0) return fail6(`no service matches "${needle}"`);
11203
+ if (matches.length === 0) return fail7(`no service matches "${needle}"`);
11030
11204
  const view = matches.find((candidate) => {
11031
11205
  const current = candidate.service.currentAttemptId === null ? null : candidate.attempts.find((attempt3) => attempt3.id === candidate.service.currentAttemptId);
11032
11206
  return current !== null && current !== void 0 && current.exitedAt === null;
11033
11207
  }) ?? matches[0];
11034
- if (view === void 0) return fail6(`no service matches "${needle}"`);
11208
+ if (view === void 0) return fail7(`no service matches "${needle}"`);
11035
11209
  const currentAttempt = view.service.currentAttemptId === null ? null : view.attempts.find((candidate) => candidate.id === view.service.currentAttemptId) ?? null;
11036
11210
  const attempt2 = view.attempts.find((candidate) => candidate.id.startsWith(needle)) ?? currentAttempt ?? view.attempts.findLast((candidate) => candidate.sealantSessionId !== null) ?? null;
11037
11211
  if (attempt2?.sealantSessionId === null || attempt2 === null) {
11038
- return fail6(
11212
+ return fail7(
11039
11213
  `"${needle}" is an adopted port \u2014 no process of Mend's, no logs. mend service run supervises.`
11040
11214
  );
11041
11215
  }
11042
11216
  const label = view.service.name;
11043
- say6(
11044
- dim6(
11217
+ say7(
11218
+ dim7(
11045
11219
  attempt2.exitedAt === null ? `following ${label} from sequence ${from} \u2014 Ctrl+C detaches, the Service keeps running` : `${label} \xB7 ${attempt2.status} \u2014 recorded output from sequence ${from}`
11046
11220
  )
11047
11221
  );
11048
- say6("");
11222
+ say7("");
11049
11223
  let cursor = from;
11050
11224
  let telemetryReported = false;
11051
11225
  for (; ; ) {
@@ -11055,7 +11229,7 @@ var serviceLogs = async (config, args) => {
11055
11229
  `/processes/${attempt2.id}/logs?from=${encodeURIComponent(cursor)}&limit=256`
11056
11230
  );
11057
11231
  if (!telemetryReported) {
11058
- say6(dim6(`telemetry loss: ${page.telemetryLoss} \xB7 ${page.telemetryNote}`));
11232
+ say7(dim7(`telemetry loss: ${page.telemetryLoss} \xB7 ${page.telemetryNote}`));
11059
11233
  telemetryReported = true;
11060
11234
  }
11061
11235
  for (const chunk of page.chunks) {
@@ -11067,25 +11241,25 @@ var serviceLogs = async (config, args) => {
11067
11241
  if (ended && !advanced) break;
11068
11242
  if (!advanced) await new Promise((resolve8) => setTimeout(resolve8, 250));
11069
11243
  }
11070
- say6("");
11071
- say6(dim6(`stream ended \xB7 next sequence ${cursor}`));
11244
+ say7("");
11245
+ say7(dim7(`stream ended \xB7 next sequence ${cursor}`));
11072
11246
  };
11073
11247
  var serviceRestart = async (config, args) => {
11074
11248
  const needle = args.find((a) => !a.startsWith("--"));
11075
- if (needle === void 0) return fail6(usageOf("service restart"));
11249
+ if (needle === void 0) return fail7(usageOf("service restart"));
11076
11250
  const service = await findLiveService(config, needle);
11077
11251
  const restarted = await withSpinner(
11078
11252
  `restarting ${service.label ?? service.id.slice(0, 8)}\u2026`,
11079
11253
  mutateService(config, "POST", `/services/${service.id}/restart`)
11080
11254
  );
11081
- say6(`${green6("\u2713")} restarted \xB7 ${restarted.status}`);
11255
+ say7(`${green7("\u2713")} restarted \xB7 ${restarted.status}`);
11082
11256
  printServiceEndpoint(config, restarted);
11083
11257
  };
11084
11258
  var serviceInit = async (args) => {
11085
11259
  const root = gitTopLevel(process.cwd()) ?? process.cwd();
11086
11260
  const target = path21.join(root, "mend.toml");
11087
11261
  if (fs20.existsSync(target)) {
11088
- return fail6(`${target} already exists \u2014 edit it directly (init never merges)`);
11262
+ return fail7(`${target} already exists \u2014 edit it directly (init never merges)`);
11089
11263
  }
11090
11264
  const rootFiles = fs20.readdirSync(root);
11091
11265
  const proposals = [];
@@ -11127,30 +11301,30 @@ var serviceInit = async (args) => {
11127
11301
  }
11128
11302
  }
11129
11303
  if (proposals.length === 0) {
11130
- return fail6(
11304
+ return fail7(
11131
11305
  "nothing to propose \u2014 no server-ish package.json script with a nameable port, no compose ports"
11132
11306
  );
11133
11307
  }
11134
11308
  const toml = renderMendToml(proposals);
11135
- say6(dim6(`proposed ${target}:`));
11136
- say6("");
11309
+ say7(dim7(`proposed ${target}:`));
11310
+ say7("");
11137
11311
  process.stdout.write(toml);
11138
- say6("");
11312
+ say7("");
11139
11313
  if (!args.includes("--yes")) {
11140
11314
  if (process.stdin.isTTY !== true) {
11141
- return fail6("non-interactive \u2014 pass --yes to write the file");
11315
+ return fail7("non-interactive \u2014 pass --yes to write the file");
11142
11316
  }
11143
11317
  const readline = await import("node:readline/promises");
11144
11318
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
11145
11319
  const answer = await rl.question("write it? [y/N] ");
11146
11320
  rl.close();
11147
11321
  if (answer.trim().toLowerCase() !== "y") {
11148
- say6(dim6("nothing written"));
11322
+ say7(dim7("nothing written"));
11149
11323
  return;
11150
11324
  }
11151
11325
  }
11152
11326
  fs20.writeFileSync(target, toml);
11153
- say6(`${green6("\u2713")} wrote ${target} \u2014 commit it, then: mend service run ${proposals[0]?.name}`);
11327
+ say7(`${green7("\u2713")} wrote ${target} \u2014 commit it, then: mend service run ${proposals[0]?.name}`);
11154
11328
  };
11155
11329
  var tunnelServices = async (config, services, portOverride) => {
11156
11330
  for (const service of services) {
@@ -11159,15 +11333,15 @@ var tunnelServices = async (config, services, portOverride) => {
11159
11333
  (socket) => pumpConnection(socket, tunnelUrlFor(config, service.id))
11160
11334
  );
11161
11335
  await listenLocal(server, port, false).catch(
11162
- (error) => fail6(
11336
+ (error) => fail7(
11163
11337
  error.code === "EADDRINUSE" ? `127.0.0.1:${port} is already in use here \u2014 pick one with: mend service connect ${service.label} --port <n>` : error.message
11164
11338
  )
11165
11339
  );
11166
- say6(
11167
- `${green6("\u25CF")} ${service.label ?? service.id.slice(0, 8)} \u2192 127.0.0.1:${port} ${dim6(`(tunnel to ${config.url})`)}`
11340
+ say7(
11341
+ `${green7("\u25CF")} ${service.label ?? service.id.slice(0, 8)} \u2192 127.0.0.1:${port} ${dim7(`(tunnel to ${config.url})`)}`
11168
11342
  );
11169
11343
  }
11170
- say6(dim6(" connections are authenticated as you \xB7 Ctrl-C stops"));
11344
+ say7(dim7(" connections are authenticated as you \xB7 Ctrl-C stops"));
11171
11345
  await new Promise(() => {
11172
11346
  });
11173
11347
  };
@@ -11177,7 +11351,7 @@ var attachTunnels = (config, optOut) => {
11177
11351
  let attached = false;
11178
11352
  const tell = (line) => {
11179
11353
  if (!attached) {
11180
- say6(line);
11354
+ say7(line);
11181
11355
  return;
11182
11356
  }
11183
11357
  const rows = process.stdout.rows ?? 24;
@@ -11187,9 +11361,9 @@ var attachTunnels = (config, optOut) => {
11187
11361
  listServices: () => fetchServices(config),
11188
11362
  tunnelUrl: (serviceId) => tunnelUrlFor(config, serviceId),
11189
11363
  events: serverEvents(config),
11190
- onOpen: (tunnel) => tell(`${green6("\u25CF")} ${tunnel.line} ${dim6("\xB7 tunnel, closes on detach")}`),
11364
+ onOpen: (tunnel) => tell(`${green7("\u25CF")} ${tunnel.line} ${dim7("\xB7 tunnel, closes on detach")}`),
11191
11365
  onClose: (tunnel, reason) => {
11192
- if (reason === "stopped") tell(dim6(`\u25CB ${tunnel.service.label} stopped \xB7 tunnel closed`));
11366
+ if (reason === "stopped") tell(dim7(`\u25CB ${tunnel.service.label} stopped \xB7 tunnel closed`));
11193
11367
  },
11194
11368
  onError: (service, message) => tell(amber2(`${service.label} not tunneled \xB7 ${message}`))
11195
11369
  });
@@ -11213,18 +11387,18 @@ var serviceConnect = async (config, args) => {
11213
11387
  const portFlag = args.indexOf("--port");
11214
11388
  const portOverride = portFlag === -1 ? null : Number(args[portFlag + 1]);
11215
11389
  if (portOverride !== null && !Number.isInteger(portOverride)) {
11216
- return fail6("--port takes a port number");
11390
+ return fail7("--port takes a port number");
11217
11391
  }
11218
11392
  const names = args.filter((a, i) => !a.startsWith("--") && i !== portFlag + 1);
11219
11393
  const live = (await fetchServices(config)).filter((s) => s.protocol === "tcp");
11220
11394
  const picked = names.length === 0 ? live : live.filter((s) => names.some((n) => s.label === n || s.id.startsWith(n)));
11221
11395
  if (picked.length === 0) {
11222
- return fail6(
11396
+ return fail7(
11223
11397
  names.length === 0 ? "no live TCP services \u2014 mend service run starts one" : `no live TCP service matches "${names.join('", "')}"`
11224
11398
  );
11225
11399
  }
11226
11400
  if (portOverride !== null && picked.length !== 1) {
11227
- return fail6("--port applies to exactly one service \u2014 name it");
11401
+ return fail7("--port applies to exactly one service \u2014 name it");
11228
11402
  }
11229
11403
  await tunnelServices(config, picked, portOverride);
11230
11404
  };
@@ -11265,23 +11439,23 @@ var memoryPathOf = (name) => {
11265
11439
  };
11266
11440
  var memoryImport = async (config, args) => {
11267
11441
  const repoRoot = cwdFacts(process.cwd()).repoRoot;
11268
- if (repoRoot === null) return fail6("run mend memory import inside the repository's checkout");
11442
+ if (repoRoot === null) return fail7("run mend memory import inside the repository's checkout");
11269
11443
  const claudeDir = claudeMemoryDirFor(repoRoot);
11270
11444
  const claude = claudeDir === null ? null : scanClaudeMemory(claudeDir);
11271
11445
  const codex = await scanCodexMemory(repoRoot);
11272
- for (const note of [...claude?.notes ?? [], ...codex.notes]) say6(dim6(` ${note}`));
11446
+ for (const note of [...claude?.notes ?? [], ...codex.notes]) say7(dim7(` ${note}`));
11273
11447
  const files = [...claude?.files ?? [], ...codex.files];
11274
11448
  if (files.length === 0) {
11275
- return fail6(`neither claude nor codex keeps memory for ${repoRoot} on this machine`);
11449
+ return fail7(`neither claude nor codex keeps memory for ${repoRoot} on this machine`);
11276
11450
  }
11277
11451
  const project2 = await findProject(config, takeFlagValue4(args, "--project"));
11278
11452
  if (claude !== null && claude.files.length > 0) {
11279
- say6(
11453
+ say7(
11280
11454
  `claude memory \xB7 ${claude.dir} \xB7 ${claude.files.length} file${claude.files.length === 1 ? "" : "s"}`
11281
11455
  );
11282
11456
  }
11283
11457
  if (codex.files.length > 0) {
11284
- say6(
11458
+ say7(
11285
11459
  `codex memory \xB7 ${codex.home} \xB7 ${codex.summaries} conversation summar${codex.summaries === 1 ? "y" : "ies"} of this repository`
11286
11460
  );
11287
11461
  }
@@ -11296,12 +11470,12 @@ var memoryImport = async (config, args) => {
11296
11470
  source === null ? { files } : { files, source }
11297
11471
  )
11298
11472
  );
11299
- say6(
11300
- `${dryRun ? "would import" : green6("imported")} into ${project2.name} \xB7 ${importReportCounts(report)}`
11473
+ say7(
11474
+ `${dryRun ? "would import" : green7("imported")} into ${project2.name} \xB7 ${importReportCounts(report)}`
11301
11475
  );
11302
- for (const line of importReportLines(report)) say6(dim6(line));
11303
- say6(
11304
- dim6(
11476
+ for (const line of importReportLines(report)) say7(dim7(line));
11477
+ say7(
11478
+ dim7(
11305
11479
  dryRun ? "--dry-run: nothing written" : "every version replaced is kept \xB7 sessions in the project receive it from the next launch"
11306
11480
  )
11307
11481
  );
@@ -11316,7 +11490,7 @@ var memoryCommand = async (config, args) => {
11316
11490
  const name = rest.find(
11317
11491
  (arg, index) => !arg.startsWith("--") && rest[index - 1] !== "--project"
11318
11492
  );
11319
- if (name === void 0) return fail6(usageOf(`memory ${verb}`));
11493
+ if (name === void 0) return fail7(usageOf(`memory ${verb}`));
11320
11494
  const query = `?path=${encodeURIComponent(memoryPathOf(name))}`;
11321
11495
  if (verb === "rm") {
11322
11496
  const removed = await api(
@@ -11324,7 +11498,7 @@ var memoryCommand = async (config, args) => {
11324
11498
  "DELETE",
11325
11499
  `${base}/file${query}`
11326
11500
  );
11327
- return say6(
11501
+ return say7(
11328
11502
  removed.removed ? `removed ${name} \xB7 kept as a version` : `${name}: not in memory`
11329
11503
  );
11330
11504
  }
@@ -11344,15 +11518,15 @@ var memoryCommand = async (config, args) => {
11344
11518
  base
11345
11519
  );
11346
11520
  if (view.files.length === 0) {
11347
- say6(
11348
- `${project2.name}: no agent memory yet ${dim6("\xB7 mend memory import brings this machine's")}`
11521
+ say7(
11522
+ `${project2.name}: no agent memory yet ${dim7("\xB7 mend memory import brings this machine's")}`
11349
11523
  );
11350
11524
  return;
11351
11525
  }
11352
11526
  const width = Math.max(...view.files.map((file) => file.name.length));
11353
11527
  for (const file of view.files) {
11354
- say6(
11355
- `${file.harness.padEnd(7)} ${file.name.padEnd(width)} ${kilobytes(file.bytes).padStart(8)} ${dim6(
11528
+ say7(
11529
+ `${file.harness.padEnd(7)} ${file.name.padEnd(width)} ${kilobytes(file.bytes).padStart(8)} ${dim7(
11356
11530
  `${file.updatedAt.slice(0, 16).replace("T", " ")} \xB7 ${file.updatedBySession === null ? "imported" : `session ${file.updatedBySession.slice(0, 8)}`}`
11357
11531
  )}`
11358
11532
  );
@@ -11362,17 +11536,17 @@ var secretsCommand = async (config, args) => {
11362
11536
  const [verb, ...rest] = args;
11363
11537
  if (verb === "add" || verb === "rm") {
11364
11538
  const given = rest.find((arg, index) => !arg.startsWith("--") && rest[index - 1] !== "--from");
11365
- if (given === void 0) return fail6(usageOf(`secrets ${verb}`));
11539
+ if (given === void 0) return fail7(usageOf(`secrets ${verb}`));
11366
11540
  const resolved = secretFilePathOf(given, os13.homedir());
11367
- if (resolved.issue !== null) return fail6(resolved.issue);
11541
+ if (resolved.issue !== null) return fail7(resolved.issue);
11368
11542
  if (verb === "rm") {
11369
11543
  const removed = await api(
11370
11544
  config,
11371
11545
  "DELETE",
11372
11546
  `/me/secret-files?path=${encodeURIComponent(resolved.path)}`
11373
11547
  );
11374
- return say6(
11375
- removed.removed ? `removed ~/${resolved.path} ${dim6("\xB7 sessions launched from now on do not receive it")}` : `~/${resolved.path}: not kept`
11548
+ return say7(
11549
+ removed.removed ? `removed ~/${resolved.path} ${dim7("\xB7 sessions launched from now on do not receive it")}` : `~/${resolved.path}: not kept`
11376
11550
  );
11377
11551
  }
11378
11552
  const from = takeFlagValue4(rest, "--from");
@@ -11380,31 +11554,31 @@ var secretsCommand = async (config, args) => {
11380
11554
  try {
11381
11555
  bytes = fs20.readFileSync(from ?? 0);
11382
11556
  } catch (error) {
11383
- return fail6(
11557
+ return fail7(
11384
11558
  from === null ? `nothing on stdin: pass --from <file> or pipe the content in` : `${from}: ${error instanceof Error ? error.message : String(error)}`
11385
11559
  );
11386
11560
  }
11387
11561
  if (bytes.byteLength === 0)
11388
- return fail6(from === null ? "nothing on stdin" : `${from} is empty`);
11562
+ return fail7(from === null ? "nothing on stdin" : `${from} is empty`);
11389
11563
  const saved = await api(config, "PUT", "/me/secret-files", secretFileUploadOf(resolved.path, bytes));
11390
- say6(
11391
- `${green6(saved.action)} ~/${saved.file.path} \xB7 ${saved.file.bytes} B ${dim6(
11564
+ say7(
11565
+ `${green7(saved.action)} ~/${saved.file.path} \xB7 ${saved.file.bytes} B ${dim7(
11392
11566
  "\xB7 sessions launched from now on receive it"
11393
11567
  )}`
11394
11568
  );
11395
11569
  return;
11396
11570
  }
11397
- if (verb !== void 0 && verb !== "list") return fail6(usageOf("secrets"));
11571
+ if (verb !== void 0 && verb !== "list") return fail7(usageOf("secrets"));
11398
11572
  const view = await api(
11399
11573
  config,
11400
11574
  "GET",
11401
11575
  "/me/secret-files"
11402
11576
  );
11403
11577
  if (view.files.length === 0) {
11404
- say6(`no secret files ${dim6("\xB7 mend secrets add <path> --from <file> keeps one")}`);
11578
+ say7(`no secret files ${dim7("\xB7 mend secrets add <path> --from <file> keeps one")}`);
11405
11579
  return;
11406
11580
  }
11407
- for (const line of secretFileLines(view.files)) say6(line);
11581
+ for (const line of secretFileLines(view.files)) say7(line);
11408
11582
  };
11409
11583
  var isProvider = (value) => value === "claude" || value === "codex" || value === "github";
11410
11584
  var readIfExists = (file) => fs20.existsSync(file) ? fs20.readFileSync(file, "utf8") : null;
@@ -11458,7 +11632,7 @@ var accountsCommand = async (config) => {
11458
11632
  try {
11459
11633
  lines = await accountsLines(config);
11460
11634
  } catch (error) {
11461
- return fail6(error instanceof Error ? error.message : String(error));
11635
+ return fail7(error instanceof Error ? error.message : String(error));
11462
11636
  }
11463
11637
  for (const line of lines) process.stdout.write(`${line}
11464
11638
  `);
@@ -11470,7 +11644,7 @@ var claudeGrantSecret = () => {
11470
11644
  var doctorBundle = (config, args) => doctorBundleCommand(args, {
11471
11645
  defaultDir: path21.join(mendCliHome(), "bundles"),
11472
11646
  now: () => /* @__PURE__ */ new Date(),
11473
- say: say6,
11647
+ say: say7,
11474
11648
  warn: (line) => process.stderr.write(`${line}
11475
11649
  `),
11476
11650
  collectors: (tail) => bundleCollectors({
@@ -11515,24 +11689,24 @@ var claudeGrant = async () => {
11515
11689
  const dir = throwawayLoginDir(home, "claude-login-");
11516
11690
  try {
11517
11691
  if (grantStatus(cli, dir) === null) {
11518
- fail6(
11692
+ fail7(
11519
11693
  "claude: could not run `claude auth status` \u2014 install Claude Code, set MEND_CLAUDE_BIN, or paste a credential: mend connect claude --from-stdin"
11520
11694
  );
11521
11695
  return null;
11522
11696
  }
11523
- say6(" Mend needs its own Claude login; it is sent to your server and not kept here");
11524
- say6(dim6(" your own Claude login stays as it is"));
11697
+ say7(" Mend needs its own Claude login; it is sent to your server and not kept here");
11698
+ say7(dim7(" your own Claude login stays as it is"));
11525
11699
  if (!runClaudeLogin(cli, dir)) {
11526
- fail6("claude: the login did not complete");
11700
+ fail7("claude: the login did not complete");
11527
11701
  return null;
11528
11702
  }
11529
11703
  const status = grantStatus(cli, dir);
11530
11704
  if (status === null || !status.loggedIn) {
11531
- fail6("claude: the login completed but Claude still reports no grant in Mend's directory");
11705
+ fail7("claude: the login completed but Claude still reports no grant in Mend's directory");
11532
11706
  return null;
11533
11707
  }
11534
11708
  if (status.configDirectory !== null && path21.resolve(status.configDirectory) !== path21.resolve(dir)) {
11535
- fail6(
11709
+ fail7(
11536
11710
  `claude: this Claude read ${status.configDirectory} instead of ${dir}, so a separate grant is not possible \u2014 connect the shared one deliberately with --use-my-login`
11537
11711
  );
11538
11712
  return null;
@@ -11540,33 +11714,33 @@ var claudeGrant = async () => {
11540
11714
  const read = readGrant(dir);
11541
11715
  if (read.kind === "missing") {
11542
11716
  const where = read.triedService === null ? read.triedPath : `${read.triedPath} or the Keychain item ${read.triedService}`;
11543
- fail6(`claude: logged in, but no credential to read \u2014 looked in ${where}`);
11717
+ fail7(`claude: logged in, but no credential to read \u2014 looked in ${where}`);
11544
11718
  return null;
11545
11719
  }
11546
11720
  const why = staleGrantReason(read.secret);
11547
11721
  if (why !== null) {
11548
- fail6(`claude: the new login is already ${why}`);
11722
+ fail7(`claude: the new login is already ${why}`);
11549
11723
  return null;
11550
11724
  }
11551
11725
  const mine = localCredential("claude");
11552
11726
  if (mine !== null && sameGrant(read.secret, mine)) {
11553
- fail6(
11727
+ fail7(
11554
11728
  "claude: that is the same grant this machine's Claude holds, so both sides would race on refresh \u2014 connect it deliberately with --use-my-login"
11555
11729
  );
11556
11730
  return null;
11557
11731
  }
11558
11732
  const personalAfter = grantStatus(cli, personal);
11559
11733
  if (personalBefore?.loggedIn === true && personalAfter?.loggedIn === false) {
11560
- say6(
11734
+ say7(
11561
11735
  ` your own Claude login was signed out by this one \u2014 this account allows one grant at a time. Run \`claude auth login\` to get it back, and connect the shared grant with --use-my-login instead.`
11562
11736
  );
11563
11737
  } else if (personalAfter?.loggedIn === true) {
11564
- say6(dim6(" your own Claude login still works \xB7 verified"));
11738
+ say7(dim7(" your own Claude login still works \xB7 verified"));
11565
11739
  }
11566
11740
  const kept = claudeGrantDir(home);
11567
11741
  if (fs20.existsSync(kept)) {
11568
11742
  forgetGrant(kept);
11569
- say6(dim6(` removed the copy an older mend kept in ${kept} \xB7 the server refreshes the login`));
11743
+ say7(dim7(` removed the copy an older mend kept in ${kept} \xB7 the server refreshes the login`));
11570
11744
  }
11571
11745
  return read.secret;
11572
11746
  } finally {
@@ -11580,12 +11754,12 @@ var connectPi = async (config, flags) => {
11580
11754
  return;
11581
11755
  }
11582
11756
  const scan = scanPiProfile(takeFlagValue4(flags, "--dir") ?? piAgentDir());
11583
- if ("error" in scan) return fail6(scan.error);
11584
- for (const line of piProfileLines(scan)) say6(line);
11757
+ if ("error" in scan) return fail7(scan.error);
11758
+ for (const line of piProfileLines(scan)) say7(line);
11585
11759
  const issue = validatePiProfile(scan.files);
11586
- if (issue !== null) return fail6(`pi: ${issue}`);
11760
+ if (issue !== null) return fail7(`pi: ${issue}`);
11587
11761
  if (flags.includes("--dry-run")) {
11588
- say6(dim6(" --dry-run: nothing sent"));
11762
+ say7(dim7(" --dry-run: nothing sent"));
11589
11763
  return;
11590
11764
  }
11591
11765
  const saved = await withSpinner(
@@ -11606,13 +11780,13 @@ var connectCommand = async (config, args) => {
11606
11780
  const [providerArg, ...flags] = args;
11607
11781
  if (providerArg === "pi") return connectPi(config, flags);
11608
11782
  if (!isProvider(providerArg)) {
11609
- return fail6(usageOf("connect"));
11783
+ return fail7(usageOf("connect"));
11610
11784
  }
11611
11785
  const provider = providerArg;
11612
11786
  if (flags.includes("--remove")) {
11613
11787
  const identity = await api(config, "GET", "/me/sealant");
11614
11788
  const account2 = identity.accounts.find((row) => row.provider === provider);
11615
- if (account2 === void 0) return fail6(`${provider}: nothing connected`);
11789
+ if (account2 === void 0) return fail7(`${provider}: nothing connected`);
11616
11790
  await api(config, "DELETE", `/me/sealant/accounts/${account2.id}`);
11617
11791
  process.stdout.write(`${provider}: disconnected
11618
11792
  `);
@@ -11621,15 +11795,15 @@ var connectCommand = async (config, args) => {
11621
11795
  let secret;
11622
11796
  if (flags.includes("--from-stdin")) {
11623
11797
  secret = fs20.readFileSync(0, "utf8").trim();
11624
- if (secret === "") return fail6("nothing on stdin");
11798
+ if (secret === "") return fail7("nothing on stdin");
11625
11799
  } else if (provider === "codex" && !flags.includes("--use-my-login")) {
11626
11800
  const grant = codexGrant({
11627
11801
  cli: codexCli(),
11628
11802
  personalAuthJson: readIfExists(path21.join(personalCodexHome(), "auth.json")),
11629
- say: say6,
11803
+ say: say7,
11630
11804
  parent: mendCliHome()
11631
11805
  });
11632
- if (grant.kind === "failed") return fail6(grant.reason);
11806
+ if (grant.kind === "failed") return fail7(grant.reason);
11633
11807
  secret = grant.secret;
11634
11808
  } else if (provider === "claude" && !flags.includes("--use-my-login")) {
11635
11809
  secret = await claudeGrant();
@@ -11638,11 +11812,11 @@ var connectCommand = async (config, args) => {
11638
11812
  secret = localCredential(provider);
11639
11813
  if (secret === null) {
11640
11814
  const where = provider === "github" ? "`gh auth login` first, or pipe a token: gh auth token | mend connect github --from-stdin" : provider === "codex" ? "`codex login` first, or: mend connect codex --from-stdin < auth.json" : "`claude auth login` first, or: mend connect claude --from-stdin";
11641
- return fail6(`${provider}: no credential on this machine \u2014 ${where}`);
11815
+ return fail7(`${provider}: no credential on this machine \u2014 ${where}`);
11642
11816
  }
11643
11817
  if (provider === "claude" || provider === "codex") {
11644
- say6(
11645
- dim6(
11818
+ say7(
11819
+ dim7(
11646
11820
  " --use-my-login: Mend and this machine will share one login, and whichever refreshes second is signed out"
11647
11821
  )
11648
11822
  );
@@ -11650,7 +11824,7 @@ var connectCommand = async (config, args) => {
11650
11824
  }
11651
11825
  const narrowed = narrowCredential(provider, secret);
11652
11826
  if (narrowed.kind === "narrowed" && narrowed.dropped.length > 0) {
11653
- say6(dim6(` keeping ${narrowed.dropped.join(", ")} on this machine`));
11827
+ say7(dim7(` keeping ${narrowed.dropped.join(", ")} on this machine`));
11654
11828
  }
11655
11829
  const account = await withSpinner(
11656
11830
  `connecting ${provider}`,
@@ -11663,8 +11837,8 @@ var connectCommand = async (config, args) => {
11663
11837
  `);
11664
11838
  const facts = claudeGrantFacts(narrowed.secret);
11665
11839
  if (facts !== null) {
11666
- say6(
11667
- dim6(
11840
+ say7(
11841
+ dim7(
11668
11842
  ` access expires ${minuteOrUnknown(facts.accessExpiresAt)} \xB7 grant expires ${minuteOrUnknown(facts.refreshExpiresAt)}`
11669
11843
  )
11670
11844
  );
@@ -11690,25 +11864,25 @@ var login = async (config, args) => {
11690
11864
  defaultUrl: config.url,
11691
11865
  save: (next) => {
11692
11866
  saveCliConfig({ url: next.url, token: next.token, deviceId: next.deviceId });
11693
- say6(dim6(` token saved to ${CONFIG_PATH} (0600)`));
11867
+ say7(dim7(` token saved to ${CONFIG_PATH} (0600)`));
11694
11868
  }
11695
11869
  });
11696
11870
  };
11697
11871
  var logout = async (config) => {
11698
11872
  if (!fs20.existsSync(CONFIG_PATH) && config.token === null) {
11699
- say6(dim6("nothing saved \u2014 already signed out"));
11873
+ say7(dim7("nothing saved \u2014 already signed out"));
11700
11874
  return;
11701
11875
  }
11702
11876
  if (config.token !== null && config.deviceId !== null) {
11703
11877
  try {
11704
11878
  await request(config, "DELETE", `/me/devices/${config.deviceId}`);
11705
- say6(`${green6("\u2713")} device revoked on ${config.url}`);
11879
+ say7(`${green7("\u2713")} device revoked on ${config.url}`);
11706
11880
  } catch {
11707
- say6(dim6(" could not revoke on the server \u2014 end it under Settings \u2192 Devices"));
11881
+ say7(dim7(" could not revoke on the server \u2014 end it under Settings \u2192 Devices"));
11708
11882
  }
11709
11883
  }
11710
11884
  saveCliConfig({ ...config, token: null, deviceId: null });
11711
- say6(`${green6("\u2713")} signed out \xB7 ${dim6(`token removed from ${CONFIG_PATH}`)}`);
11885
+ say7(`${green7("\u2713")} signed out \xB7 ${dim7(`token removed from ${CONFIG_PATH}`)}`);
11712
11886
  };
11713
11887
  var UNINSTALL_CHOICES = [
11714
11888
  { scope: "all", text: "everything \xB7 the server on this machine and this machine's Mend files" },
@@ -11720,20 +11894,20 @@ var UNINSTALL_CHOICES = [
11720
11894
  ];
11721
11895
  var askUninstallScope = async () => {
11722
11896
  if (process.stdin.isTTY !== true || process.stdout.isTTY !== true) {
11723
- return fail6(`${UNINSTALL_USAGE} \xB7 no terminal to ask on`);
11897
+ return fail7(`${UNINSTALL_USAGE} \xB7 no terminal to ask on`);
11724
11898
  }
11725
- say6("what should go?");
11726
- UNINSTALL_CHOICES.forEach((choice, index) => say6(` ${index + 1}. ${choice.text}`));
11899
+ say7("what should go?");
11900
+ UNINSTALL_CHOICES.forEach((choice, index) => say7(` ${index + 1}. ${choice.text}`));
11727
11901
  const readline = await import("node:readline/promises");
11728
11902
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
11729
11903
  const answer = (await rl.question(" 1, 2 or 3: ")).trim();
11730
11904
  rl.close();
11731
11905
  const chosen = UNINSTALL_CHOICES[Number(answer) - 1];
11732
- if (chosen === void 0) return fail6(`"${answer}" is not one of the choices`);
11906
+ if (chosen === void 0) return fail7(`"${answer}" is not one of the choices`);
11733
11907
  return chosen.scope;
11734
11908
  };
11735
11909
  var confirmUninstall = async (word) => {
11736
- if (process.stdin.isTTY !== true) return fail6("non-interactive \u2014 pass --yes to remove");
11910
+ if (process.stdin.isTTY !== true) return fail7("non-interactive \u2014 pass --yes to remove");
11737
11911
  const readline = await import("node:readline/promises");
11738
11912
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
11739
11913
  const answer = (await rl.question(word === "y" ? "remove? [y/N] " : `type ${word} to remove: `)).trim().toLowerCase();
@@ -11742,7 +11916,7 @@ var confirmUninstall = async (word) => {
11742
11916
  };
11743
11917
  var uninstallCommand = async (config, args) => {
11744
11918
  const parsed = parseUninstallArgs(args);
11745
- if ("error" in parsed) return fail6(parsed.error);
11919
+ if ("error" in parsed) return fail7(parsed.error);
11746
11920
  const scope = parsed.scope ?? await askUninstallScope();
11747
11921
  const server = nodeServerRuntime();
11748
11922
  const runtime = {
@@ -11761,42 +11935,42 @@ var uninstallCommand = async (config, args) => {
11761
11935
  }
11762
11936
  };
11763
11937
  const plan = await describeUninstall(runtime, scope);
11764
- say6(dim6(`mend uninstall \xB7 ${scope === "all" ? "everything" : scope}`));
11765
- for (const line of planLines(plan, server.configDir)) say6(` ${line}`);
11938
+ say7(dim7(`mend uninstall \xB7 ${scope === "all" ? "everything" : scope}`));
11939
+ for (const line of planLines(plan, server.configDir)) say7(` ${line}`);
11766
11940
  const nothing = (plan.server === null || plan.server === "none") && (plan.home === null || plan.home.cliConfig === null && plan.home.sshDirectory === null && plan.home.managedSshBlocks === 0);
11767
11941
  if (nothing) {
11768
- say6(dim6("nothing to remove"));
11942
+ say7(dim7("nothing to remove"));
11769
11943
  return;
11770
11944
  }
11771
11945
  if (planDeletesData(plan)) {
11772
- say6("repositories, worktrees, the database and its backups are deleted with the server");
11946
+ say7("repositories, worktrees, the database and its backups are deleted with the server");
11773
11947
  }
11774
11948
  if (!parsed.yes && !await confirmUninstall(planDeletesData(plan) ? "delete" : "y")) {
11775
- say6(dim6("nothing removed"));
11949
+ say7(dim7("nothing removed"));
11776
11950
  return;
11777
11951
  }
11778
11952
  const outcome = await executeUninstall(runtime, plan);
11779
- for (const line of outcome.leftovers) say6(dim6(` kept \xB7 ${line}`));
11953
+ for (const line of outcome.leftovers) say7(dim7(` kept \xB7 ${line}`));
11780
11954
  if (outcome.failures.length > 0) {
11781
- return fail6(outcome.failures.join("\n"));
11955
+ return fail7(outcome.failures.join("\n"));
11782
11956
  }
11783
- say6(
11784
- `${green6("\u2713")} ${scope === "all" ? "Mend is gone from this machine" : scope === "server" ? "the server is gone from this machine" : "this machine no longer holds Mend files"}`
11957
+ say7(
11958
+ `${green7("\u2713")} ${scope === "all" ? "Mend is gone from this machine" : scope === "server" ? "the server is gone from this machine" : "this machine no longer holds Mend files"}`
11785
11959
  );
11786
11960
  };
11787
11961
  var printGitKey = (key) => {
11788
11962
  if (key.publicKey === null) return;
11789
- say6(key.publicKey);
11790
- if (key.fingerprint !== null) say6(dim6(` ${key.fingerprint}`));
11791
- say6(dim6(" add this to your git account's SSH keys (GitHub: settings \u2192 SSH keys) so"));
11792
- say6(dim6(" every repository you can reach works; for one repository only, add it"));
11793
- say6(dim6(" as that repository's deploy key instead (grant write if sessions push)"));
11963
+ say7(key.publicKey);
11964
+ if (key.fingerprint !== null) say7(dim7(` ${key.fingerprint}`));
11965
+ say7(dim7(" add this to your git account's SSH keys (GitHub: settings \u2192 SSH keys) so"));
11966
+ say7(dim7(" every repository you can reach works; for one repository only, add it"));
11967
+ say7(dim7(" as that repository's deploy key instead (grant write if sessions push)"));
11794
11968
  };
11795
11969
  var keysShow = async (config) => {
11796
11970
  const key = await api(config, "GET", "/keys/git");
11797
11971
  if (!key.exists) {
11798
- say6(
11799
- `no Mend key yet ${dim6("\u2014 mend keys init generates one (ed25519, stays on the server host)")}`
11972
+ say7(
11973
+ `no Mend key yet ${dim7("\u2014 mend keys init generates one (ed25519, stays on the server host)")}`
11800
11974
  );
11801
11975
  return;
11802
11976
  }
@@ -11804,13 +11978,13 @@ var keysShow = async (config) => {
11804
11978
  };
11805
11979
  var keysInit = async (config) => {
11806
11980
  const key = await api(config, "POST", "/keys/git");
11807
- say6(`${green6("\u2713")} Mend key ready ${dim6("(private half stays on the server host)")}`);
11981
+ say7(`${green7("\u2713")} Mend key ready ${dim7("(private half stays on the server host)")}`);
11808
11982
  printGitKey(key);
11809
11983
  };
11810
11984
  var keysShare = async (config) => {
11811
11985
  const agentSock = process.env["SSH_AUTH_SOCK"];
11812
11986
  if (agentSock === void 0 || agentSock === "") {
11813
- return fail6("SSH_AUTH_SOCK is not set \u2014 start (or plug in) your ssh-agent first");
11987
+ return fail7("SSH_AUTH_SOCK is not set \u2014 start (or plug in) your ssh-agent first");
11814
11988
  }
11815
11989
  await shareAgent({
11816
11990
  url: () => socketUrl(config, "keys-bridge", { host: os13.hostname() }),
@@ -11819,26 +11993,26 @@ var keysShare = async (config) => {
11819
11993
  onEvent: (event) => {
11820
11994
  switch (event.kind) {
11821
11995
  case "connected":
11822
- say6(`${green6("\u25CF")} sharing this machine's ssh-agent with ${config.url}`);
11823
- say6(dim6(` agent: ${agentSock} \xB7 signature requests print here \xB7 Ctrl-C stops sharing`));
11996
+ say7(`${green7("\u25CF")} sharing this machine's ssh-agent with ${config.url}`);
11997
+ say7(dim7(` agent: ${agentSock} \xB7 signature requests print here \xB7 Ctrl-C stops sharing`));
11824
11998
  return;
11825
11999
  case "disconnected":
11826
- say6(
11827
- dim6(`not connected \u2014 retrying in ${Math.round(event.retryMs / 1e3)}s (Ctrl-C stops)`)
12000
+ say7(
12001
+ dim7(`not connected \u2014 retrying in ${Math.round(event.retryMs / 1e3)}s (Ctrl-C stops)`)
11828
12002
  );
11829
12003
  return;
11830
12004
  case "sign-requested":
11831
- say6(`${amber2("\u270E")} signature requested by mend ${dim6(`(${event.context})`)}`);
11832
- say6(dim6(" waiting \u2014 touch your key if it blinks (up to 60s)\u2026"));
12005
+ say7(`${amber2("\u270E")} signature requested by mend ${dim7(`(${event.context})`)}`);
12006
+ say7(dim7(" waiting \u2014 touch your key if it blinks (up to 60s)\u2026"));
11833
12007
  return;
11834
12008
  case "identities-requested":
11835
- say6(dim6(` identities requested (${event.context})`));
12009
+ say7(dim7(` identities requested (${event.context})`));
11836
12010
  return;
11837
12011
  case "signed":
11838
- say6(`${green6("\u2713")} signed ${dim6(`(${event.seconds.toFixed(1)}s)`)}`);
12012
+ say7(`${green7("\u2713")} signed ${dim7(`(${event.seconds.toFixed(1)}s)`)}`);
11839
12013
  return;
11840
12014
  case "not-signed":
11841
- say6(`${amber2("\u2717")} not signed \u2014 ${event.message}`);
12015
+ say7(`${amber2("\u2717")} not signed \u2014 ${event.message}`);
11842
12016
  return;
11843
12017
  }
11844
12018
  }
@@ -11848,15 +12022,15 @@ var gitAuthorCommand = async (config, args) => {
11848
12022
  const asked = parseGitAuthorArgs(args);
11849
12023
  switch (asked.kind) {
11850
12024
  case "usage":
11851
- return fail6(usageOf("git-author"));
12025
+ return fail7(usageOf("git-author"));
11852
12026
  case "invalid":
11853
- return fail6(asked.message);
12027
+ return fail7(asked.message);
11854
12028
  case "show":
11855
- say6(gitAuthorLine(await api(config, "GET", "/me/git-author")));
12029
+ say7(gitAuthorLine(await api(config, "GET", "/me/git-author")));
11856
12030
  return;
11857
12031
  case "clear": {
11858
12032
  const author = await api(config, "DELETE", "/me/git-author");
11859
- say6(`${green6("\u2713")} git author \xB7 ${gitAuthorLine(author)}`);
12033
+ say7(`${green7("\u2713")} git author \xB7 ${gitAuthorLine(author)}`);
11860
12034
  return;
11861
12035
  }
11862
12036
  case "set": {
@@ -11864,9 +12038,9 @@ var gitAuthorCommand = async (config, args) => {
11864
12038
  name: asked.name,
11865
12039
  email: asked.email
11866
12040
  });
11867
- say6(`${green6("\u2713")} git author \xB7 ${gitAuthorLine(author)}`);
11868
- say6(
11869
- dim6(" sessions launched from now on commit as this, unless their dotfiles say otherwise")
12041
+ say7(`${green7("\u2713")} git author \xB7 ${gitAuthorLine(author)}`);
12042
+ say7(
12043
+ dim7(" sessions launched from now on commit as this, unless their dotfiles say otherwise")
11870
12044
  );
11871
12045
  return;
11872
12046
  }
@@ -11875,19 +12049,19 @@ var gitAuthorCommand = async (config, args) => {
11875
12049
  var keysMode = async (config, args) => {
11876
12050
  const [value] = args;
11877
12051
  if (value !== void 0 && value !== "mend-key" && value !== "bridge") {
11878
- return fail6(`keys mode takes mend-key or bridge, not "${value}"`);
12052
+ return fail7(`keys mode takes mend-key or bridge, not "${value}"`);
11879
12053
  }
11880
12054
  const access = value === void 0 ? await api(config, "GET", "/me/git-access") : await api(config, "PUT", "/me/git-access", { mode: value });
11881
- if (value !== void 0) say6(`${green6("\u2713")} git access \xB7 ${value}`);
12055
+ if (value !== void 0) say7(`${green7("\u2713")} git access \xB7 ${value}`);
11882
12056
  if (access.mode === "mend-key") {
11883
- say6(`mend-key ${dim6("\u2014 your Mend key on the server signs; works whenever the server is up")}`);
12057
+ say7(`mend-key ${dim7("\u2014 your Mend key on the server signs; works whenever the server is up")}`);
11884
12058
  if (access.key.exists) printGitKey(access.key);
11885
- else say6(dim6(" no key yet \u2014 mend keys init creates it"));
12059
+ else say7(dim7(" no key yet \u2014 mend keys init creates it"));
11886
12060
  return;
11887
12061
  }
11888
- say6(`bridge ${dim6("\u2014 this machine's ssh-agent signs; only while a mend command runs here")}`);
11889
- say6(
11890
- access.bridge.connected ? `${green6("\u25CF")} signer connected \xB7 ${access.bridge.clientName ?? "unknown machine"}` : dim6(" no signer connected \u2014 mend shares the agent whenever it runs (or: mend keys share)")
12062
+ say7(`bridge ${dim7("\u2014 this machine's ssh-agent signs; only while a mend command runs here")}`);
12063
+ say7(
12064
+ access.bridge.connected ? `${green7("\u25CF")} signer connected \xB7 ${access.bridge.clientName ?? "unknown machine"}` : dim7(" no signer connected \u2014 mend shares the agent whenever it runs (or: mend keys share)")
11891
12065
  );
11892
12066
  };
11893
12067
  var keysCommand = async (config, args) => {
@@ -11903,42 +12077,42 @@ var keysCommand = async (config, args) => {
11903
12077
  case void 0:
11904
12078
  return keysShow(config);
11905
12079
  default:
11906
- return fail6(`unknown keys command "${verb}" \xB7 mend help keys lists them`);
12080
+ return fail7(`unknown keys command "${verb}" \xB7 mend help keys lists them`);
11907
12081
  }
11908
12082
  };
11909
12083
  var formatDotfileBytes = (bytes) => bytes < 1024 ? `${bytes} B` : `${(bytes / 1024).toFixed(1)} KB`;
11910
- var repositoryLine = (repository) => repository === null ? `repo ${dim6("none")}` : `repo ${repository.url} ${dim6(`(${dotfilesRepositoryFacts(repository)})`)}`;
12084
+ var repositoryLine = (repository) => repository === null ? `repo ${dim7("none")}` : `repo ${repository.url} ${dim7(`(${dotfilesRepositoryFacts(repository)})`)}`;
11911
12085
  var dotfilesShow = async (config) => {
11912
12086
  const dotfiles = await api(config, "GET", "/dotfiles");
11913
- say6(repositoryLine(dotfiles.repository));
12087
+ say7(repositoryLine(dotfiles.repository));
11914
12088
  if (dotfiles.snapshot === null) {
11915
- say6(`snapshot ${dim6("none \u2014 sync from this machine: mend dotfiles sync --all")}`);
12089
+ say7(`snapshot ${dim7("none \u2014 sync from this machine: mend dotfiles sync --all")}`);
11916
12090
  return;
11917
12091
  }
11918
12092
  const snapshot = dotfiles.snapshot;
11919
- say6(
11920
- `snapshot ${snapshot.files.length} file${snapshot.files.length === 1 ? "" : "s"} \xB7 from ${snapshot.source} \xB7 ${dim6(snapshot.sha.slice(0, 7))}`
12093
+ say7(
12094
+ `snapshot ${snapshot.files.length} file${snapshot.files.length === 1 ? "" : "s"} \xB7 from ${snapshot.source} \xB7 ${dim7(snapshot.sha.slice(0, 7))}`
11921
12095
  );
11922
12096
  for (const file of snapshot.files) {
11923
- say6(` ${file.path.padEnd(36)} ${dim6(formatDotfileBytes(file.bytes))}`);
12097
+ say7(` ${file.path.padEnd(36)} ${dim7(formatDotfileBytes(file.bytes))}`);
11924
12098
  }
11925
12099
  };
11926
12100
  var dotfilesRepo = async (config, args) => {
11927
12101
  const parsed = parseDotfilesRepoArgs(args);
11928
- if (parsed.kind === "error") return fail6(`${parsed.error}
12102
+ if (parsed.kind === "error") return fail7(`${parsed.error}
11929
12103
  ${usageOf("dotfiles repo")}`);
11930
12104
  const repository = parsed.kind === "clear" ? null : parsed.repository;
11931
- if (repository !== null) say6(dim6(`cloning ${repository.url} on the server to check it\u2026`));
12105
+ if (repository !== null) say7(dim7(`cloning ${repository.url} on the server to check it\u2026`));
11932
12106
  const result = await api(config, "PUT", "/dotfiles/repository", { repository });
11933
12107
  if (result.repository === null) {
11934
- say6(
11935
- `${green6("\u2713")} cleared the dotfiles repository ${dim6("\u2014 applies from the next session launch")}`
12108
+ say7(
12109
+ `${green7("\u2713")} cleared the dotfiles repository ${dim7("\u2014 applies from the next session launch")}`
11936
12110
  );
11937
12111
  return;
11938
12112
  }
11939
- say6(`${green6("\u2713")} saved \xB7 the server cloned it once to check`);
11940
- say6(repositoryLine(result.repository));
11941
- say6(dim6("applies from the next session launch"));
12113
+ say7(`${green7("\u2713")} saved \xB7 the server cloned it once to check`);
12114
+ say7(repositoryLine(result.repository));
12115
+ say7(dim7("applies from the next session launch"));
11942
12116
  };
11943
12117
  var dotfilesSync = async (config, args) => {
11944
12118
  const all = args.includes("--all");
@@ -11947,36 +12121,36 @@ var dotfilesSync = async (config, args) => {
11947
12121
  if (!all && requestedPaths.length === 0) {
11948
12122
  const found = scanDotfileCandidates(home);
11949
12123
  if (found.length === 0) {
11950
- say6(dim6("no known config files found under ~"));
12124
+ say7(dim7("no known config files found under ~"));
11951
12125
  return;
11952
12126
  }
11953
12127
  let group = "";
11954
12128
  for (const entry of found) {
11955
12129
  if (entry.group !== group) {
11956
12130
  group = entry.group;
11957
- say6(dim6(group));
12131
+ say7(dim7(group));
11958
12132
  }
11959
- say6(` ${entry.path.padEnd(36)} ${dim6(formatDotfileBytes(entry.bytes))}`);
12133
+ say7(` ${entry.path.padEnd(36)} ${dim7(formatDotfileBytes(entry.bytes))}`);
11960
12134
  }
11961
- say6("");
11962
- say6(
12135
+ say7("");
12136
+ say7(
11963
12137
  `sync everything with ${cobalt2("mend dotfiles sync --all")}, or pick: ${cobalt2("mend dotfiles sync .zshrc .gitconfig")}`
11964
12138
  );
11965
12139
  return;
11966
12140
  }
11967
12141
  const selected = all ? scanDotfileCandidates(home).map((entry) => entry.path) : requestedPaths;
11968
- if (selected.length === 0) return fail6("nothing to sync \u2014 no known config files found under ~");
12142
+ if (selected.length === 0) return fail7("nothing to sync \u2014 no known config files found under ~");
11969
12143
  const read = readSyncFiles(home, selected);
11970
- if ("error" in read) return fail6(read.error);
12144
+ if ("error" in read) return fail7(read.error);
11971
12145
  const result = await api(config, "POST", "/dotfiles/snapshot", {
11972
12146
  files: read.files,
11973
12147
  source: os13.hostname(),
11974
12148
  merge: false
11975
12149
  });
11976
12150
  const snapshot = result.snapshot;
11977
- if (snapshot === null) return fail6("the server accepted the sync but reports no snapshot");
11978
- say6(
11979
- `${green6("synced")} ${snapshot.files.length} file${snapshot.files.length === 1 ? "" : "s"} from ${os13.hostname()} \xB7 ${dim6(snapshot.sha.slice(0, 7))} ${dim6("\u2014 applies from the next session launch")}`
12151
+ if (snapshot === null) return fail7("the server accepted the sync but reports no snapshot");
12152
+ say7(
12153
+ `${green7("synced")} ${snapshot.files.length} file${snapshot.files.length === 1 ? "" : "s"} from ${os13.hostname()} \xB7 ${dim7(snapshot.sha.slice(0, 7))} ${dim7("\u2014 applies from the next session launch")}`
11980
12154
  );
11981
12155
  };
11982
12156
  var envLoad = async (config, args) => {
@@ -11995,10 +12169,10 @@ var envLoad = async (config, args) => {
11995
12169
  try {
11996
12170
  contents = fs20.readFileSync(file, "utf8");
11997
12171
  } catch {
11998
- return fail6(`cannot read ${file} \u2014 pass a path: mend env load path/to/.env`);
12172
+ return fail7(`cannot read ${file} \u2014 pass a path: mend env load path/to/.env`);
11999
12173
  }
12000
12174
  if (contents.trim() === "") {
12001
- say6(dim6(`${file} is empty`));
12175
+ say7(dim7(`${file} is empty`));
12002
12176
  return;
12003
12177
  }
12004
12178
  const project2 = await findProject(config, explicitProject);
@@ -12009,30 +12183,30 @@ var envLoad = async (config, args) => {
12009
12183
  { contents, allSecret, secretNames }
12010
12184
  );
12011
12185
  if (report.loaded.length === 0 && report.rejected.length === 0 && report.malformedLines.length === 0) {
12012
- say6(dim6(`${path21.basename(file)} has no variables`));
12186
+ say7(dim7(`${path21.basename(file)} has no variables`));
12013
12187
  return;
12014
12188
  }
12015
- say6(`${green6("\u2713")} loaded ${path21.basename(file)} into ${project2.name}`);
12016
- for (const line of formatLoadReport(report, { dim: dim6, warn: amber2 })) say6(line);
12189
+ say7(`${green7("\u2713")} loaded ${path21.basename(file)} into ${project2.name}`);
12190
+ for (const line of formatLoadReport(report, { dim: dim7, warn: amber2 })) say7(line);
12017
12191
  const plaintextUrls = report.loaded.filter(
12018
12192
  (entry) => entry.lane === "configuration" && /_(URL|URI|DSN)$/.test(entry.name)
12019
12193
  );
12020
12194
  if (plaintextUrls.length > 0) {
12021
- say6(
12195
+ say7(
12022
12196
  amber2(
12023
12197
  ` ${plaintextUrls.map((entry) => entry.name).join(", ")} stored as plaintext configuration \u2014 if a value embeds a password, store it as a secret: mend env load --secret ${plaintextUrls.map((entry) => entry.name).join(",")}`
12024
12198
  )
12025
12199
  );
12026
12200
  }
12027
12201
  if (report.malformedLines.length > 0) {
12028
- say6(
12202
+ say7(
12029
12203
  amber2(
12030
12204
  ` skipped ${report.malformedLines.length} malformed line${report.malformedLines.length === 1 ? "" : "s"}: ${report.malformedLines.join(", ")}`
12031
12205
  )
12032
12206
  );
12033
12207
  }
12034
- say6(
12035
- dim6(
12208
+ say7(
12209
+ dim7(
12036
12210
  ` configuration r${report.environmentRevision} \xB7 secrets r${report.secretRevision} \u2014 applies from the next workspace launch, including resume; running workspaces keep what they started with`
12037
12211
  )
12038
12212
  );
@@ -12044,11 +12218,11 @@ var envShow = async (config, args) => {
12044
12218
  api(config, "GET", `/projects/${project2.id}/secrets`),
12045
12219
  api(config, "GET", `/projects/${project2.id}/cluster-bindings`)
12046
12220
  ]);
12047
- say6(
12048
- `${project2.name} ${dim6(`\xB7 configuration r${environment.revision} \xB7 secrets r${secrets.revision} \xB7 cluster r${cluster.revision}`)}`
12221
+ say7(
12222
+ `${project2.name} ${dim7(`\xB7 configuration r${environment.revision} \xB7 secrets r${secrets.revision} \xB7 cluster r${cluster.revision}`)}`
12049
12223
  );
12050
12224
  if (environment.variables.length === 0 && secrets.secrets.length === 0 && cluster.bindings.length === 0 && cluster.serviceAccount === null) {
12051
- say6(dim6(` nothing stored \u2014 load a file: ${cobalt2("mend env load")}`));
12225
+ say7(dim7(` nothing stored \u2014 load a file: ${cobalt2("mend env load")}`));
12052
12226
  return;
12053
12227
  }
12054
12228
  const bindingNames = cluster.bindings.map((b) => `${b.kind}/${b.objectName}`);
@@ -12059,23 +12233,23 @@ var envShow = async (config, args) => {
12059
12233
  ...bindingNames.map((name) => name.length)
12060
12234
  );
12061
12235
  for (const variable of environment.variables) {
12062
- say6(` ${variable.name.padEnd(width)} configuration ${dim6("\xB7 plaintext")}`);
12236
+ say7(` ${variable.name.padEnd(width)} configuration ${dim7("\xB7 plaintext")}`);
12063
12237
  }
12064
12238
  for (const secret of secrets.secrets) {
12065
- say6(` ${secret.name.padEnd(width)} secret ${dim6("\xB7 value set, never shown")}`);
12239
+ say7(` ${secret.name.padEnd(width)} secret ${dim7("\xB7 value set, never shown")}`);
12066
12240
  }
12067
12241
  for (const name of bindingNames) {
12068
- say6(
12069
- ` ${name.padEnd(width)} cluster binding ${dim6("\xB7 resolved by the platform at launch \xB7 contents unknown to Mend")}`
12242
+ say7(
12243
+ ` ${name.padEnd(width)} cluster binding ${dim7("\xB7 resolved by the platform at launch \xB7 contents unknown to Mend")}`
12070
12244
  );
12071
12245
  }
12072
12246
  if (cluster.serviceAccount !== null) {
12073
- say6(
12074
- ` ${cluster.serviceAccount.padEnd(width)} service account ${dim6("\xB7 workspace pod identity \xB7 allowlisted by the operator")}`
12247
+ say7(
12248
+ ` ${cluster.serviceAccount.padEnd(width)} service account ${dim7("\xB7 workspace pod identity \xB7 allowlisted by the operator")}`
12075
12249
  );
12076
12250
  }
12077
12251
  if (!cluster.clusterCapable && (cluster.bindings.length > 0 || cluster.serviceAccount !== null)) {
12078
- say6(
12252
+ say7(
12079
12253
  amber2(
12080
12254
  ` ${cluster.bindings.length} cluster binding${cluster.bindings.length === 1 ? "" : "s"}${cluster.serviceAccount === null ? "" : " \xB7 service account set"} \xB7 local runner \u2014 cluster bindings do not resolve here`
12081
12255
  )
@@ -12089,48 +12263,48 @@ var envCluster = async (config, args) => {
12089
12263
  const usage2 = usageOf("env cluster");
12090
12264
  const project2 = await findProject(config, explicitProject);
12091
12265
  const route = `/projects/${project2.id}/cluster-bindings`;
12092
- const appliesLine = () => say6(
12093
- dim6(
12266
+ const appliesLine = () => say7(
12267
+ dim7(
12094
12268
  " applies from the next workspace launch; running workspaces keep what they started with"
12095
12269
  )
12096
12270
  );
12097
12271
  if (verb === "add") {
12098
12272
  const [kind, objectName] = rest;
12099
12273
  if (kind !== "secret" && kind !== "configmap" || objectName === void 0) {
12100
- return fail6(`env cluster add takes a kind and an object name
12274
+ return fail7(`env cluster add takes a kind and an object name
12101
12275
  ${usage2}`);
12102
12276
  }
12103
12277
  const result = await api(config, "POST", route, {
12104
12278
  kind,
12105
12279
  objectName
12106
12280
  });
12107
- say6(`${green6("\u2713")} bound ${kind}/${objectName} ${dim6(`\xB7 cluster r${result.revision}`)}`);
12108
- say6(dim6(" resolved by the platform at launch \xB7 contents unknown to Mend"));
12281
+ say7(`${green7("\u2713")} bound ${kind}/${objectName} ${dim7(`\xB7 cluster r${result.revision}`)}`);
12282
+ say7(dim7(" resolved by the platform at launch \xB7 contents unknown to Mend"));
12109
12283
  return appliesLine();
12110
12284
  }
12111
12285
  if (verb === "remove") {
12112
12286
  const [ref] = rest;
12113
12287
  const [kind, objectName] = ref?.split("/", 2) ?? [];
12114
12288
  if (kind !== "secret" && kind !== "configmap" || objectName === void 0) {
12115
- return fail6(`env cluster remove takes <kind>/<name>, e.g. secret/app-env
12289
+ return fail7(`env cluster remove takes <kind>/<name>, e.g. secret/app-env
12116
12290
  ${usage2}`);
12117
12291
  }
12118
12292
  const snapshot = await api(config, "GET", route);
12119
12293
  const binding = snapshot.bindings.find((b) => b.kind === kind && b.objectName === objectName);
12120
- if (binding === void 0) return fail6(`${kind}/${objectName} is not bound on ${project2.name}`);
12294
+ if (binding === void 0) return fail7(`${kind}/${objectName} is not bound on ${project2.name}`);
12121
12295
  const result = await api(
12122
12296
  config,
12123
12297
  "DELETE",
12124
12298
  `${route}/${binding.id}`
12125
12299
  );
12126
- say6(`${green6("\u2713")} removed ${kind}/${objectName} ${dim6(`\xB7 cluster r${result.revision}`)}`);
12300
+ say7(`${green7("\u2713")} removed ${kind}/${objectName} ${dim7(`\xB7 cluster r${result.revision}`)}`);
12127
12301
  return appliesLine();
12128
12302
  }
12129
12303
  if (verb === "sa") {
12130
12304
  const clear = args.includes("--clear");
12131
12305
  const [name] = rest;
12132
12306
  if (!clear && name === void 0)
12133
- return fail6(`env cluster sa takes a name or --clear
12307
+ return fail7(`env cluster sa takes a name or --clear
12134
12308
  ${usage2}`);
12135
12309
  const result = await api(
12136
12310
  config,
@@ -12138,11 +12312,11 @@ ${usage2}`);
12138
12312
  `${route}/service-account`,
12139
12313
  { serviceAccount: clear ? null : name }
12140
12314
  );
12141
- say6(
12142
- result.serviceAccount === null ? `${green6("\u2713")} cleared the workspace service account ${dim6(`\xB7 cluster r${result.revision}`)}` : `${green6("\u2713")} service account ${result.serviceAccount} ${dim6(`\xB7 cluster r${result.revision}`)}`
12315
+ say7(
12316
+ result.serviceAccount === null ? `${green7("\u2713")} cleared the workspace service account ${dim7(`\xB7 cluster r${result.revision}`)}` : `${green7("\u2713")} service account ${result.serviceAccount} ${dim7(`\xB7 cluster r${result.revision}`)}`
12143
12317
  );
12144
12318
  if (result.serviceAccount !== null) {
12145
- say6(
12319
+ say7(
12146
12320
  amber2(
12147
12321
  " the session agent holds this role's full permissions for the whole session \u2014 bind a least-privilege role intended for untrusted code; names outside the platform allowlist fail the launch"
12148
12322
  )
@@ -12150,7 +12324,7 @@ ${usage2}`);
12150
12324
  }
12151
12325
  return appliesLine();
12152
12326
  }
12153
- return fail6(`unknown env cluster command "${verb ?? ""}"
12327
+ return fail7(`unknown env cluster command "${verb ?? ""}"
12154
12328
  ${usage2}`);
12155
12329
  };
12156
12330
  var envCommand = async (config, args) => {
@@ -12164,7 +12338,7 @@ var envCommand = async (config, args) => {
12164
12338
  case void 0:
12165
12339
  return envShow(config, rest);
12166
12340
  default:
12167
- return fail6(`unknown env command "${verb}" \xB7 mend help env lists them`);
12341
+ return fail7(`unknown env command "${verb}" \xB7 mend help env lists them`);
12168
12342
  }
12169
12343
  };
12170
12344
  var dotfilesCommand = async (config, args) => {
@@ -12178,7 +12352,7 @@ var dotfilesCommand = async (config, args) => {
12178
12352
  case void 0:
12179
12353
  return dotfilesShow(config);
12180
12354
  default:
12181
- return fail6(`unknown dotfiles command "${verb}" \xB7 mend help dotfiles lists them`);
12355
+ return fail7(`unknown dotfiles command "${verb}" \xB7 mend help dotfiles lists them`);
12182
12356
  }
12183
12357
  };
12184
12358
  var skillsList = async (config, args) => {
@@ -12191,23 +12365,23 @@ var skillsList = async (config, args) => {
12191
12365
  );
12192
12366
  const library = project2 === null ? "your library" : project2.name;
12193
12367
  if (skills.length === 0) {
12194
- say6(dim6(`no skills in ${library} \u2014 push a local one: mend skills push`));
12368
+ say7(dim7(`no skills in ${library} \u2014 push a local one: mend skills push`));
12195
12369
  return;
12196
12370
  }
12197
12371
  for (const skill of skills) {
12198
- say6(
12199
- ` ${skill.name.padEnd(28)} ${dim6(`${skill.fileCount} file${skill.fileCount === 1 ? "" : "s"} \xB7 ${formatDotfileBytes(skill.bytes)}`)}`
12372
+ say7(
12373
+ ` ${skill.name.padEnd(28)} ${dim7(`${skill.fileCount} file${skill.fileCount === 1 ? "" : "s"} \xB7 ${formatDotfileBytes(skill.bytes)}`)}`
12200
12374
  );
12201
- if (skill.description !== "") say6(` ${dim6(skill.description)}`);
12375
+ if (skill.description !== "") say7(` ${dim7(skill.description)}`);
12202
12376
  }
12203
12377
  };
12204
12378
  var skillsPush = async (config, args) => {
12205
12379
  const dirFlag = takeFlagValue4(args, "--dir");
12206
12380
  const root = dirFlag === null ? path21.join(os13.homedir(), DEFAULT_SKILLS_DIR) : path21.resolve(dirFlag);
12207
12381
  const scanned = scanSkillLibrary(root);
12208
- if ("error" in scanned) return fail6(scanned.error);
12209
- for (const note of scanned.notes) say6(dim6(` ${note.skill}: ${note.message}`));
12210
- if (scanned.skills.length === 0) return fail6(`no skills found under ${root}`);
12382
+ if ("error" in scanned) return fail7(scanned.error);
12383
+ for (const note of scanned.notes) say7(dim7(` ${note.skill}: ${note.message}`));
12384
+ if (scanned.skills.length === 0) return fail7(`no skills found under ${root}`);
12211
12385
  const forProject = args.includes("--project");
12212
12386
  const project2 = forProject ? await findProject(config, takeFlagValue4(args, "--project")) : null;
12213
12387
  const report = await api(config, "POST", "/skills/sync", {
@@ -12227,10 +12401,10 @@ var skillsPush = async (config, args) => {
12227
12401
  `${report.unchanged.length} unchanged`,
12228
12402
  ...report.removed.length > 0 ? [`${report.removed.length} removed`] : []
12229
12403
  ].join(" \xB7 ");
12230
- say6(
12231
- `${green6("pushed")} ${scanned.skills.length} skill${scanned.skills.length === 1 ? "" : "s"} from ${root} to ${library} \xB7 ${dim6(counts)}`
12404
+ say7(
12405
+ `${green7("pushed")} ${scanned.skills.length} skill${scanned.skills.length === 1 ? "" : "s"} from ${root} to ${library} \xB7 ${dim7(counts)}`
12232
12406
  );
12233
- say6(dim6("sessions receive them from the next launch"));
12407
+ say7(dim7("sessions receive them from the next launch"));
12234
12408
  };
12235
12409
  var skillsCommand = async (config, args) => {
12236
12410
  const [verb, ...rest] = args;
@@ -12243,7 +12417,7 @@ var skillsCommand = async (config, args) => {
12243
12417
  return skillsList(config, args);
12244
12418
  default:
12245
12419
  if (verb.startsWith("--")) return skillsList(config, args);
12246
- return fail6(`unknown skills command "${verb}" \xB7 mend help skills lists them`);
12420
+ return fail7(`unknown skills command "${verb}" \xB7 mend help skills lists them`);
12247
12421
  }
12248
12422
  };
12249
12423
  var completeCommand = async (config, args) => {
@@ -12351,7 +12525,7 @@ var completionsCommand = (args) => {
12351
12525
  process.stdout.write(BASH_COMPLETIONS);
12352
12526
  return;
12353
12527
  default:
12354
- return fail6(`${usageOf("completions")} \xB7 e.g. mend completions zsh > "$fpath[1]/_mend"`);
12528
+ return fail7(`${usageOf("completions")} \xB7 e.g. mend completions zsh > "$fpath[1]/_mend"`);
12355
12529
  }
12356
12530
  };
12357
12531
  var supervisedRun = async (config, session, argv) => {
@@ -12361,15 +12535,15 @@ var supervisedRun = async (config, session, argv) => {
12361
12535
  "provisioning workspace \u2014 a first launch builds the harness image (can take minutes)\u2026",
12362
12536
  request(config, "POST", `/sessions/${session.id}/launch`, { argv })
12363
12537
  );
12364
- say6(
12365
- `${green6("\u2713 recording")} \xB7 run ${dim6(launched.id.slice(0, 8))} \xB7 workspace mounts the worktree`
12538
+ say7(
12539
+ `${green7("\u2713 recording")} \xB7 run ${dim7(launched.id.slice(0, 8))} \xB7 workspace mounts the worktree`
12366
12540
  );
12367
- say6(dim6(` ${argv.join(" ")} \u2014 live record:`));
12368
- say6("");
12541
+ say7(dim7(` ${argv.join(" ")} \u2014 live record:`));
12542
+ say7("");
12369
12543
  const headers = {};
12370
12544
  if (config.token !== null) headers["authorization"] = `Bearer ${config.token}`;
12371
12545
  const response = await fetch(`${config.url}/api/events`, { headers });
12372
- if (response.body === null) return fail6("event stream unavailable");
12546
+ if (response.body === null) return fail7("event stream unavailable");
12373
12547
  const reader = response.body.getReader();
12374
12548
  const decoder = new TextDecoder();
12375
12549
  let buffer = "";
@@ -12391,7 +12565,7 @@ var supervisedRun = async (config, session, argv) => {
12391
12565
  }
12392
12566
  if (event.sessionId !== session.id) continue;
12393
12567
  if (event.type === "session-progress" && event.line !== void 0) {
12394
- say6(dim6(` ${event.line}`));
12568
+ say7(dim7(` ${event.line}`));
12395
12569
  }
12396
12570
  if (event.type === "session") {
12397
12571
  const detail = await api(config, "GET", `/sessions/${session.id}`);
@@ -12401,9 +12575,9 @@ var supervisedRun = async (config, session, argv) => {
12401
12575
  }
12402
12576
  }
12403
12577
  await reader.cancel().catch(() => void 0);
12404
- say6("");
12405
- say6(`${green6("\u2713")} session ${settled ?? "settled"} \xB7 recorded \xB7 checkpoint taken`);
12406
- say6(`${cobalt2(" review")} \xB7 ${config.url}/sessions/${session.id}`);
12578
+ say7("");
12579
+ say7(`${green7("\u2713")} session ${settled ?? "settled"} \xB7 recorded \xB7 checkpoint taken`);
12580
+ say7(`${cobalt2(" review")} \xB7 ${config.url}/sessions/${session.id}`);
12407
12581
  process.exit(settled === "failed" ? 1 : 0);
12408
12582
  };
12409
12583
  var continueSession = async (config, args) => {
@@ -12426,20 +12600,20 @@ var continueSession = async (config, args) => {
12426
12600
  }
12427
12601
  }
12428
12602
  if (sessionId === null || followUp === null) {
12429
- return fail6("no session with a pending follow-up \u2014 send one from the review first");
12603
+ return fail7("no session with a pending follow-up \u2014 send one from the review first");
12430
12604
  }
12431
12605
  } else {
12432
12606
  followUp = await api(config, "GET", `/sessions/${sessionId}/follow-up`);
12433
- if (followUp === null) return fail6(`session ${sessionId} has no pending follow-up`);
12607
+ if (followUp === null) return fail7(`session ${sessionId} has no pending follow-up`);
12434
12608
  }
12435
12609
  const detail = await api(config, "GET", `/sessions/${sessionId}`);
12436
12610
  const session = detail.session;
12437
- say6(`${green6("\u2713")} follow-up for session ${dim6(session.id.slice(0, 8))} \xB7 ${session.branch}`);
12438
- say6(dim6(" instruction:"));
12439
- for (const line of followUp.instruction.split("\n").slice(0, 6)) say6(dim6(` \u2502 ${line}`));
12440
- if (followUp.instruction.split("\n").length > 6) say6(dim6(" \u2502 \u2026"));
12611
+ say7(`${green7("\u2713")} follow-up for session ${dim7(session.id.slice(0, 8))} \xB7 ${session.branch}`);
12612
+ say7(dim7(" instruction:"));
12613
+ for (const line of followUp.instruction.split("\n").slice(0, 6)) say7(dim7(` \u2502 ${line}`));
12614
+ if (followUp.instruction.split("\n").length > 6) say7(dim7(" \u2502 \u2026"));
12441
12615
  if (followUp.reviewSliceId === null || followUp.checkpointAId === null || followUp.checkpointBId === null || followUp.diffDigest === null || followUp.idempotencyKey === null) {
12442
- return fail6("legacy follow-up \u2014 recreate it from a pinned Review before delivery");
12616
+ return fail7("legacy follow-up \u2014 recreate it from a pinned Review before delivery");
12443
12617
  }
12444
12618
  const delivered = await withSpinner(
12445
12619
  "delivering persisted Review bundle \u2014 retries reconcile one process\u2026",
@@ -12454,16 +12628,16 @@ var continueSession = async (config, args) => {
12454
12628
  })
12455
12629
  );
12456
12630
  if (delivered.status === "pending") {
12457
- return fail6("the session is active \u2014 the follow-up remains pending");
12631
+ return fail7("the session is active \u2014 the follow-up remains pending");
12458
12632
  }
12459
12633
  if (delivered.status === "delivery_failed") {
12460
- return fail6(delivered.deliveryError ?? "delivery failed before process membership finalized");
12634
+ return fail7(delivered.deliveryError ?? "delivery failed before process membership finalized");
12461
12635
  }
12462
- say6(
12463
- `${green6("\u2713 recording")} \xB7 delivered to run ${delivered.deliverySealantRunId ?? "unknown"}${detachHint()}`
12636
+ say7(
12637
+ `${green7("\u2713 recording")} \xB7 delivered to run ${delivered.deliverySealantRunId ?? "unknown"}${detachHint()}`
12464
12638
  );
12465
- say6(`${cobalt2(" watch")} \xB7 ${config.url}/sessions/${session.id}`);
12466
- say6("");
12639
+ say7(`${cobalt2(" watch")} \xB7 ${config.url}/sessions/${session.id}`);
12640
+ say7("");
12467
12641
  await attachOrExit(config, session.id, session.harness);
12468
12642
  exitAfterSessionEnd(config, session.id);
12469
12643
  };
@@ -12480,19 +12654,19 @@ var resumeCommand = async (config, args) => {
12480
12654
  const detail = await api(config, "GET", `/projects/${project2.id}`);
12481
12655
  const match = prefix === void 0 ? detail.sessions.find((s) => !agentLiveIn(detail, s)) : detail.sessions.find((s) => s.id.startsWith(prefix));
12482
12656
  if (match === void 0) {
12483
- return fail6(
12657
+ return fail7(
12484
12658
  prefix === void 0 ? "no settled session to resume \u2014 mend status lists sessions" : `no session matches "${prefix}"`
12485
12659
  );
12486
12660
  }
12487
12661
  if (agentLiveIn(detail, match)) {
12488
- return fail6(
12662
+ return fail7(
12489
12663
  `session ${match.id.slice(0, 8)} is live \u2014 attach: mend attach ${match.id.slice(0, 8)}`
12490
12664
  );
12491
12665
  }
12492
- say6(
12493
- `${green6("\u2713")} resuming ${match.harness} \xB7 ${dim6(match.id.slice(0, 8))}${withHarness === null ? "" : ` ${dim6("as")} ${withHarness}`}`
12666
+ say7(
12667
+ `${green7("\u2713")} resuming ${match.harness} \xB7 ${dim7(match.id.slice(0, 8))}${withHarness === null ? "" : ` ${dim7("as")} ${withHarness}`}`
12494
12668
  );
12495
- say6(`${cobalt2(" watch")} \xB7 ${config.url}/sessions/${match.id}`);
12669
+ say7(`${cobalt2(" watch")} \xB7 ${config.url}/sessions/${match.id}`);
12496
12670
  const priorAgent = detail.annotations.find((annotation) => annotation.sessionId === match.id)?.currentAgent ?? null;
12497
12671
  const protocolPrior = priorAgent?.kind === "agent-protocol" && withHarness === null;
12498
12672
  await startAndFollow(
@@ -12503,8 +12677,8 @@ var resumeCommand = async (config, args) => {
12503
12677
  harness: withHarness
12504
12678
  })
12505
12679
  );
12506
- say6(`${green6("\u2713 recording")} \xB7 same worktree, conversation restored${detachHint()}`);
12507
- say6("");
12680
+ say7(`${green7("\u2713 recording")} \xB7 same worktree, conversation restored${detachHint()}`);
12681
+ say7("");
12508
12682
  await attachOrExit(config, match.id, withHarness ?? match.harness);
12509
12683
  exitAfterSessionEnd(config, match.id);
12510
12684
  };
@@ -12534,20 +12708,20 @@ var rejoinCommand = async (config, args) => {
12534
12708
  const matches = prefix === void 0 ? newest === void 0 ? [] : [newest] : eligible.filter((session2) => session2.id.startsWith(prefix));
12535
12709
  if (matches.length === 0) {
12536
12710
  const harnessDescription = harness === null ? "" : ` ${harness}`;
12537
- return fail6(
12711
+ return fail7(
12538
12712
  prefix === void 0 ? `no${harnessDescription} session to rejoin in project ${project2.name}` : `no${harnessDescription} session matches "${prefix}" in project ${project2.name}`
12539
12713
  );
12540
12714
  }
12541
12715
  if (matches.length > 1) {
12542
- return fail6(`session prefix "${prefix}" is ambiguous \u2014 use more of the id`);
12716
+ return fail7(`session prefix "${prefix}" is ambiguous \u2014 use more of the id`);
12543
12717
  }
12544
12718
  const session = matches[0];
12545
- if (session === void 0) return fail6("session selection failed");
12719
+ if (session === void 0) return fail7("session selection failed");
12546
12720
  const alreadyLive = agentLiveIn(detail, session);
12547
- say6(
12548
- `${green6("\u2713")} rejoining ${sessionDisplayName(session)} \xB7 ${session.harness} ${dim6(session.id.slice(0, 8))} \xB7 ${alreadyLive ? "already live" : "restoring"}`
12721
+ say7(
12722
+ `${green7("\u2713")} rejoining ${sessionDisplayName(session)} \xB7 ${session.harness} ${dim7(session.id.slice(0, 8))} \xB7 ${alreadyLive ? "already live" : "restoring"}`
12549
12723
  );
12550
- say6(`${cobalt2(" watch")} \xB7 ${config.url}/sessions/${session.id}`);
12724
+ say7(`${cobalt2(" watch")} \xB7 ${config.url}/sessions/${session.id}`);
12551
12725
  let restored = false;
12552
12726
  const currentAgent = detail.annotations.find((annotation) => annotation.sessionId === session.id)?.currentAgent ?? null;
12553
12727
  if (currentAgent?.kind === "agent-protocol") {
@@ -12565,11 +12739,11 @@ var rejoinCommand = async (config, args) => {
12565
12739
  "resuming \u2014 a fresh workspace restores the saved session state\u2026"
12566
12740
  );
12567
12741
  }
12568
- say6(
12569
- restored ? `${green6("\u2713 recording")} \xB7 same worktree, conversation restored${detachHint()}` : `${green6("\u2713 recording")} \xB7 attached to the live session${detachHint()}`
12742
+ say7(
12743
+ restored ? `${green7("\u2713 recording")} \xB7 same worktree, conversation restored${detachHint()}` : `${green7("\u2713 recording")} \xB7 attached to the live session${detachHint()}`
12570
12744
  );
12571
12745
  await tunnels?.start(session.id);
12572
- say6("");
12746
+ say7("");
12573
12747
  let outcome = await attachWithTunnels(
12574
12748
  tunnels,
12575
12749
  () => attachTty(config, session.id, session.harness, 0n, void 0, {
@@ -12601,7 +12775,7 @@ var projectsCommand = async (config) => {
12601
12775
  api(config, "GET", "/sessions")
12602
12776
  ]);
12603
12777
  if (projects.length === 0) {
12604
- say6(dim6("no adopted projects \u2014 mend adopt brings one in"));
12778
+ say7(dim7("no adopted projects \u2014 mend adopt brings one in"));
12605
12779
  return;
12606
12780
  }
12607
12781
  const liveByProject = /* @__PURE__ */ new Map();
@@ -12613,13 +12787,13 @@ var projectsCommand = async (config) => {
12613
12787
  const here = matchProjectByCwd(projects, cwdFacts(process.cwd()));
12614
12788
  for (const project2 of projects) {
12615
12789
  const live = liveByProject.get(project2.id) ?? 0;
12616
- const liveLabel = live > 0 ? green6(`${live} live`) : dim6("\u2014");
12790
+ const liveLabel = live > 0 ? green7(`${live} live`) : dim7("\u2014");
12617
12791
  const marker = project2.id === here?.id ? cobalt2("\u25B8 ") : " ";
12618
- say6(
12619
- `${marker}${project2.name.padEnd(nameWidth)} ${dim6(project2.defaultBranch.padEnd(branchWidth))} ${liveLabel} ${dim6(project2.storePath)}`
12792
+ say7(
12793
+ `${marker}${project2.name.padEnd(nameWidth)} ${dim7(project2.defaultBranch.padEnd(branchWidth))} ${liveLabel} ${dim7(project2.storePath)}`
12620
12794
  );
12621
12795
  }
12622
- if (here !== void 0) say6(dim6(` \u25B8 ${here.name} is the cwd's project`));
12796
+ if (here !== void 0) say7(dim7(` \u25B8 ${here.name} is the cwd's project`));
12623
12797
  };
12624
12798
  var refreshCommand = async (config, args) => {
12625
12799
  const explicit = args.find((a) => !a.startsWith("--")) ?? takeFlagValue4(args, "--project");
@@ -12629,20 +12803,20 @@ var refreshCommand = async (config, args) => {
12629
12803
  "POST",
12630
12804
  `/projects/${project2.id}/refresh`
12631
12805
  );
12632
- say6(`${green6("\u2713")} refreshed ${project2.name} ${dim6(`\xB7 ${branches.length} branches`)}`);
12806
+ say7(`${green7("\u2713")} refreshed ${project2.name} ${dim7(`\xB7 ${branches.length} branches`)}`);
12633
12807
  for (const branch of branches.slice(0, 12)) {
12634
12808
  const marker = branch.isDefault ? cobalt2("\u25B8 ") : " ";
12635
- say6(
12636
- `${marker}${branch.name} ${dim6(branch.sha.slice(0, 12))} ${dim6(branch.committedAt.slice(0, 10))}`
12809
+ say7(
12810
+ `${marker}${branch.name} ${dim7(branch.sha.slice(0, 12))} ${dim7(branch.committedAt.slice(0, 10))}`
12637
12811
  );
12638
12812
  }
12639
- if (branches.length > 12) say6(dim6(` \u2026 ${branches.length - 12} more`));
12813
+ if (branches.length > 12) say7(dim7(` \u2026 ${branches.length - 12} more`));
12640
12814
  };
12641
12815
  var rowHold = (row) => (
12642
12816
  // A workspace a stop is still saving (docs/adr/0002) reads what is left, first.
12643
12817
  captureLineOf(row.session) ?? (row.annotation === void 0 ? null : servicesHoldOf(row.session, row.annotation.currentAgent, row.annotation.liveServices ?? 0))
12644
12818
  );
12645
- var printSessionRow = (row) => {
12819
+ var printSessionRow = (row, workspaceLines = []) => {
12646
12820
  const { session, annotation } = row;
12647
12821
  const live = ACTIVE_STATUSES.has(session.status);
12648
12822
  const status = session.status.padEnd(9);
@@ -12657,9 +12831,10 @@ var printSessionRow = (row) => {
12657
12831
  facts.push(amber2("follow-up pending"));
12658
12832
  const base = session.baseRef === null ? session.baseSha.slice(0, 12) : session.baseRef;
12659
12833
  const model = session.model === null || session.model === void 0 ? "" : ` \xB7 ${session.model}${session.effort === null || session.effort === void 0 ? "" : ` \xB7 ${session.effort}`}`;
12660
- say6(
12661
- `${session.harness.padEnd(8)} ${dim6(session.id.slice(0, 8))} ${live ? green6(status) : dim6(status)} ${row.projectName} ${dim6(`${session.branch} \xB7 base ${base}${model}`)}${facts.length > 0 ? ` ${facts.join(dim6(" \xB7 "))}` : ""}`
12834
+ say7(
12835
+ `${session.harness.padEnd(8)} ${dim7(session.id.slice(0, 8))} ${live ? green7(status) : dim7(status)} ${row.projectName} ${dim7(`${session.branch} \xB7 base ${base}${model}`)}${facts.length > 0 ? ` ${facts.join(dim7(" \xB7 "))}` : ""}`
12662
12836
  );
12837
+ for (const line of workspaceLines) say7(` ${dim7(line)}`);
12663
12838
  };
12664
12839
  var modelsCommand = async (config, args) => {
12665
12840
  const catalogs = await api(
@@ -12667,15 +12842,15 @@ var modelsCommand = async (config, args) => {
12667
12842
  "GET",
12668
12843
  "/harnesses/models"
12669
12844
  );
12670
- if (args.includes("--json")) return say6(modelCatalogJson(catalogs));
12671
- for (const line of modelCatalogLines(catalogs, dim6)) say6(line);
12845
+ if (args.includes("--json")) return say7(modelCatalogJson(catalogs));
12846
+ for (const line of modelCatalogLines(catalogs, dim7)) say7(line);
12672
12847
  };
12673
12848
  var sessionsCommand = async (config, args) => {
12674
12849
  const all = args.includes("--all");
12675
12850
  if (args.includes("--json=v2")) {
12676
12851
  const projectFlag2 = args.indexOf("--project");
12677
12852
  const projectName2 = projectFlag2 !== -1 && args[projectFlag2 + 1] !== void 0 ? String(args[projectFlag2 + 1]) : null;
12678
- say6(JSON.stringify(await buildWorktreesJson(config, projectName2), null, 2));
12853
+ say7(JSON.stringify(await buildWorktreesJson(config, projectName2), null, 2));
12679
12854
  return;
12680
12855
  }
12681
12856
  const json2 = args.includes("--json");
@@ -12684,7 +12859,7 @@ var sessionsCommand = async (config, args) => {
12684
12859
  const projects = await api(config, "GET", "/projects");
12685
12860
  const scope = projectName === null ? projects : projects.filter((p) => p.name === projectName);
12686
12861
  if (projectName !== null && scope.length === 0) {
12687
- return fail6(`no adopted project named "${projectName}"`);
12862
+ return fail7(`no adopted project named "${projectName}"`);
12688
12863
  }
12689
12864
  let rows;
12690
12865
  if (all || projectName !== null || !json2) {
@@ -12714,11 +12889,11 @@ var sessionsCommand = async (config, args) => {
12714
12889
  }
12715
12890
  if (rows.length === 0) {
12716
12891
  if (json2) {
12717
- say6(JSON.stringify({ version: 1, sessions: [] }, null, 2));
12892
+ say7(JSON.stringify({ version: 1, sessions: [] }, null, 2));
12718
12893
  return;
12719
12894
  }
12720
- say6(
12721
- dim6(all ? "no sessions" : "no active sessions \u2014 mend sessions --all includes settled ones")
12895
+ say7(
12896
+ dim7(all ? "no sessions" : "no active sessions \u2014 mend sessions --all includes settled ones")
12722
12897
  );
12723
12898
  return;
12724
12899
  }
@@ -12760,10 +12935,14 @@ var sessionsCommand = async (config, args) => {
12760
12935
  }
12761
12936
  }))
12762
12937
  };
12763
- say6(JSON.stringify(payload, null, 2));
12938
+ say7(JSON.stringify(payload, null, 2));
12764
12939
  return;
12765
12940
  }
12766
- for (const row of rows) printSessionRow(row);
12941
+ const workspaceLines = await workspaceLinesOf(
12942
+ config,
12943
+ rows.map((row) => row.session)
12944
+ );
12945
+ for (const row of rows) printSessionRow(row, workspaceLines.get(row.session.id));
12767
12946
  };
12768
12947
  var toWorktreeJsonSession = (session) => ({
12769
12948
  id: session.id,
@@ -12841,8 +13020,8 @@ var worktreesCommand = async (config, args) => {
12841
13020
  request: (method, route, body) => request(config, method, route, body),
12842
13021
  listWorktrees: async (project2) => (await buildWorktreesJson(config, project2)).worktrees,
12843
13022
  liveStatuses: ACTIVE_STATUSES,
12844
- say: say6,
12845
- fail: fail6
13023
+ say: say7,
13024
+ fail: fail7
12846
13025
  },
12847
13026
  args.slice(1)
12848
13027
  );
@@ -12852,11 +13031,11 @@ var worktreesCommand = async (config, args) => {
12852
13031
  const projectName = projectFlag !== -1 && args[projectFlag + 1] !== void 0 ? String(args[projectFlag + 1]) : null;
12853
13032
  const payload = await buildWorktreesJson(config, projectName);
12854
13033
  if (json2) {
12855
- say6(JSON.stringify(payload, null, 2));
13034
+ say7(JSON.stringify(payload, null, 2));
12856
13035
  return;
12857
13036
  }
12858
13037
  if (payload.worktrees.length === 0) {
12859
- say6(dim6("no worktrees yet \u2014 mend claude --name <worktree> starts one"));
13038
+ say7(dim7("no worktrees yet \u2014 mend claude --name <worktree> starts one"));
12860
13039
  return;
12861
13040
  }
12862
13041
  for (const worktree of payload.worktrees) {
@@ -12864,19 +13043,19 @@ var worktreesCommand = async (config, args) => {
12864
13043
  const facts = [
12865
13044
  `${worktree.sessions.length} session${worktree.sessions.length === 1 ? "" : "s"}`
12866
13045
  ];
12867
- if (live > 0) facts.push(green6(`${live} live`));
13046
+ if (live > 0) facts.push(green7(`${live} live`));
12868
13047
  if (worktree.review !== null && worktree.review.openComments > 0) {
12869
13048
  facts.push(amber2(`${worktree.review.openComments} open`));
12870
13049
  }
12871
13050
  const base = worktree.baseRef ?? worktree.baseSha.slice(0, 12);
12872
- say6(
12873
- `${worktree.name.padEnd(24)} ${worktree.projectName} ${dim6(`${worktree.branch} \xB7 base ${base}`)} ${facts.join(dim6(" \xB7 "))}`
13051
+ say7(
13052
+ `${worktree.name.padEnd(24)} ${worktree.projectName} ${dim7(`${worktree.branch} \xB7 base ${base}`)} ${facts.join(dim7(" \xB7 "))}`
12874
13053
  );
12875
13054
  for (const session of worktree.sessions) {
12876
13055
  const status = session.status.padEnd(9);
12877
13056
  const name = session.label ?? `session ${session.id.slice(0, 8)}`;
12878
- say6(
12879
- ` \u2514 ${session.harness.padEnd(8)} ${dim6(session.id.slice(0, 8))} ${ACTIVE_STATUSES.has(session.status) ? green6(status) : dim6(status)} ${name}`
13057
+ say7(
13058
+ ` \u2514 ${session.harness.padEnd(8)} ${dim7(session.id.slice(0, 8))} ${ACTIVE_STATUSES.has(session.status) ? green7(status) : dim7(status)} ${name}`
12880
13059
  );
12881
13060
  }
12882
13061
  }
@@ -12891,13 +13070,13 @@ var hasNodeFfi = () => {
12891
13070
  };
12892
13071
  var dashboard = async (config, options = {}) => {
12893
13072
  if (process.stdout.isTTY !== true) {
12894
- say6(renderIndex());
13073
+ say7(renderIndex());
12895
13074
  return;
12896
13075
  }
12897
13076
  if (!hasNodeFfi()) {
12898
13077
  const major = Number(process.versions.node.split(".")[0]);
12899
13078
  if (Number.isNaN(major) || major < 26) {
12900
- return fail6(
13079
+ return fail7(
12901
13080
  `the dashboard needs Node >= 26 (node:ffi) \u2014 this is ${process.version}; every other command still works`
12902
13081
  );
12903
13082
  }
@@ -12908,7 +13087,7 @@ var dashboard = async (config, options = {}) => {
12908
13087
  );
12909
13088
  process.exit(rerun.status ?? 0);
12910
13089
  }
12911
- const { runDashboard } = await import("./dashboard-2HF3KTTU.js");
13090
+ const { runDashboard } = await import("./dashboard-4J2WMT3G.js");
12912
13091
  const agentShare = await startShareIfBridge(config);
12913
13092
  const tunnels = options.noTunnel === true || serverIsLocal(config) ? null : createServiceTunnels({
12914
13093
  listServices: () => fetchServices(config),
@@ -12956,29 +13135,29 @@ var withAgentShare = async (config, work) => {
12956
13135
  };
12957
13136
  var helpCommand = (words) => {
12958
13137
  if (words.length === 0) {
12959
- say6(renderIndex());
13138
+ say7(renderIndex());
12960
13139
  return;
12961
13140
  }
12962
13141
  const doc = findCommand(words);
12963
13142
  if (doc !== null && (doc.name.split(" ").length > 1 || words.length === 1)) {
12964
- say6(renderCommand(doc));
13143
+ say7(renderCommand(doc));
12965
13144
  return;
12966
13145
  }
12967
13146
  const group = renderGroup(words[0] ?? "");
12968
13147
  if (doc !== null) {
12969
- say6(renderCommand(doc));
13148
+ say7(renderCommand(doc));
12970
13149
  return;
12971
13150
  }
12972
13151
  if (group !== null) {
12973
- say6(group);
13152
+ say7(group);
12974
13153
  return;
12975
13154
  }
12976
- return fail6(`no command "${words.join(" ")}" \xB7 mend help lists them`);
13155
+ return fail7(`no command "${words.join(" ")}" \xB7 mend help lists them`);
12977
13156
  };
12978
13157
  var manCommand = (words) => {
12979
13158
  const doc = words.length === 0 ? null : findCommand(words);
12980
13159
  if (words.length > 0 && doc === null) {
12981
- return fail6(`no command "${words.join(" ")}" \xB7 mend help lists them`);
13160
+ return fail7(`no command "${words.join(" ")}" \xB7 mend help lists them`);
12982
13161
  }
12983
13162
  const version = cliVersion();
12984
13163
  const page = doc === null ? renderManIndex(version) : renderManPage(doc, version);
@@ -12987,7 +13166,7 @@ var manCommand = (words) => {
12987
13166
  const result = spawnSync6("man", ["-l", file], { stdio: "inherit" });
12988
13167
  fs20.rmSync(file, { force: true });
12989
13168
  if (result.error !== void 0 || result.status !== 0) {
12990
- say6(doc === null ? renderIndex() : renderCommand(doc));
13169
+ say7(doc === null ? renderIndex() : renderCommand(doc));
12991
13170
  }
12992
13171
  };
12993
13172
  var main = async () => {
@@ -12999,7 +13178,7 @@ var main = async () => {
12999
13178
  }
13000
13179
  if (command === "server") {
13001
13180
  const result = await serverCommand(rest);
13002
- if (result._tag === "error") return fail6(result.message);
13181
+ if (result._tag === "error") return fail7(result.message);
13003
13182
  return;
13004
13183
  }
13005
13184
  const config = loadConfig();
@@ -13059,7 +13238,13 @@ var main = async () => {
13059
13238
  );
13060
13239
  case "session":
13061
13240
  if (rest[0] === "share") return sessionShareCommand(boundApi(config), rest.slice(1));
13062
- return fail6(`unknown session command "${rest[0] ?? ""}" \xB7 mend help session share`);
13241
+ return fail7(`unknown session command "${rest[0] ?? ""}" \xB7 mend help session share`);
13242
+ case "workspace":
13243
+ return workspaceCommand(
13244
+ boundApi(config),
13245
+ (method, route, body) => request(config, method, route, body),
13246
+ rest
13247
+ );
13063
13248
  // Hidden in the catalog: the installer renders its own QR through this.
13064
13249
  case "qr":
13065
13250
  return qrCommand(rest);
@@ -13110,10 +13295,10 @@ var main = async () => {
13110
13295
  case "--version":
13111
13296
  case "-v":
13112
13297
  for (const line of versionLines(cliVersion(), await fetchServerVersion(config.url)))
13113
- say6(line);
13298
+ say7(line);
13114
13299
  return;
13115
13300
  default:
13116
- return fail6(`unknown command "${command}" \xB7 mend help lists them`);
13301
+ return fail7(`unknown command "${command}" \xB7 mend help lists them`);
13117
13302
  }
13118
13303
  };
13119
13304
  await main();