@sealant/mend 0.27.5 → 0.29.0

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 (75) hide show
  1. package/README.md +36 -13
  2. package/dist/{chunk-A5I5EW2Y.js → chunk-F6AJNFVE.js} +238 -8
  3. package/dist/{dashboard-G52NHJCZ.js → dashboard-ZKCPU2QJ.js} +1388 -602
  4. package/dist/main.js +1473 -663
  5. package/man/mend-accounts.1 +1 -1
  6. package/man/mend-adopt.1 +8 -2
  7. package/man/mend-attach.1 +1 -1
  8. package/man/mend-codex.1 +1 -1
  9. package/man/mend-completions.1 +1 -1
  10. package/man/mend-connect.1 +9 -4
  11. package/man/mend-continue.1 +1 -1
  12. package/man/mend-doctor.1 +1 -1
  13. package/man/mend-dotfiles-sync.1 +1 -1
  14. package/man/mend-dotfiles.1 +1 -1
  15. package/man/mend-env-cluster.1 +1 -1
  16. package/man/mend-env-load.1 +1 -1
  17. package/man/mend-env-show.1 +1 -1
  18. package/man/mend-folder-create.1 +11 -0
  19. package/man/mend-folder-list.1 +11 -0
  20. package/man/mend-folder-push.1 +18 -0
  21. package/man/mend-folder-rm.1 +11 -0
  22. package/man/mend-help.1 +1 -1
  23. package/man/mend-invite.1 +26 -0
  24. package/man/mend-keys-init.1 +1 -1
  25. package/man/mend-keys-mode.1 +1 -1
  26. package/man/mend-keys-share.1 +1 -1
  27. package/man/mend-keys-show.1 +1 -1
  28. package/man/mend-login.1 +1 -1
  29. package/man/mend-logout.1 +1 -1
  30. package/man/mend-man.1 +1 -1
  31. package/man/mend-members.1 +11 -0
  32. package/man/mend-operator-exposure.1 +11 -0
  33. package/man/mend-operator-gate.1 +11 -0
  34. package/man/mend-operator-grant-owner.1 +11 -0
  35. package/man/mend-operator-org-create.1 +11 -0
  36. package/man/mend-operator-org-invite-owner.1 +15 -0
  37. package/man/mend-operator-org-list.1 +11 -0
  38. package/man/mend-operator-org-rename.1 +11 -0
  39. package/man/mend-operator-reset-link.1 +11 -0
  40. package/man/mend-pair.1 +1 -1
  41. package/man/mend-projects.1 +1 -1
  42. package/man/mend-refresh.1 +1 -1
  43. package/man/mend-rejoin.1 +1 -1
  44. package/man/mend-resume.1 +1 -1
  45. package/man/mend-run.1 +1 -1
  46. package/man/mend-server-logs.1 +1 -1
  47. package/man/mend-server-restart.1 +1 -1
  48. package/man/mend-server-setup.1 +2 -2
  49. package/man/mend-server-start.1 +1 -1
  50. package/man/mend-server-status.1 +1 -1
  51. package/man/mend-server-stop.1 +1 -1
  52. package/man/mend-server-upgrade.1 +1 -1
  53. package/man/mend-server.1 +1 -1
  54. package/man/mend-service-add.1 +1 -1
  55. package/man/mend-service-connect.1 +1 -1
  56. package/man/mend-service-init.1 +1 -1
  57. package/man/mend-service-list.1 +1 -1
  58. package/man/mend-service-logs.1 +1 -1
  59. package/man/mend-service-restart.1 +1 -1
  60. package/man/mend-service-run.1 +1 -1
  61. package/man/mend-service-stop.1 +1 -1
  62. package/man/mend-session-share.1 +14 -0
  63. package/man/mend-sessions.1 +1 -1
  64. package/man/mend-shell.1 +1 -1
  65. package/man/mend-skills-push.1 +1 -1
  66. package/man/mend-skills.1 +1 -1
  67. package/man/mend-ssh-setup.1 +1 -1
  68. package/man/mend-ssh.1 +1 -1
  69. package/man/mend-stop.1 +1 -1
  70. package/man/mend-ui.1 +6 -2
  71. package/man/mend-uninstall.1 +1 -1
  72. package/man/mend-version.1 +1 -1
  73. package/man/mend-worktrees.1 +1 -1
  74. package/man/mend.1 +48 -2
  75. package/package.json +1 -1
