@sealant/mend 0.36.0-next.632 → 0.36.0-next.645

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-OHOMU7JP.js → chunk-ASHAV3UV.js} +334 -3
  3. package/dist/{dashboard-34ZANJ24.js → dashboard-4J2WMT3G.js} +142 -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/README.md CHANGED
@@ -171,6 +171,8 @@ mend refresh [project] fetch origin's branches into the store
171
171
  mend land <session> [--branch b] [--no-pr] [--title t] | --check
172
172
  push the change to origin, open or update its pull request
173
173
  mend pull <session> [--force] fetch the change into this clone as mend/<name>
174
+ mend workspace replace <session> [--yes]
175
+ replace a workspace that started before Mend 0.36
174
176
 
175
177
  services
176
178
  mend service run|add|connect|list|logs|restart|stop|init
@@ -193,7 +195,8 @@ mend members who belongs to your organization, and thei
193
195
  mend invite [--role member|owner] [--email <address>] [--days <n>]
194
196
  print a one-time invitation link
195
197
  mend folder list|create|push|rm your organization's folders
196
- mend session share <session> on|off shared control: let everyone who can see a session steer it
198
+ mend session share <session> on|off [--yes]
199
+ shared control: each turn runs on its sender's login
197
200
 
198
201
  this machine
199
202
  mend operator org list|create|rename|invite-owner