package/README.md CHANGED
@@ -11,11 +11,24 @@ npm install -g @sealant/mend
11
11
 
12
12
  Requires Node 22+ and a running Mend server.
13
13
 
14
- Run bare `mend` for the interactive dashboard. Highlight a session and press `v` to review its
15
- accumulated change in the terminal: navigate files and hunks, switch between unified and split
16
- diffs, reveal whitespace, select line ranges, add line or whole-change comments, inspect linked
17
- evidence, and draft a follow-up for the same session. Press `y` to deliver a pending follow-up and
18
- relaunch that session, or `o` to continue the review in the web app.
14
+ Run bare `mend` for the interactive dashboard. The session pane takes three quarters of the screen
15
+ and previews the recorded conversation without taking terminal control. The remaining quarter is a
16
+ sidebar of three stacked sections — **Projects**, **Worktrees**, **Sessions** — where the section
17
+ you are in stands open and the other two fold to the line that says what is selected; moving into
18
+ the session pane leaves the sidebar as it was.
19
+
20
+ Use `↑↓` to select rows and `←→` or Tab to move between the sections and the session pane. Enter
21
+ moves right; it never launches or attaches. Press `a` to attach, `r` to resume a settled session, or
22
+ `n` to create a session in the selected worktree (`w` creates a worktree). After starting or
23
+ resuming, press `a` when ready to attach. Nothing is ever squeezed: a terminal too narrow for both
24
+ gives the whole width to the side you are on, a terminal too short for three drawn panes shows the
25
+ open section alone, and a one-line breadcrumb states whatever did not fit.
26
+
27
+ Highlight a session and press `v` to review its accumulated change in the terminal: navigate files
28
+ and hunks, switch between unified and split diffs, reveal whitespace, select line ranges, add line
29
+ or whole-change comments, inspect linked evidence, and draft a follow-up for the same session. Press
30
+ `y` to deliver a pending follow-up and relaunch that session, or `o` to continue the review in the
31
+ web app.
19
32
 
20
33
  ## Local server
21
34
 
@@ -75,7 +88,7 @@ mend doctor # every fact above, on one screen
75
88
 
76
89
  ### mend pair
77
90
 
78
- ```
91
+ ```text
79
92
  mend pair [--url <base url>]
80
93
  ```
81
94
 
@@ -88,16 +101,17 @@ from the Mend app later. The device names itself when it claims the code.
88
101
 
89
102
  ### mend doctor
90
103
 
91
- ```
104
+ ```sh
92
105
  mend doctor
93
106
  ```
94
107
 
95
108
  Reads, and changes nothing: server reachable, token accepted, the Sealant connection, each connected
96
109
  account, adopted projects, the `claude` / `codex` / `gh` CLIs on PATH and whether their credentials
97
- exist on this machine, and the tailnet address. One line per fact — `✓` observed, `○` not set up
98
- yet, `✗` a blocker — and every line that needs an action ends with the one command that takes it:
110
+ exist on this machine, and how the instance is exposed: what its operator declared and what the
111
+ server observed. One line per fact — `✓` observed, `○` not set up yet, `✗` a blocker — and every
112
+ line that needs an action ends with the one command that takes it:
99
113
 
100
- ```
114
+ ```text
101
115
  ✓ server http://localhost:3105 · mend 0.5.0
102
116
  ✓ signed in token accepted
103
117
  ✓ sealant connected · http://127.0.0.1:4000
@@ -105,14 +119,14 @@ yet, `✗` a blocker — and every line that needs an action ends with the one c
105
119
  ○ codex not connected → mend connect codex
106
120
  ✓ projects 2 adopted
107
121
  ○ gh cli on PATH · no credential here → gh auth login