@@ -26965,13 +26965,17 @@ var sameGrant = (left, right) => {
26965
26965
  var LAUNCH_WAITING_PREFIX = "waiting \xB7 the previous session in this worktree";
26966
26966
  var LAUNCH_WAITING_SAVING = `${LAUNCH_WAITING_PREFIX} is saving`;
26967
26967
  var LAUNCH_BOOTING = "booting";
26968
+ var LAUNCH_QUEUED = "queued \xB7 waiting for a worker";
26969
+ var LAUNCH_BUILDING_PREFIX = "building the workspace image";
26968
26970
  var LAUNCH_PREPARING = "preparing the workspace \xB7 no runtime yet \xB7 after an update, building the image takes about 8 minutes";
26969
26971
  var LAUNCH_BUILDING_IMAGE_LEGACY = "building the workspace image (first launch after an update, ~8 min)";
26970
26972
  var LAUNCH_PHASE_PREFIXES = [
26971
26973
  LAUNCH_WAITING_PREFIX,
26972
26974
  LAUNCH_BOOTING,
26975
+ LAUNCH_QUEUED,
26973
26976
  LAUNCH_PREPARING,
26974
- LAUNCH_BUILDING_IMAGE_LEGACY
26977
+ LAUNCH_BUILDING_IMAGE_LEGACY,
26978
+ LAUNCH_BUILDING_PREFIX
26975
26979
  ];
26976
26980
  var phaseWordsOf = (summary) => {
26977
26981
  for (const prefix of LAUNCH_PHASE_PREFIXES) {
@@ -26995,6 +26999,12 @@ var launchPhaseOf = (summary) => {
26995
26999
  return { kind: "waiting-previous", words: phase.words };
26996
27000
  }
26997
27001
  if (phase.words.startsWith(LAUNCH_BOOTING)) return { kind: "booting", words: phase.words };
27002
+ if (phase.words.startsWith(LAUNCH_QUEUED)) return { kind: "queued", words: phase.words };
27003
+ if (phase.words === LAUNCH_BUILDING_IMAGE_LEGACY)
27004
+ return { kind: "preparing", words: phase.words };
27005
+ if (phase.words.startsWith(LAUNCH_BUILDING_PREFIX)) {
27006
+ return { kind: "building", words: phase.words };
27007
+ }
26998
27008
  return { kind: "preparing", words: phase.words };
26999
27009
  };
27000
27010
 
@@ -28028,6 +28038,12 @@ var NativeIngestCursor = Schema_exports.Struct({
28028
28038
  lastEntryUuid: Schema_exports.NullOr(Schema_exports.String),
28029
28039
  lineCount: Schema_exports.Int
28030
28040
  });
28041
+ var LivePerson = class extends Schema_exports.Class("LivePerson")({
28042
+ accountId: Schema_exports.String,
28043
+ /** Their name as the instance knows it. */
28044
+ name: Schema_exports.String
28045
+ }) {
28046
+ };
28031
28047
  var Session = class extends Schema_exports.Class("Session")({
28032
28048
  id: SessionId,
28033
28049
  projectId: ProjectId,
@@ -28108,6 +28124,32 @@ var Session = class extends Schema_exports.Class("Session")({
28108
28124
  sharedControlEnabledAt: Schema_exports.NullOr(Timestamp).pipe(
28109
28125
  Schema_exports.withConstructorDefault(Effect_exports.succeed(null))
28110
28126
  ),
28127
+ /**
28128
+ * When shared control was first turned on, kept after it is turned off (docs/adr/0016,
28129
+ * decision 9): a session once shared runs on no one's memory and credits nobody until it ends.
28130
+ */
28131
+ sharedControlEverAt: Schema_exports.NullOr(Timestamp).pipe(
28132
+ Schema_exports.withDecodingDefaultKey(Effect_exports.succeed(null)),
28133
+ Schema_exports.withConstructorDefault(Effect_exports.succeed(null))
28134
+ ),
28135
+ /**
28136
+ * The people with a process live in the session's executor as their own user, in a per-person
28137
+ * executor (docs/adr/0016, decision 13): filled by the API's session list and view only, in the
28138
+ * same query; empty everywhere else, in a shared executor, and from older servers.
28139
+ */
28140
+ livePeople: Schema_exports.Array(LivePerson).pipe(
28141
+ Schema_exports.withDecodingDefaultKey(Effect_exports.succeed([])),
28142
+ Schema_exports.withConstructorDefault(Effect_exports.succeed([]))
28143
+ ),
28144
+ /**
28145
+ * The session's executor waits to be replaced (docs/adr/0016, decision 14): `marked` or
28146
+ * `retiring`; null otherwise. Read with `livePeople`, in the same query, so a client asks for the
28147
+ * retirement's detail only when there is one. Null everywhere else and from older servers.
28148
+ */
28149
+ workspaceRetirement: Schema_exports.NullOr(Schema_exports.Literals(["marked", "retiring"])).pipe(
28150
+ Schema_exports.withDecodingDefaultKey(Effect_exports.succeed(null)),
28151
+ Schema_exports.withConstructorDefault(Effect_exports.succeed(null))
28152
+ ),
28111
28153
  /**
28112
28154
  * Whether the harness left a conversation behind — a transcript Mend captured at settle or
28113
28155
  * found in the live harness home. False is a dead end: nothing to resume, nothing to hand
@@ -28364,6 +28406,62 @@ var LinuxIdentity = class extends Schema_exports.Class("LinuxIdentity")({
28364
28406
  uid: Schema_exports.Number
28365
28407
  }) {
28366
28408
  };
28409
+ var WorkspaceRetirementStopKind = Schema_exports.Literals([
28410
+ "terminal",
28411
+ "shell",
28412
+ "service",
28413
+ "turn",
28414
+ "process",
28415
+ "container",
28416
+ "unchecked"
28417
+ ]);
28418
+ var WorkspaceRetirementStop = class extends Schema_exports.Class(
28419
+ "WorkspaceRetirementStop"
28420
+ )({
28421
+ kind: WorkspaceRetirementStopKind,
28422
+ /**
28423
+ * What it is, as observed: a session's label, a Service's name, a process's command name and
28424
+ * pid, a container's name, or why something could not be checked. Empty for a process or a
28425
+ * container when the viewer is not the change's owner: they see its kind only.
28426
+ */
28427
+ label: Schema_exports.String
28428
+ }) {
28429
+ };
28430
+ var WorkspaceRetirementState = Schema_exports.Literals(["marked", "retiring"]);
28431
+ var WorkspaceRetirement = class extends Schema_exports.Class("WorkspaceRetirement")({
28432
+ state: WorkspaceRetirementState,
28433
+ /** The executor started before Mend 0.36 (no layout recorded for its launch). */
28434
+ preRelease: Schema_exports.Boolean,
28435
+ /** The account whose launch made the executor: the only one whose joins and turns it takes. */
28436
+ launcher: Schema_exports.NullOr(Schema_exports.String),
28437
+ /** What would stop if it were replaced now; empty when nothing would. */
28438
+ stops: Schema_exports.Array(WorkspaceRetirementStop),
28439
+ /** Why the last automatic replacement did not go ahead, as observed; null when none was tried. */
28440
+ reason: Schema_exports.NullOr(Schema_exports.String),
28441
+ /**
28442
+ * When what runs in the executor was last checked beyond Mend's own records (processes Mend did
28443
+ * not start, the sidecar's containers); null when only Mend's records were read.
28444
+ */
28445
+ checkedAt: Schema_exports.NullOr(Timestamp),
28446
+ /**
28447
+ * What the viewer was shown, as one token: "Replace this workspace now" names it, so Mend ends
28448
+ * nothing that was not listed (the replacement is refused if more would stop now).
28449
+ */
28450
+ fingerprint: Schema_exports.String,
28451
+ /** The viewer may replace it now: they own the change, and no agent turn is in flight. */
28452
+ canReplace: Schema_exports.Boolean
28453
+ }) {
28454
+ };
28455
+ var PreReleaseMemory = class extends Schema_exports.Class("PreReleaseMemory")({
28456
+ /** The capture it read, by its place on the worktree's chain. */
28457
+ captureN: Schema_exports.Number,
28458
+ provisional: Schema_exports.Boolean,
28459
+ creditedTo: Schema_exports.NullOr(Schema_exports.String),
28460
+ decidedBy: Schema_exports.Literals(["home-record", "only-person", "nobody", "nothing"]),
28461
+ /** Memory paths credited to nobody: two or more people's sessions shared the home. */
28462
+ notCredited: Schema_exports.Array(Schema_exports.String)
28463
+ }) {
28464
+ };
28367
28465
 
28368
28466
  // ../../packages/domain/src/workbench/host-user-namespaces.ts
28369
28467
  var HOST_USER_NAMESPACE_FILES = [
@@ -28439,7 +28537,7 @@ var ProjectClusterBindingsSnapshot = class extends Schema_exports.Class(
28439
28537
  }) {
28440
28538
  };
28441
28539
 
28442
- // ../../node_modules/.pnpm/@sealant+api-contracts-next@0.39.0-next.695_effect@4.0.0-beta.93/node_modules/@sealant/api-contracts-next/dist/workspace-environment.js
28540
+ // ../../node_modules/.pnpm/@sealant+api-contracts-next@0.39.0-next.706_effect@4.0.0-beta.93/node_modules/@sealant/api-contracts-next/dist/workspace-environment.js
28443
28541
  var RESERVED_NAMES = new Map([
28444
28542
  // Identity/process roots the daemon and shells own.
28445
28543
  ...[
@@ -28610,7 +28708,17 @@ var SessionProcess = class extends Schema_exports.Class("SessionProcess")({
28610
28708
  Schema_exports.withConstructorDefault(Effect_exports.succeed(null))
28611
28709
  ),
28612
28710
  exitedAt: Schema_exports.NullOr(Timestamp),
28613
- updatedAt: Timestamp
28711
+ updatedAt: Timestamp,
28712
+ /**
28713
+ * The Mend account whose Linux user the process runs as in a person-layout executor
28714
+ * (docs/adr/0016, decision 1: "the person a process runs as is recorded on the process when it
28715
+ * starts"). Null for a process that runs as root (a `shared` executor), on rows from before it
28716
+ * was recorded, and where older servers omit it.
28717
+ */
28718
+ runsAs: Schema_exports.NullOr(Schema_exports.String).pipe(
28719
+ Schema_exports.withDecodingDefaultKey(Effect_exports.succeed(null)),
28720
+ Schema_exports.withConstructorDefault(Effect_exports.succeed(null))
28721
+ )
28614
28722
  }) {
28615
28723
  };
28616
28724
 
@@ -29067,6 +29175,98 @@ var SlackLinkedMentionJob = Schema_exports.Struct({
29067
29175
  linkedAt: Schema_exports.String
29068
29176
  });
29069
29177
 
29178
+ // ../../packages/domain/src/workbench/shared-workspace.ts
29179
+ var listed = (names) => names.length <= 1 ? names[0] ?? "" : `${names.slice(0, -1).join(", ")} and ${names[names.length - 1] ?? ""}`;
29180
+ var joinWorktreeLine = (others) => others.length <= 1 ? `${others[0] ?? "Another person"}'s session is running in this worktree. You share its workspace: everything you run runs as you, on your own logins, but either of you can read the other's files, logins included.` : `${listed(others)}'s sessions are running in this worktree. You share its workspace: everything you run runs as you, on your own logins, but any of you can read the others' files, logins included.`;
29181
+ var JOIN_SHARED_HOME_LINE = "Another person's session is running in this worktree, in a workspace that shares one home: what you start there runs on the logins and Git identity of whoever started that workspace, not yours.";
29182
+ var sharedWorkspaceLine = (livePeople, viewer) => {
29183
+ if (livePeople.length < 2) return null;
29184
+ const others = livePeople.filter((person) => person.accountId !== viewer).map((p) => p.name);
29185
+ if (others.length === livePeople.length) {
29186
+ return `Shared workspace: ${listed(others)} \xB7 each runs as themselves \xB7 ${others.length === 2 ? "either can read the other's files" : "any of them can read the others' files"}.`;
29187
+ }
29188
+ return others.length === 1 && livePeople.length === 2 ? `Shared workspace with ${others[0]} \xB7 each of you runs as yourself \xB7 either of you can read the other's files.` : `Shared workspace with ${listed(others)} \xB7 each of you runs as yourself \xB7 any of you can read the others' files.`;
29189
+ };
29190
+ var SHARED_CONTROL_LINE = "Each turn runs on its sender's login. From now until this session ends, the agent uses no one's personal memory or instructions. The conversation so far, including what your agent loaded before, becomes visible to whoever steers.";
29191
+ var SHARED_CONTROL_LINE_OWNER_LOGINS = "Each turn runs on your provider logins and Git access, whoever sends it.";
29192
+ var sharedControlLine = (turnsOnSendersLogin) => turnsOnSendersLogin ? SHARED_CONTROL_LINE : SHARED_CONTROL_LINE_OWNER_LOGINS;
29193
+ var sharedControlConfirm = (turnsOnSendersLogin) => ({
29194
+ title: "Turn on shared control?",
29195
+ body: turnsOnSendersLogin ? SHARED_CONTROL_LINE : `Everyone who can see this project can send turns, answer approvals and interrupt. ${SHARED_CONTROL_LINE_OWNER_LOGINS}`,
29196
+ confirm: "Turn on",
29197
+ cancel: "Keep it off"
29198
+ });
29199
+ var workspaceRetirementLine = (retirement, launcherName) => {
29200
+ if (retirement.state === "retiring") {
29201
+ return "Replacing this workspace so that each person runs as themselves \xB7 nothing new starts until it has been saved and replaced";
29202
+ }
29203
+ const started = retirement.preRelease ? "This workspace started before Mend 0.36 and shares one home" : "This workspace shares one home";
29204
+ const reason = retirement.reason === null ? "" : ` \xB7 ${retirement.reason}`;
29205
+ return `${started} \xB7 it takes only ${launcherName}'s sessions and turns until it is replaced${reason}`;
29206
+ };
29207
+ var STOP_WORDS = {
29208
+ terminal: "terminal session (ends resumable)",
29209
+ shell: "shell",
29210
+ service: "Service started by hand",
29211
+ turn: "agent turn in flight",
29212
+ process: "process Mend did not start",
29213
+ container: "running container",
29214
+ unchecked: "could not check"
29215
+ };
29216
+ var REPLACE_WORKSPACE_ACTION = "Replace this workspace now";
29217
+ var timeOf3 = (at) => `${at.toISOString().slice(11, 16)} UTC`;
29218
+ var retirementStopLines = (retirement) => {
29219
+ const checked = retirement.checkedAt === null ? "Checked: Mend's records only \xB7 processes Mend did not start and running containers not checked yet" : `Checked at ${timeOf3(retirement.checkedAt)}: Mend's records, the processes in the workspace and its running containers`;
29220
+ const found = retirement.stops.length === 0 ? ["Found nothing that would stop."] : retirement.stops.map(
29221
+ (stop) => stop.label === "" ? STOP_WORDS[stop.kind] : `${STOP_WORDS[stop.kind]} \xB7 ${stop.label}`
29222
+ );
29223
+ return [checked, ...found, "Mend starts the launching session's mend.toml Services again."];
29224
+ };
29225
+
29226
+ // ../../packages/domain/src/workbench/steering.ts
29227
+ var ConversationWaitWork = Schema_exports.Struct({
29228
+ kind: Schema_exports.Literals([
29229
+ "task",
29230
+ "paused-task",
29231
+ "sub-agent",
29232
+ "terminal",
29233
+ "goal",
29234
+ "wakeup",
29235
+ "monitor",
29236
+ "cron",
29237
+ "unknown"
29238
+ ]),
29239
+ /** The harness's own id: what ending it names. */
29240
+ id: Schema_exports.String,
29241
+ description: Schema_exports.NullOr(Schema_exports.String),
29242
+ /**
29243
+ * The person the process runs as, or the session's owner, can end it from the waiting line
29244
+ * (Claude's task stop, a monitor's included, Codex's terminal terminate and goal clear). A
29245
+ * wakeup ends on its own within an hour; a scheduled prompt and what the harness would not say
29246
+ * are waited for at most `CONVERSATION_WAIT_BOUNDS_MS`.
29247
+ */
29248
+ endable: Schema_exports.Boolean
29249
+ });
29250
+ var ConversationWait = class extends Schema_exports.Class("ConversationWait")({
29251
+ sessionId: SessionId,
29252
+ /** The turn that waits; the turns behind it wait with it. */
29253
+ turnId: AgentTurnId,
29254
+ /** Whose process finishes its work: the person it runs as. */
29255
+ runsAs: Schema_exports.NullOr(Schema_exports.String),
29256
+ /** Whose turn waits. */
29257
+ sender: Schema_exports.String,
29258
+ /** A turn still runs in the process. */
29259
+ openTurn: Schema_exports.Boolean,
29260
+ work: Schema_exports.Array(ConversationWaitWork),
29261
+ /** The waiting line, in words: "Waits for Alice's 2 background tasks … before Bob's turn starts." */
29262
+ line: Schema_exports.String,
29263
+ since: Timestamp
29264
+ }) {
29265
+ };
29266
+ var CONVERSATION_WAIT_BOUNDS_MS = {
29267
+ cron: 10 * 6e4
29268
+ };
29269
+
29070
29270
  // ../../packages/domain/src/workbench/tour.ts
29071
29271
  var TourStop = class extends Schema_exports.Class("TourStop")({
29072
29272
  title: Schema_exports.String,
@@ -29475,6 +29675,120 @@ var GATEWAY_STATUSES = /* @__PURE__ */ new Set([
29475
29675
  ]);
29476
29676
  var mayStillBeWorking = (error) => error instanceof MendRequestError && (error.kind === "timeout" || error.kind === "dropped" || error.kind === "http" && error.status !== null && GATEWAY_STATUSES.has(error.status));
29477
29677
 
29678
+ // src/shared-workspace.ts
29679
+ var checkedAtOf = (retirement) => {
29680
+ if (retirement.checkedAt === null) return null;
29681
+ const at = new Date(retirement.checkedAt);
29682
+ return Number.isNaN(at.getTime()) ? null : at;
29683
+ };
29684
+ var retirementEvidenceLines = (retirement) => retirementStopLines({ stops: retirement.stops, checkedAt: checkedAtOf(retirement) });
29685
+ var workspaceReadsOf = (session) => ({
29686
+ waiting: (session.livePeople ?? []).length > 0 && session.sharedControlEnabledAt !== void 0 && session.sharedControlEnabledAt !== null,
29687
+ retirement: session.workspaceRetirement !== void 0 && session.workspaceRetirement !== null
29688
+ });
29689
+ var hasPersonFacts = (sessions) => sessions.some(
29690
+ (session) => (session.livePeople ?? []).length > 0 || session.workspaceRetirement !== void 0 && session.workspaceRetirement !== null
29691
+ );
29692
+ var worktreeListsPeople = (sessions, worktreeId) => sessions.some(
29693
+ (session) => session.worktreeId === worktreeId && (session.livePeople ?? []).length > 0
29694
+ );
29695
+ var othersLiveInWorktree = (sessions, worktreeId, viewer) => {
29696
+ if (viewer === null) return [];
29697
+ const names = /* @__PURE__ */ new Map();
29698
+ for (const session of sessions) {
29699
+ if (session.worktreeId !== worktreeId) continue;
29700
+ for (const person of session.livePeople ?? []) {
29701
+ if (person.accountId !== viewer) names.set(person.accountId, person.name);
29702
+ }
29703
+ }
29704
+ return [...names.values()];
29705
+ };
29706
+ var worktreeJoinLine = (sessions, worktreeId, viewer) => {
29707
+ const others = othersLiveInWorktree(sessions, worktreeId, viewer);
29708
+ if (others.length > 0) return joinWorktreeLine(others);
29709
+ if (viewer === null || worktreeListsPeople(sessions, worktreeId)) return null;
29710
+ const anotherLive = sessions.some(
29711
+ (session) => session.worktreeId === worktreeId && session.status !== void 0 && LIVE_STATUSES.has(session.status) && session.ownerUserId !== void 0 && session.ownerUserId !== null && session.ownerUserId !== viewer
29712
+ );
29713
+ return anotherLive ? JOIN_SHARED_HOME_LINE : null;
29714
+ };
29715
+ var launcherNameOf = (launcher, livePeople, members) => livePeople.find((person) => person.accountId === launcher)?.name ?? members.find((member) => member.userId === launcher)?.name ?? "its launcher";
29716
+ var sessionWorkspaceLines = (facts) => {
29717
+ const { retirement } = facts;
29718
+ return {
29719
+ shared: sharedWorkspaceLine(facts.livePeople, facts.viewer),
29720
+ waiting: facts.wait?.line ?? null,
29721
+ retirement: retirement === null ? null : workspaceRetirementLine(
29722
+ retirement,
29723
+ launcherNameOf(retirement.launcher, facts.livePeople, facts.members)
29724
+ ),
29725
+ // Only the change's owner replaces it, and only while it is marked: a retiring one is
29726
+ // already being replaced.
29727
+ replace: retirement === null || !retirement.canReplace || retirement.state !== "marked" ? null : {
29728
+ action: REPLACE_WORKSPACE_ACTION,
29729
+ command: `mend workspace replace ${facts.sessionId.slice(0, 8)}`,
29730
+ stops: retirementEvidenceLines(retirement)
29731
+ }
29732
+ };
29733
+ };
29734
+ var workspaceLineList = (lines) => [
29735
+ ...lines.shared === null ? [] : [lines.shared],
29736
+ ...lines.waiting === null ? [] : [lines.waiting],
29737
+ ...lines.retirement === null ? [] : [lines.retirement],
29738
+ ...lines.replace === null ? [] : [
29739
+ `${lines.replace.action} \xB7 ${lines.replace.command}`,
29740
+ ...lines.replace.stops.map((stop) => ` ${stop}`)
29741
+ ]
29742
+ ];
29743
+ var wrapWords = (text, width) => {
29744
+ const limit = Math.max(8, width);
29745
+ const lines = [];
29746
+ let current = "";
29747
+ for (const raw of text.split(/\s+/)) {
29748
+ if (raw === "") continue;
29749
+ let word = raw;
29750
+ while (word.length > limit) {
29751
+ if (current !== "") {
29752
+ lines.push(current);
29753
+ current = "";
29754
+ }
29755
+ lines.push(word.slice(0, limit));
29756
+ word = word.slice(limit);
29757
+ }
29758
+ if (current === "") current = word;
29759
+ else if (current.length + 1 + word.length <= limit) current = `${current} ${word}`;
29760
+ else {
29761
+ lines.push(current);
29762
+ current = word;
29763
+ }
29764
+ }
29765
+ if (current !== "") lines.push(current);
29766
+ return lines;
29767
+ };
29768
+ var confirmPlan = (args2, interactive) => args2.includes("--yes") || args2.includes("-y") ? "confirmed" : interactive ? "ask" : "refuse";
29769
+ var sharedControlConfirmLines = (turnsOnSendersLogin) => {
29770
+ const confirm = sharedControlConfirm(turnsOnSendersLogin);
29771
+ return [confirm.title, confirm.body];
29772
+ };
29773
+ var sharedControlQuestion = (turnsOnSendersLogin) => {
29774
+ const confirm = sharedControlConfirm(turnsOnSendersLogin);
29775
+ return `${confirm.confirm.toLowerCase()}? (n: ${confirm.cancel.toLowerCase()})`;
29776
+ };
29777
+ var replaceConfirmLines = (retirement) => [
29778
+ `${REPLACE_WORKSPACE_ACTION}?`,
29779
+ ...retirementEvidenceLines(retirement).map((stop) => ` ${stop}`)
29780
+ ];
29781
+ var askYesNo = async (question) => {
29782
+ const readline = await import("node:readline/promises");
29783
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
29784
+ try {
29785
+ const answer = (await rl.question(`${question} [y/N] `)).trim().toLowerCase();
29786
+ return answer === "y" || answer === "yes";
29787
+ } finally {
29788
+ rl.close();
29789
+ }
29790
+ };
29791
+
29478
29792
  // src/workbench-events.ts
29479
29793
  var createSseParser = () => {
29480
29794
  let buffer = "";
@@ -29553,6 +29867,10 @@ export {
29553
29867
  servicesHoldLine,
29554
29868
  validateSecretFilePath,
29555
29869
  terminalReadOnlyLine,
29870
+ sharedControlLine,
29871
+ sharedControlConfirm,
29872
+ workspaceRetirementLine,
29873
+ REPLACE_WORKSPACE_ACTION,
29556
29874
  WORKTREE_REMOVAL_FORCE_HINT,
29557
29875
  HARNESS_COMMANDS,
29558
29876
  pendingId,
@@ -29582,6 +29900,19 @@ export {
29582
29900
  noAnswerError,
29583
29901
  GATEWAY_STATUSES,
29584
29902
  mayStillBeWorking,
29903
+ workspaceReadsOf,
29904
+ hasPersonFacts,
29905
+ worktreeListsPeople,
29906
+ worktreeJoinLine,
29907
+ launcherNameOf,
29908
+ sessionWorkspaceLines,
29909
+ workspaceLineList,
29910
+ wrapWords,
29911
+ confirmPlan,
29912
+ sharedControlConfirmLines,
29913
+ sharedControlQuestion,
29914
+ replaceConfirmLines,
29915
+ askYesNo,
29585
29916
  createSseParser,
29586
29917
  eventFamilies
29587
29918
  };