108
- ○ tailnet not detected
122
+ ✓ exposure declared loopback · http origin
109
123
  ```
110
124
 
111
125
  It exits 1 when a `✗` is printed, so a setup script can gate on it. No request waits longer than 3s.
112
126
 
113
127
  ## Commands
114
128
 
115
- ```
129
+ ```text
116
130
  mend adopt [git-url] [--name <name>] clone a network Git repository into the store
117
131
  (default: the current checkout's origin URL)
118
132
  mend codex|claude|opencode new session worktree + launch the harness in it
@@ -138,7 +152,7 @@ mend version this CLI's version, and the server's when
138
152
 
139
153
  ## Signing in
140
154
 
141
- ```
155
+ ```sh
142
156
  mend login # opens the browser at <server>/authorize; press Authorize there
143
157
  mend login --url https://mend.example.com
144
158
  mend logout # revokes this terminal's device token and forgets it
@@ -228,6 +242,15 @@ on first connection, but refuses a changed key. Rerunning setup does not replace
228
242
  | `MEND_DETACH_KEY` | Set to `none` when an outer multiplexer detaches |
229
243
  | `~/.config/mend/cli.json` | `{ "url": ..., "token": ..., "deviceId": ... }` — env vars win; a pre-XDG `~/.mend/cli.json` keeps working |
230
244
 
245
+ ## Colors
246
+
247
+ The dashboard and review screen use Ayu Mirage backgrounds and accents, with brighter text and
248
+ borders for terminal legibility. `src/tui-theme.ts` defines the shared palette. Inactive pane titles
249
+ use the primary text color, not the border color.
250
+
251
+ Palette tests require at least 7:1 text contrast on the main backgrounds and 6:1 on selected rows.
252
+ Selection and diff backgrounds use solid, precomposited colors. The web theme is unchanged.
253
+
231
254
  ## Herdr
232
255
 
233
256
  When Mend attaches Codex, Claude Code, or OpenCode inside a Herdr pane, it reports that harness to
@@ -4,6 +4,64 @@ var __export = (target, all3) => {
4
4
  __defProp(target, name, { get: all3[name], enumerable: true });
5
5
  };
6
6
 
7
+ // ../../packages/domain/src/workbench/connected-credential.ts
8
+ var CLAUDE_GRANT_SECTION = "claudeAiOauth";
9
+ var narrowCredential = (provider, secret) => {
10
+ if (provider !== "claude") return { kind: "unchanged", secret };
11
+ const parsed = parseDocument(secret);
12
+ if (parsed === null) return { kind: "unchanged", secret };
13
+ const grant = parsed[CLAUDE_GRANT_SECTION];
14
+ if (grant === void 0) return { kind: "unchanged", secret };
15
+ const dropped = Object.keys(parsed).filter((key) => key !== CLAUDE_GRANT_SECTION).toSorted();
16
+ return {
17
+ kind: "narrowed",
18
+ // Two spaces and a trailing newline: the shape Claude Code writes, so a round trip through
19
+ // Mend leaves a file a person can still read.
20
+ secret: `${JSON.stringify({ [CLAUDE_GRANT_SECTION]: grant }, null, 2)}
21
+ `,
22
+ dropped
23
+ };
24
+ };
25
+ var parseDocument = (secret) => {
26
+ const trimmed = secret.trim();
27
+ if (!trimmed.startsWith("{")) return null;
28
+ try {
29
+ const value3 = JSON.parse(trimmed);
30
+ return typeof value3 === "object" && value3 !== null && !Array.isArray(value3) ? value3 : null;
31
+ } catch {
32
+ return null;
33
+ }
34
+ };
35
+ var claudeGrantFacts = (secret) => {
36
+ const parsed = parseDocument(secret);
37
+ const grant = parsed?.[CLAUDE_GRANT_SECTION];
38
+ if (typeof grant !== "object" || grant === null) return null;
39
+ const record3 = { ...grant };
40
+ const refreshToken = record3["refreshToken"];
41
+ return {
42
+ accessExpiresAt: asDate(record3["expiresAt"]),
43
+ refreshExpiresAt: asDate(record3["refreshTokenExpiresAt"]),
44
+ subscriptionType: typeof record3["subscriptionType"] === "string" ? record3["subscriptionType"] : null,
45
+ hasRefreshToken: typeof refreshToken === "string" && refreshToken !== ""
46
+ };
47
+ };
48
+ var asDate = (value3) => {
49
+ if (typeof value3 !== "number" || !Number.isFinite(value3) || value3 <= 0) return null;
50
+ const date2 = new Date(value3);
51
+ return Number.isNaN(date2.getTime()) ? null : date2;
52
+ };
53
+ var sameGrant = (left, right) => {
54
+ const token = (secret) => {
55
+ const grant = parseDocument(secret)?.[CLAUDE_GRANT_SECTION];
56
+ if (typeof grant !== "object" || grant === null) return null;
57
+ const value3 = grant["refreshToken"];
58
+ return typeof value3 === "string" && value3 !== "" ? value3 : null;
59
+ };
60
+ const a = token(left);
61
+ const b = token(right);
62
+ return a !== null && b !== null && a === b;
63
+ };
64
+
7
65
  // ../../node_modules/.pnpm/effect@4.0.0-beta.93/node_modules/effect/dist/Pipeable.js
8
66
  var pipeArguments = (self, args2) => {
9
67
  switch (args2.length) {
@@ -26436,6 +26494,11 @@ var ProjectEnvironmentVariableId = Schema_exports.String.pipe(
26436
26494
  );
26437
26495
  var ProjectSecretId = Schema_exports.String.pipe(Schema_exports.brand("ProjectSecretId"));
26438
26496
  var ProjectClusterBindingId = Schema_exports.String.pipe(Schema_exports.brand("ProjectClusterBindingId"));
26497
+ var OrganizationId = Schema_exports.String.pipe(Schema_exports.brand("OrganizationId"));
26498
+ var InvitationId = Schema_exports.String.pipe(Schema_exports.brand("InvitationId"));
26499
+ var FolderId = Schema_exports.String.pipe(Schema_exports.brand("FolderId"));
26500
+ var AuditEventId = Schema_exports.String.pipe(Schema_exports.brand("AuditEventId"));
26501
+ var SessionControlEventId = Schema_exports.String.pipe(Schema_exports.brand("SessionControlEventId"));
26439
26502
 
26440
26503
  // ../../packages/domain/src/settings.ts
26441
26504
  var PrMode = Schema_exports.Literals(["draft-immediately", "pr-on-approval"]);
@@ -26563,6 +26626,45 @@ var Timestamp = Schema_exports.Union([
26563
26626
  ]);
26564
26627
  var SequenceNumber = Schema_exports.Union([Schema_exports.BigIntFromString, Schema_exports.BigInt]);
26565
26628
 
26629
+ // ../../packages/domain/src/workbench/organization.ts
26630
+ var OrganizationRole = Schema_exports.Literals(["owner", "member"]);
26631
+ var InstanceRole = Schema_exports.Literals(["operator"]);
26632
+ var TenancyMode = Schema_exports.Literals(["single", "multi"]);
26633
+ var ProjectVisibility = Schema_exports.Literals(["private", "shared"]);
26634
+ var Organization = class extends Schema_exports.Class("Organization")({
26635
+ id: OrganizationId,
26636
+ /** Display name, unique per instance after trimming and case folding. */
26637
+ name: Schema_exports.String,
26638
+ /** The account that created it; null for the organization the upgrade created. */
26639
+ createdByUserId: Schema_exports.NullOr(Schema_exports.String),
26640
+ createdAt: Timestamp,
26641
+ updatedAt: Timestamp
26642
+ }) {
26643
+ };
26644
+ var OrganizationMember = class extends Schema_exports.Class("OrganizationMember")({
26645
+ organizationId: OrganizationId,
26646
+ userId: Schema_exports.String,
26647
+ name: Schema_exports.String,
26648
+ email: Schema_exports.String,
26649
+ role: OrganizationRole,
26650
+ joinedAt: Timestamp
26651
+ }) {
26652
+ };
26653
+ var Invitation = class extends Schema_exports.Class("Invitation")({
26654
+ id: InvitationId,
26655
+ organizationId: OrganizationId,
26656
+ role: OrganizationRole,
26657
+ /** When set, only the account with this email can accept. */
26658
+ email: Schema_exports.NullOr(Schema_exports.String),
26659
+ createdByUserId: Schema_exports.String,
26660
+ createdAt: Timestamp,
26661
+ expiresAt: Timestamp,
26662
+ acceptedByUserId: Schema_exports.NullOr(Schema_exports.String),
26663
+ acceptedAt: Schema_exports.NullOr(Timestamp),
26664
+ revokedAt: Schema_exports.NullOr(Timestamp)
26665
+ }) {
26666
+ };
26667
+
26566
26668
  // ../../packages/domain/src/workbench/project.ts
26567
26669
  var AutomationChoice = Schema_exports.Literals(["inherit", "on", "off"]);
26568
26670
  var GitAuthMode = Schema_exports.Literals(["ambient", "mend-key", "bridge"]);
@@ -26586,7 +26688,10 @@ var repositoryCloneUrlIssue = (value3) => {
26586
26688
  } catch {
26587
26689
  return REPOSITORY_CLONE_URL_GUIDANCE;
26588
26690
  }
26589
- if (url.protocol !== "http:" && url.protocol !== "https:" && url.protocol !== "ssh:" && url.protocol !== "git:" || url.hostname === "" || url.pathname === "" || url.pathname === "/") {
26691
+ if (url.protocol !== "http:" && url.protocol !== "https:" && url.protocol !== "ssh:" && url.protocol !== "git:" || url.hostname === "" || url.pathname === "" || url.pathname === "/" || // A host is a DNS name or an IP literal. `ssh:` is not a special scheme, so URL keeps any
26692
+ // code point in its host; a `$`, backtick or `;` there would reach a shell through
26693
+ // GIT_SSH_COMMAND.
26694
+ !/^(?:[a-z0-9_-]+(?:\.[a-z0-9_-]+)*\.?|\[[0-9a-f:.]+\])$/i.test(url.hostname)) {
26590
26695
  return REPOSITORY_CLONE_URL_GUIDANCE;
26591
26696
  }
26592
26697
  return null;
@@ -26597,11 +26702,20 @@ var RepositoryCloneUrl = Schema_exports.String.pipe(
26597
26702
  );
26598
26703
  var Project = class extends Schema_exports.Class("Project")({
26599
26704
  id: ProjectId,
26600
- /** Short name; also the store directory name. */
26705
+ /** Short name, unique within the organization. */
26601
26706
  name: Schema_exports.String,
26707
+ /** The organization that owns the project (docs/adr/0003-organizations-and-tenancy.md). */
26708
+ organizationId: OrganizationId,
26709
+ /** `private`: its creator only. `shared`: every member of its organization. */
26710
+ visibility: ProjectVisibility,
26711
+ /** The account that adopted it; the creator a private project is visible to. */
26712
+ createdByUserId: Schema_exports.NullOr(Schema_exports.String),
26602
26713
  /** Network Git URL used for adoption. Null only for legacy bare-created repositories. */
26603
26714
  originUrl: Schema_exports.NullOr(Schema_exports.String),
26604
- /** Absolute path of the bare repo inside the store: `<storeRoot>/<name>/repo.git`. */
26715
+ /**
26716
+ * Absolute path of the bare repo inside the store: `<storeRoot>/<projectId>/repo.git` for
26717
+ * projects adopted after organizations, `<storeRoot>/<name>/repo.git` before.
26718
+ */
26605
26719
  storePath: Schema_exports.String,
26606
26720
  defaultBranch: Schema_exports.String,
26607
26721
  /** HEAD of the default branch at adoption — display only; git is the source of truth. */
@@ -26653,6 +26767,45 @@ var Project = class extends Schema_exports.Class("Project")({
26653
26767
  }) {
26654
26768
  };
26655
26769
 
26770
+ // ../../packages/domain/src/workbench/audit.ts
26771
+ var AuditAction = Schema_exports.Literals([
26772
+ "invitation.created",
26773
+ "invitation.revoked",
26774
+ "invitation.accepted",
26775
+ "member.role_changed",
26776
+ "member.removed",
26777
+ "project.visibility_changed",
26778
+ "project.taken_over",
26779
+ "folder.created",
26780
+ "folder.removed",
26781
+ "reference.added",
26782
+ "reference.removed",
26783
+ "session.shared_control_on",
26784
+ "session.shared_control_off",
26785
+ "member.password_reset_issued",
26786
+ "organization.created",
26787
+ "organization.renamed",
26788
+ "recovery.owner_granted",
26789
+ "recovery.password_reset_issued"
26790
+ ]);
26791
+ var AuditData = Schema_exports.Record(
26792
+ Schema_exports.String,
26793
+ Schema_exports.Union([Schema_exports.String, Schema_exports.Number, Schema_exports.Boolean, Schema_exports.Null])
26794
+ );
26795
+ var AuditEvent = class extends Schema_exports.Class("AuditEvent")({
26796
+ id: AuditEventId,
26797
+ organizationId: OrganizationId,
26798
+ /** The account that acted. */
26799
+ actorUserId: Schema_exports.String,
26800
+ action: AuditAction,
26801
+ /** What the action touched: `member`, `invitation`, `project`, `session`, `folder` or `reference`. */
26802
+ subjectType: Schema_exports.String,
26803
+ subjectId: Schema_exports.String,
26804
+ data: AuditData,
26805
+ createdAt: Timestamp
26806
+ }) {
26807
+ };
26808
+
26656
26809
  // ../../packages/domain/src/workbench/agent-protocol.ts
26657
26810
  var AgentLaunchMode = Schema_exports.Literals(["pty", "protocol"]);
26658
26811
  var AgentTurnStatus = Schema_exports.Literals([
@@ -26888,6 +27041,36 @@ var ContextSnapshot = class extends Schema_exports.Class("ContextSnapshot")({
26888
27041
  }) {
26889
27042
  };
26890
27043
 
27044
+ // ../../packages/domain/src/workbench/folder.ts
27045
+ var Folder = class extends Schema_exports.Class("Folder")({
27046
+ id: FolderId,
27047
+ organizationId: OrganizationId,
27048
+ /** Short name, unique within the organization; the default mount directory name. */
27049
+ name: Schema_exports.String,
27050
+ /** Absolute path of the directory inside the store: `_organizations/<org>/folders/<id>`. */
27051
+ path: Schema_exports.String,
27052
+ createdByUserId: Schema_exports.NullOr(Schema_exports.String),
27053
+ createdAt: Timestamp,
27054
+ updatedAt: Timestamp
27055
+ }) {
27056
+ };
27057
+ var ProjectFolder = class extends Schema_exports.Class("ProjectFolder")({
27058
+ projectId: ProjectId,
27059
+ folderId: FolderId,
27060
+ /** Mount directory under `/workspace/home/`. */
27061
+ name: Schema_exports.String,
27062
+ readOnly: Schema_exports.Boolean,
27063
+ createdAt: Timestamp
27064
+ }) {
27065
+ };
27066
+ var FolderFile = class extends Schema_exports.Class("FolderFile")({
27067
+ path: Schema_exports.String,
27068
+ bytes: Schema_exports.Int
27069
+ }) {
27070
+ };
27071
+ var FOLDER_MAX_FILE_BYTES = 1024 * 1024;
27072
+ var FOLDER_MAX_REQUEST_BYTES = 4 * 1024 * 1024;
27073
+
26891
27074
  // ../../packages/domain/src/workbench/review-slice.ts
26892
27075
  var DiffDigest = Schema_exports.String.pipe(
26893
27076
  Schema_exports.check(Schema_exports.isPattern(/^[0-9a-f]{64}$/)),
@@ -26966,11 +27149,22 @@ var SessionExtraMount = class extends Schema_exports.Class("SessionExtraMount")(
26966
27149
  // ../../packages/domain/src/workbench/reference.ts
26967
27150
  var Reference2 = class extends Schema_exports.Class("Reference")({
26968
27151
  id: ReferenceId,
26969
- /** Short name; also the clone directory and the mount directory name. */
27152
+ /** Short name, unique within the organization; also the mount directory name. */
26970
27153
  name: Schema_exports.String,
27154
+ /** The organization that owns the reference (docs/adr/0003-organizations-and-tenancy.md). */
27155
+ organizationId: OrganizationId,
27156
+ /**
27157
+ * The account that added it. References added before organizations are credited to the oldest
27158
+ * account; null only on an instance that had no account yet.
27159
+ */
27160
+ createdByUserId: Schema_exports.NullOr(Schema_exports.String),
26971
27161
  /** Where the clone comes from — a remote URL or a local path. */
26972
27162
  originUrl: Schema_exports.String,
26973
- /** Absolute path of the clone inside the store: `<storeRoot>/_references/<name>`. */
27163
+ /**
27164
+ * Absolute path of the clone inside the store:
27165
+ * `<storeRoot>/_organizations/<organizationId>/references/<id>`, or
27166
+ * `<storeRoot>/_references/<name>` for references added before organizations.
27167
+ */
26974
27168
  path: Schema_exports.String,
26975
27169
  /** Branch or tag the clone is held at; null = the remote's default branch. */
26976
27170
  pinnedRef: Schema_exports.NullOr(Schema_exports.String),
@@ -27062,6 +27256,16 @@ var Session = class extends Schema_exports.Class("Session")({
27062
27256
  dotfiles: Schema_exports.NullOr(SessionDotfiles),
27063
27257
  /** Who provisioned the session — whose dotfiles apply. Null for pre-column rows. */
27064
27258
  ownerUserId: Schema_exports.NullOr(Schema_exports.String),
27259
+ /**
27260
+ * Shared control (docs/adr/0003-organizations-and-tenancy.md): when set, anyone who can see the
27261
+ * session may steer it, still on the owner's credentials. Who turned it on, and when.
27262
+ */
27263
+ sharedControlEnabledByUserId: Schema_exports.NullOr(Schema_exports.String).pipe(
27264
+ Schema_exports.withConstructorDefault(Effect_exports.succeed(null))
27265
+ ),
27266
+ sharedControlEnabledAt: Schema_exports.NullOr(Timestamp).pipe(
27267
+ Schema_exports.withConstructorDefault(Effect_exports.succeed(null))
27268
+ ),
27065
27269
  /**
27066
27270
  * Whether the harness left a conversation behind — a transcript Mend captured at settle or
27067
27271
  * found in the live harness home. False is a dead end: nothing to resume, nothing to hand
@@ -27105,8 +27309,11 @@ var HotWorkspace = class extends Schema_exports.Class("HotWorkspace")({
27105
27309
  * launch. Rows from before still carry the pre-created worktree the drain must remove.
27106
27310
  */
27107
27311
  worktreeId: Schema_exports.NullOr(WorktreeId),
27108
- /** Whose dotfiles were resolved at prewarm. Null when no user has dotfiles configured. */
27109
- ownerUserId: Schema_exports.NullOr(Schema_exports.String),
27312
+ /**
27313
+ * The account the workspace was provisioned as: its connected accounts, dotfiles and signer.
27314
+ * Only that account's sessions claim it (docs/adr/0003-organizations-and-tenancy.md).
27315
+ */
27316
+ ownerUserId: Schema_exports.String,
27110
27317
  status: HotWorkspaceStatus,
27111
27318
  /** Why provisioning failed, when it did — surfaced on the project setup page. */
27112
27319
  error: Schema_exports.NullOr(Schema_exports.String),
@@ -27188,7 +27395,7 @@ var ProjectClusterBindingsSnapshot = class extends Schema_exports.Class(
27188
27395
  }) {
27189
27396
  };
27190
27397
 
27191
- // ../../node_modules/.pnpm/@sealant+api-contracts@0.32.0_effect@4.0.0-beta.93/node_modules/@sealant/api-contracts/dist/workspace-environment.js
27398
+ // ../../node_modules/.pnpm/@sealant+api-contracts@0.36.0_effect@4.0.0-beta.93/node_modules/@sealant/api-contracts/dist/workspace-environment.js
27192
27399
  var RESERVED_NAMES = new Map([
27193
27400
  // Identity/process roots the daemon and shells own.
27194
27401
  ...[
@@ -27523,6 +27730,26 @@ var ServiceView = class extends Schema_exports.Class("ServiceView")({
27523
27730
  }) {
27524
27731
  };
27525
27732
 
27733
+ // ../../packages/domain/src/workbench/session-control.ts
27734
+ var SessionControlKind = Schema_exports.Literals([
27735
+ "interrupt",
27736
+ "terminal-attach",
27737
+ "shell-open",
27738
+ "stop",
27739
+ "shared-control-on",
27740
+ "shared-control-off"
27741
+ ]);
27742
+ var SessionControlEvent = class extends Schema_exports.Class("SessionControlEvent")({
27743
+ id: SessionControlEventId,
27744
+ sessionId: SessionId,
27745
+ actorUserId: Schema_exports.String,
27746
+ kind: SessionControlKind,
27747
+ /** The turn, process or Service the act concerned, when it concerned one. */
27748
+ refId: Schema_exports.NullOr(Schema_exports.String),
27749
+ createdAt: Timestamp
27750
+ }) {
27751
+ };
27752
+
27526
27753
  // ../../packages/domain/src/workbench/session-run.ts
27527
27754
  var SessionRun = class extends Schema_exports.Class("SessionRun")({
27528
27755
  sealantRunId: SealantRunId,
@@ -27879,6 +28106,9 @@ var trackBracketedPaste = (output, current) => {
27879
28106
  var pasteBytes = (text, bracketed) => Buffer.from(bracketed ? `\x1B[200~${text}\x1B[201~` : text, "utf8");
27880
28107
 
27881
28108
  export {
28109
+ narrowCredential,
28110
+ claudeGrantFacts,
28111
+ sameGrant,
27882
28112
  repositoryCloneUrlIssue,
27883
28113
  RepositoryCloneUrl,
27884
28114
  HARNESS_COMMANDS,