@opengeni/api-router 0.30.3 → 2.2.0-canary.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 (165) hide show
  1. package/dist/api-websocket.d.ts +18 -0
  2. package/dist/app.js +1 -1
  3. package/dist/auth/managed-auth.d.ts +6 -0
  4. package/dist/{chunk-WCXHI3FF.js → chunk-3TP54PPX.js} +26692 -15389
  5. package/dist/chunk-3TP54PPX.js.map +1 -0
  6. package/dist/codemode.d.ts +8 -1
  7. package/dist/company-brain-okf.d.ts +24 -0
  8. package/dist/connected-machine-computer-access.d.ts +11 -0
  9. package/dist/connection-authority-owner.d.ts +59 -0
  10. package/dist/connection-ownership.d.ts +47 -0
  11. package/dist/controller-data-plane.d.ts +16 -0
  12. package/dist/editable-artifact-websocket.d.ts +5 -15
  13. package/dist/editable-artifact-workspace-files.d.ts +1 -1
  14. package/dist/http/api-error.d.ts +10 -0
  15. package/dist/http/cors.d.ts +5 -0
  16. package/dist/http/interaction-control-error.d.ts +13 -0
  17. package/dist/http/sse.d.ts +2 -3
  18. package/dist/index.d.ts +5 -2
  19. package/dist/index.js +326 -82
  20. package/dist/index.js.map +1 -1
  21. package/dist/integrations/atlassian.d.ts +17 -0
  22. package/dist/integrations/fiken.d.ts +7 -2
  23. package/dist/integrations/google-drive.d.ts +18 -0
  24. package/dist/integrations/oauth-client.d.ts +22 -3
  25. package/dist/integrations/oauth-profiles.d.ts +195 -0
  26. package/dist/integrations/personal-github-repositories.d.ts +45 -0
  27. package/dist/integrations/personal-github.d.ts +40 -0
  28. package/dist/integrations/pr-review-provider.d.ts +22 -0
  29. package/dist/integrations/provider-oauth.d.ts +8 -0
  30. package/dist/integrations/slack-app-home.d.ts +24 -0
  31. package/dist/integrations/slack-bot.d.ts +157 -9
  32. package/dist/integrations/slack-interactions.d.ts +39 -5
  33. package/dist/integrations/slack-routing.d.ts +120 -0
  34. package/dist/integrations/social-oauth.d.ts +5 -0
  35. package/dist/interaction-frame-proxy.d.ts +68 -0
  36. package/dist/mcp/company-brain-governed-writes.d.ts +26 -0
  37. package/dist/mcp/company-profile-agent-admin.d.ts +44 -0
  38. package/dist/mcp/documents.d.ts +1 -0
  39. package/dist/mcp/remember.d.ts +28 -0
  40. package/dist/mcp/request-abort.d.ts +19 -0
  41. package/dist/mcp/scheduled-task-view.d.ts +4 -4
  42. package/dist/mcp/server.d.ts +15 -2
  43. package/dist/mcp/session-view.d.ts +4 -0
  44. package/dist/mcp/session-wait.d.ts +137 -0
  45. package/dist/routes/automations.d.ts +4 -0
  46. package/dist/routes/billing.d.ts +5 -0
  47. package/dist/routes/browser-sessions.d.ts +4 -1
  48. package/dist/routes/company-brain.d.ts +3 -0
  49. package/dist/routes/company-profile.d.ts +2 -1
  50. package/dist/routes/connection-authorities.d.ts +3 -0
  51. package/dist/routes/personal-github-git-broker.d.ts +29 -0
  52. package/dist/routes/personal-github.d.ts +3 -0
  53. package/dist/routes/pr-review.d.ts +3 -0
  54. package/dist/routes/sessions.d.ts +1 -0
  55. package/dist/routes/user-resource-authorities.d.ts +3 -0
  56. package/dist/routes/workspace-capture.d.ts +10 -2
  57. package/dist/routes/workspace-learning.d.ts +3 -0
  58. package/dist/routes/workspaces.d.ts +19 -0
  59. package/dist/sandbox/channel-a.d.ts +11 -1
  60. package/dist/sandbox/connection-authority.d.ts +3 -0
  61. package/dist/sandbox/enrollment.d.ts +2 -0
  62. package/dist/sandbox/machines.d.ts +2 -2
  63. package/dist/sandbox/metrics-ingestion.d.ts +10 -20
  64. package/dist/sandbox/viewer.d.ts +24 -1
  65. package/dist/sandbox-file-artifacts.d.ts +11 -0
  66. package/dist/scheduled-task-deletion.d.ts +14 -0
  67. package/dist/slack-reaction-files.d.ts +1 -1
  68. package/dist/temporal-schedule-cleanup.d.ts +1 -0
  69. package/package.json +20 -18
  70. package/src/api-websocket.ts +23 -0
  71. package/src/app.ts +161 -23
  72. package/src/auth/managed-auth.ts +25 -3
  73. package/src/codemode.ts +53 -23
  74. package/src/codex-realtime.ts +8 -2
  75. package/src/company-brain-okf.ts +340 -0
  76. package/src/connected-machine-computer-access.ts +33 -0
  77. package/src/connection-authority-owner.ts +61 -0
  78. package/src/connection-ownership.ts +180 -0
  79. package/src/controller-data-plane.ts +47 -0
  80. package/src/editable-artifact-native-kernel.ts +26 -15
  81. package/src/editable-artifact-office-import.ts +28 -3
  82. package/src/editable-artifact-production.ts +13 -7
  83. package/src/editable-artifact-websocket.ts +11 -18
  84. package/src/editable-artifact-workspace-files.ts +31 -6
  85. package/src/http/api-error.ts +28 -0
  86. package/src/http/auth.ts +4 -0
  87. package/src/http/cors.ts +35 -0
  88. package/src/http/interaction-control-error.ts +164 -0
  89. package/src/http/sse.ts +112 -66
  90. package/src/index.ts +46 -6
  91. package/src/integrations/atlassian.ts +146 -35
  92. package/src/integrations/fiken.ts +102 -22
  93. package/src/integrations/google-drive.ts +301 -92
  94. package/src/integrations/oauth-client.ts +272 -143
  95. package/src/integrations/oauth-profiles.ts +477 -0
  96. package/src/integrations/personal-github-repositories.ts +445 -0
  97. package/src/integrations/personal-github.ts +705 -0
  98. package/src/integrations/pr-review-provider.ts +246 -0
  99. package/src/integrations/provider-oauth.ts +121 -5
  100. package/src/integrations/slack-app-home.ts +300 -0
  101. package/src/integrations/slack-bot.ts +342 -57
  102. package/src/integrations/slack-interactions.ts +1898 -259
  103. package/src/integrations/slack-routing.ts +337 -0
  104. package/src/integrations/social-oauth.ts +25 -0
  105. package/src/interaction-frame-proxy.ts +409 -0
  106. package/src/mcp/company-brain-governed-writes.ts +262 -0
  107. package/src/mcp/company-profile-agent-admin.ts +205 -0
  108. package/src/mcp/documents.ts +37 -6
  109. package/src/mcp/files.ts +16 -1
  110. package/src/mcp/remember.ts +181 -0
  111. package/src/mcp/request-abort.ts +44 -0
  112. package/src/mcp/scheduled-task-view.ts +1 -0
  113. package/src/mcp/server.ts +719 -369
  114. package/src/mcp/session-view.ts +54 -0
  115. package/src/mcp/session-wait.ts +554 -0
  116. package/src/model-catalog.ts +20 -12
  117. package/src/routes/api-integrations.ts +4 -0
  118. package/src/routes/api-keys.ts +1 -0
  119. package/src/routes/automations.ts +534 -0
  120. package/src/routes/billing.ts +57 -1
  121. package/src/routes/browser-sessions.ts +329 -79
  122. package/src/routes/channels.ts +17 -1
  123. package/src/routes/codex.ts +50 -0
  124. package/src/routes/company-brain.ts +367 -0
  125. package/src/routes/company-profile.ts +1 -1
  126. package/src/routes/computer-sessions.ts +320 -93
  127. package/src/routes/connection-authorities.ts +139 -0
  128. package/src/routes/connections.ts +144 -34
  129. package/src/routes/documents.ts +353 -4
  130. package/src/routes/editable-artifacts.ts +11 -3
  131. package/src/routes/enrollments.ts +116 -26
  132. package/src/routes/environments.ts +127 -55
  133. package/src/routes/files.ts +72 -11
  134. package/src/routes/install.ts +82 -28
  135. package/src/routes/integration-facets.ts +29 -0
  136. package/src/routes/interaction-resources.ts +20 -2
  137. package/src/routes/machines.ts +275 -13
  138. package/src/routes/organization-memberships.ts +717 -28
  139. package/src/routes/packs.ts +4 -3
  140. package/src/routes/personal-github-git-broker.ts +785 -0
  141. package/src/routes/personal-github.ts +319 -0
  142. package/src/routes/pr-review.ts +531 -0
  143. package/src/routes/rigs.ts +104 -39
  144. package/src/routes/scheduled-tasks.ts +19 -21
  145. package/src/routes/sessions.ts +775 -38
  146. package/src/routes/social.ts +14 -2
  147. package/src/routes/supergrok.ts +23 -4
  148. package/src/routes/transcription-recordings.ts +8 -2
  149. package/src/routes/user-resource-authorities.ts +138 -0
  150. package/src/routes/workspace-artifacts.ts +4 -1
  151. package/src/routes/workspace-capture.ts +21 -0
  152. package/src/routes/workspace-learning.ts +228 -0
  153. package/src/routes/workspaces.ts +59 -6
  154. package/src/sandbox/auth-callout.ts +38 -12
  155. package/src/sandbox/channel-a.ts +242 -19
  156. package/src/sandbox/connection-authority.ts +3 -0
  157. package/src/sandbox/enrollment.ts +15 -3
  158. package/src/sandbox/machines.ts +186 -64
  159. package/src/sandbox/metrics-ingestion.ts +220 -58
  160. package/src/sandbox/viewer.ts +243 -19
  161. package/src/sandbox-file-artifacts.ts +329 -0
  162. package/src/scheduled-task-deletion.ts +127 -0
  163. package/src/slack-reaction-files.ts +16 -5
  164. package/src/temporal-schedule-cleanup.ts +13 -0
  165. package/dist/chunk-WCXHI3FF.js.map +0 -1
@@ -0,0 +1,19 @@
1
+ import type { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
2
+ /**
3
+ * Serve one first-party MCP POST and bind the tool handlers' `extra.signal` to
4
+ * the HTTP client's connection.
5
+ *
6
+ * The API builds a fresh transport plus `McpServer` per POST, so an MCP
7
+ * `notifications/cancelled` from the worker would land on a different Protocol
8
+ * instance and never reach the handler. The only cancellation evidence this
9
+ * process can observe is the HTTP request's own abort (`Request.signal`, which
10
+ * Bun fires when the client disconnects). Closing the transport runs the SDK
11
+ * `Protocol._onclose`, which aborts every in-flight request handler's
12
+ * controller, so a blocking tool such as `session_wait` stops promptly when the
13
+ * worker drops the call (Steer, Pause, turn interruption).
14
+ *
15
+ * In JSON-response mode the SDK's `handleRequest` promise never settles once
16
+ * its stream mapping is cleared, so the race resolves a client-gone response
17
+ * instead of leaving the route handler pending.
18
+ */
19
+ export declare function handleMcpRequestWithClientAbort(transport: Pick<WebStandardStreamableHTTPServerTransport, "handleRequest" | "close">, request: Request, clientSignal: AbortSignal | undefined): Promise<Response>;
@@ -137,7 +137,7 @@ export declare function scheduledTaskMcpSummary(task: ScheduledTask): {
137
137
  configuration: {
138
138
  model: string | null;
139
139
  reasoningEffort: "high" | "low" | "max" | "medium" | "minimal" | "none" | "xhigh" | null;
140
- sandboxBackend: "blaxel" | "cloudflare" | "daytona" | "docker" | "e2b" | "local" | "modal" | "none" | "runloop" | "selfhosted" | "vercel" | null;
140
+ sandboxBackend: "blaxel" | "cloudflare" | "daytona" | "docker" | "e2b" | "local" | "modal" | "none" | "opensandbox" | "runloop" | "selfhosted" | "vercel" | null;
141
141
  hasGoal: boolean;
142
142
  promptBytes: number;
143
143
  resourceCount: number;
@@ -260,7 +260,7 @@ export declare function boundScheduledTaskDetailMcp(task: ScheduledTask): {
260
260
  configuration: {
261
261
  model: string | null;
262
262
  reasoningEffort: "high" | "low" | "max" | "medium" | "minimal" | "none" | "xhigh" | null;
263
- sandboxBackend: "blaxel" | "cloudflare" | "daytona" | "docker" | "e2b" | "local" | "modal" | "none" | "runloop" | "selfhosted" | "vercel" | null;
263
+ sandboxBackend: "blaxel" | "cloudflare" | "daytona" | "docker" | "e2b" | "local" | "modal" | "none" | "opensandbox" | "runloop" | "selfhosted" | "vercel" | null;
264
264
  hasGoal: boolean;
265
265
  promptBytes: number;
266
266
  resourceCount: number;
@@ -310,7 +310,7 @@ export declare function boundScheduledTaskDetailMcp(task: ScheduledTask): {
310
310
  metadataKeys: string[];
311
311
  model: string | null;
312
312
  reasoningEffort: "high" | "low" | "max" | "medium" | "minimal" | "none" | "xhigh" | null;
313
- sandboxBackend: "blaxel" | "cloudflare" | "daytona" | "docker" | "e2b" | "local" | "modal" | "none" | "runloop" | "selfhosted" | "vercel" | null;
313
+ sandboxBackend: "blaxel" | "cloudflare" | "daytona" | "docker" | "e2b" | "local" | "modal" | "none" | "opensandbox" | "runloop" | "selfhosted" | "vercel" | null;
314
314
  goal: {
315
315
  text: string;
316
316
  successCriteria: string | null;
@@ -444,7 +444,7 @@ export declare function boundScheduledTaskMcpPage(input: {
444
444
  configuration: {
445
445
  model: string | null;
446
446
  reasoningEffort: "high" | "low" | "max" | "medium" | "minimal" | "none" | "xhigh" | null;
447
- sandboxBackend: "blaxel" | "cloudflare" | "daytona" | "docker" | "e2b" | "local" | "modal" | "none" | "runloop" | "selfhosted" | "vercel" | null;
447
+ sandboxBackend: "blaxel" | "cloudflare" | "daytona" | "docker" | "e2b" | "local" | "modal" | "none" | "opensandbox" | "runloop" | "selfhosted" | "vercel" | null;
448
448
  hasGoal: boolean;
449
449
  promptBytes: number;
450
450
  resourceCount: number;
@@ -1,4 +1,4 @@
1
- import { type AccessGrant, type SessionAuthorizationActor, type WorkspaceMemoryPromptMode } from "@opengeni/contracts";
1
+ import { type AccessGrant, type GitHubRepository, type ResourceRef, type SessionAuthorizationActor, type WorkspaceMemoryPromptMode } from "@opengeni/contracts";
2
2
  import { listSessionDiscoverySummaries, type SessionDiscoveryCursor, type SessionDiscoveryOrderBy } from "@opengeni/db";
3
3
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
4
  import type { ApiRouteDeps } from "@opengeni/core";
@@ -45,6 +45,16 @@ export declare function memorySlackPublicationActor(actor: Extract<SessionAuthor
45
45
  };
46
46
  ownerLabel: string | null;
47
47
  };
48
+ /**
49
+ * Project one allowlisted GitHub App repository into the resource an agent or
50
+ * scheduled task attaches. Every listed repository is in the workspace
51
+ * allowlist, public or private, so every resource carries the stable ids
52
+ * that mint the scoped installation token; a bare URI would clone anonymously
53
+ * and could never push.
54
+ */
55
+ export declare function repositoryWithScheduledTaskResource(repository: GitHubRepository): GitHubRepository & {
56
+ resource: ResourceRef;
57
+ };
48
58
  export declare function encodeSessionDiscoveryCursor(cursor: SessionDiscoveryCursor): string;
49
59
  export declare function decodeSessionDiscoveryCursor(value: string): SessionDiscoveryCursor;
50
60
  export declare function capSessionDiscoveryPage(page: Awaited<ReturnType<typeof listSessionDiscoverySummaries>>, includeLastMessage: boolean): {
@@ -79,10 +89,13 @@ export declare function capSessionDiscoveryPage(page: Awaited<ReturnType<typeof
79
89
  attentionDescendants: number;
80
90
  pausedDescendants: number;
81
91
  failedDescendants: number;
92
+ unreadDescendants?: number | undefined;
93
+ activelyWorkingDescendants?: number | undefined;
94
+ attentionSince?: string | null | undefined;
82
95
  truncated: boolean;
83
96
  };
84
97
  latestMessage?: {
85
- type: "agent.message.completed" | "agent.message.delta" | "agent.model.request" | "agent.model.usage" | "agent.reasoning.delta" | "agent.toolCall.created" | "agent.toolCall.output" | "agent.updated" | "artifact.created" | "codex.account.switched" | "codex.capacity.resumed" | "codex.capacity.superseded" | "codex.capacity.waiting" | "codex.credential.selected" | "codex.fleet.decision" | "credential.auth_needed" | "fs.changed" | "git.changed" | "goal.cleared" | "goal.completed" | "goal.continuation" | "goal.paused" | "goal.progress" | "goal.resumed" | "goal.rewrite.proposed" | "goal.rewrite.rejected" | "goal.set" | "goal.updated" | "machine.link.lost" | "machine.link.restored" | "machine.op.failed" | "machine.op.recovered" | "machine.runner.restarted" | "memory.corrected" | "memory.saved" | "recording.available" | "recording.failed" | "recording.started" | "rig.setup.completed" | "rig.setup.failed" | "rig.setup.skipped" | "rig.setup.started" | "sandbox.box.created" | "sandbox.box.lost" | "sandbox.box.snapshot" | "sandbox.box.terminated" | "sandbox.command.output.delta" | "sandbox.env.drift" | "sandbox.operation.completed" | "sandbox.operation.failed" | "sandbox.operation.started" | "session.context.cleared" | "session.context.compacted" | "session.context.compaction.requested" | "session.context.compaction.skipped" | "session.context.compaction.started" | "session.control.paused" | "session.control.resumed" | "session.control.steer_requested" | "session.created" | "session.event.envelope_omitted" | "session.humanInput.requested" | "session.mcp.approval_policy.updated" | "session.queue.changed" | "session.queue.history" | "session.queue.prompt.cancelled" | "session.realtime.ended" | "session.realtime.started" | "session.requiresAction" | "session.route.reconciled" | "session.status.changed" | "session.title_set" | "session.tool_policy.updated" | "session.visibility.changed" | "stream.closed" | "stream.opened" | "stream.revoked" | "stream.url.rotated" | "system.update.cancelled" | "system.update.delivered" | "system.update.pending" | "system.update.settled" | "system.update.superseded" | "terminal.pty.exited" | "terminal.pty.output.delta" | "terminal.pty.started" | "tool.auth_needed" | "turn.cancelled" | "turn.capacity_waiting" | "turn.completed" | "turn.event.rejected_late" | "turn.failed" | "turn.queued" | "turn.recovery.requested" | "turn.started" | "turn.superseded" | "user.approvalDecision" | "user.humanInputResponse" | "user.message" | "user.pause" | "workspace.inference.paused" | "workspace.inference.resumed" | "workspace.revision.captured" | "workspace.revision.degraded";
98
+ type: "agent.message.completed" | "agent.message.delta" | "agent.model.request" | "agent.model.usage" | "agent.reasoning.delta" | "agent.toolCall.created" | "agent.toolCall.output" | "agent.updated" | "artifact.created" | "codex.account.switched" | "codex.capacity.resumed" | "codex.capacity.superseded" | "codex.capacity.waiting" | "codex.credential.selected" | "codex.fleet.decision" | "credential.auth_needed" | "fs.changed" | "git.changed" | "goal.cleared" | "goal.completed" | "goal.continuation" | "goal.held" | "goal.paused" | "goal.progress" | "goal.resumed" | "goal.rewrite.proposed" | "goal.rewrite.rejected" | "goal.set" | "goal.updated" | "machine.link.lost" | "machine.link.restored" | "machine.op.failed" | "machine.op.recovered" | "machine.runner.restarted" | "memory.corrected" | "memory.saved" | "recording.available" | "recording.failed" | "recording.started" | "rig.setup.completed" | "rig.setup.failed" | "rig.setup.skipped" | "rig.setup.started" | "sandbox.box.created" | "sandbox.box.lost" | "sandbox.box.snapshot" | "sandbox.box.terminated" | "sandbox.command.output.delta" | "sandbox.env.drift" | "sandbox.operation.completed" | "sandbox.operation.failed" | "sandbox.operation.started" | "session.command.backgrounded" | "session.command.finished" | "session.context.cleared" | "session.context.compacted" | "session.context.compaction.requested" | "session.context.compaction.skipped" | "session.context.compaction.started" | "session.control.paused" | "session.control.resumed" | "session.control.steer_requested" | "session.created" | "session.event.envelope_omitted" | "session.humanInput.requested" | "session.mcp.approval_policy.updated" | "session.personal_resources.attached" | "session.queue.changed" | "session.queue.history" | "session.queue.prompt.cancelled" | "session.realtime.ended" | "session.realtime.started" | "session.requiresAction" | "session.route.reconciled" | "session.status.changed" | "session.title_set" | "session.tool_policy.updated" | "session.visibility.changed" | "stream.closed" | "stream.opened" | "stream.revoked" | "stream.url.rotated" | "system.update.cancelled" | "system.update.delivered" | "system.update.pending" | "system.update.settled" | "system.update.superseded" | "terminal.pty.exited" | "terminal.pty.output.delta" | "terminal.pty.started" | "tool.auth_needed" | "turn.cancelled" | "turn.capacity_waiting" | "turn.completed" | "turn.event.rejected_late" | "turn.failed" | "turn.queued" | "turn.recovery.requested" | "turn.started" | "turn.startup.phase.completed" | "turn.startup.phase.failed" | "turn.startup.phase.started" | "turn.superseded" | "user.approvalDecision" | "user.humanInputResponse" | "user.message" | "user.pause" | "workspace.inference.paused" | "workspace.inference.resumed" | "workspace.revision.captured" | "workspace.revision.degraded";
86
99
  preview: string | null;
87
100
  previewTruncated: boolean;
88
101
  } | null;
@@ -93,6 +93,7 @@ export declare function boundSessionDetailMcp(session: Session, effectiveControl
93
93
  rigId: string | null;
94
94
  rigVersionId: string | null;
95
95
  firstPartyMcpPermissions: unknown;
96
+ effectiveToolPolicy: unknown;
96
97
  mcpServers: unknown;
97
98
  parentSessionId: string | null;
98
99
  createIdempotencyKey: string | null;
@@ -118,6 +119,9 @@ export declare function boundSessionDetailMcp(session: Session, effectiveControl
118
119
  attentionDescendants: number;
119
120
  pausedDescendants: number;
120
121
  failedDescendants: number;
122
+ unreadDescendants?: number | undefined;
123
+ activelyWorkingDescendants?: number | undefined;
124
+ attentionSince?: string | null | undefined;
121
125
  truncated: boolean;
122
126
  };
123
127
  createdAt: string;
@@ -0,0 +1,137 @@
1
+ /**
2
+ * `session_wait`: one blocking first-party MCP call that replaces the
3
+ * `sleep 55` plus three or four `session_events`/`session_get` probes an agent
4
+ * otherwise runs per loop while it waits for a child or peer session.
5
+ *
6
+ * The durable `session_events` table is the only authority. The NATS event bus
7
+ * is live fanout only, so every wake (bus, deadline, or the initial call) is
8
+ * followed by a database read and the returned rows are always the exact
9
+ * durable events, never the bus payload. Subscriptions are opened before the
10
+ * first read so an event committed between the read and the subscription
11
+ * cannot be missed.
12
+ *
13
+ * Timing facts: the built-in `opengeni` MCP server entry carries no
14
+ * `timeoutMs`, so the worker's MCP client uses the SDK default request timeout
15
+ * of 60 s and a longer call would surface as a `-32001` tool error. The wait is
16
+ * therefore capped at {@link SESSION_WAIT_MAX_SECONDS} both in the tool schema
17
+ * and inside {@link waitForSessionChanges}. The API's `Bun.serve`
18
+ * `idleTimeout` is 255 s, far above that cap.
19
+ *
20
+ * Cancellation: the API serves one transport per POST, so the worker's MCP
21
+ * `notifications/cancelled` never reaches this handler; instead the route binds
22
+ * the HTTP request's own abort to `transport.close()` (`request-abort.ts`),
23
+ * which aborts `extra.signal`. A worker that drops the call on Steer/Pause
24
+ * therefore ends the server-side wait promptly; the deadline bounds it anyway.
25
+ *
26
+ * The live bus is best-effort: a failed subscription degrades the wait to the
27
+ * durable pre-check plus the deadline re-check and is reported as
28
+ * `liveFanout: false` rather than failing the tool.
29
+ */
30
+ import type { SessionEvent, SessionEventSemanticClass, SessionEventType } from "@opengeni/contracts";
31
+ export declare const SESSION_WAIT_MAX_TARGETS = 16;
32
+ export declare const SESSION_WAIT_MAX_SECONDS = 50;
33
+ export declare const SESSION_WAIT_DEFAULT_SECONDS = 45;
34
+ /** Newest-first durable rows read per target on every database check. */
35
+ export declare const SESSION_WAIT_EVENTS_PER_TARGET = 20;
36
+ /**
37
+ * The durable event types that matter to a waiter: turn lifecycle, completed
38
+ * agent messages, blocking failures, goal facts, and session status/control
39
+ * changes. Raw deltas, tool receipts, sandbox/machine diagnostics, and PTY
40
+ * noise never wake a waiter; `session_events` remains the drill-down for them.
41
+ */
42
+ export declare const SESSION_WAIT_EVENT_TYPES: readonly ["turn.started", "turn.completed", "turn.failed", "turn.cancelled", "turn.superseded", "turn.capacity_waiting", "agent.message.completed", "session.status.changed", "session.requiresAction", "session.humanInput.requested", "session.control.paused", "session.control.resumed", "tool.auth_needed", "credential.auth_needed", "rig.setup.failed", "goal.set", "goal.updated", "goal.progress", "goal.rewrite.proposed", "goal.rewrite.rejected", "goal.completed", "goal.paused", "goal.resumed", "goal.cleared", "goal.continuation"];
43
+ /** The self-session event that announces a newly pending machine input. */
44
+ export declare const SESSION_WAIT_OWN_PENDING_EVENT_TYPE = "system.update.pending";
45
+ /**
46
+ * Whether a pending own machine input of this kind ends the wait. Every
47
+ * pre-existing kind and `child_requires_action` are `immediate`; deferred
48
+ * child notices are reported but do not end the wait by themselves.
49
+ */
50
+ export declare function ownPendingKindWakes(kind: string): boolean;
51
+ export declare function sessionWaitSemanticClass(type: SessionEventType): SessionEventSemanticClass;
52
+ export type SessionWaitTarget = {
53
+ sessionId: string;
54
+ afterSequence: number;
55
+ };
56
+ export type SessionWaitEventSummary = {
57
+ id: string;
58
+ sequence: number;
59
+ type: SessionEventType;
60
+ occurredAt: string;
61
+ turnId: string | null;
62
+ turnGeneration: number | null;
63
+ status: string;
64
+ text: string | null;
65
+ failure: {
66
+ error: string | null;
67
+ code: string | null;
68
+ retryable: boolean | null;
69
+ recovery: string | null;
70
+ } | null;
71
+ result?: unknown;
72
+ };
73
+ export type SessionWaitTargetResult = {
74
+ sessionId: string;
75
+ afterSequence: number;
76
+ /** Cursor for the next `session_wait`/`session_events after=` call. */
77
+ latestSequence: number;
78
+ hasMore: boolean;
79
+ events: SessionWaitEventSummary[];
80
+ };
81
+ export type SessionWaitResult = {
82
+ changed: SessionWaitTargetResult[];
83
+ ownPendingUpdates: number;
84
+ ownPendingUpdateKinds: string[];
85
+ /**
86
+ * Pending own inputs whose kind wakes the session by itself (every
87
+ * pre-existing kind plus `child_requires_action`). Only these end the wait;
88
+ * `deferred` child notices (resolution, pause, capacity wait, progress) are
89
+ * reported but keep the wait on the targets.
90
+ */
91
+ ownPendingImmediateUpdates: number;
92
+ ownPendingDeferredUpdateKinds: string[];
93
+ waitedMs: number;
94
+ timedOut: boolean;
95
+ aborted: boolean;
96
+ /** False when at least one live-fanout subscription failed; the wait then relied on the deadline re-check. */
97
+ liveFanout: boolean;
98
+ truncated: boolean;
99
+ bytes: number;
100
+ maxBytes: number;
101
+ };
102
+ export type SessionWaitTargetRead = {
103
+ events: readonly SessionEvent[];
104
+ hasMore: boolean;
105
+ };
106
+ export type SessionWaitSource = {
107
+ /** Durable forward read of matching events strictly after the target cursor. */
108
+ readTargetEvents: (target: SessionWaitTarget) => Promise<SessionWaitTargetRead>;
109
+ /** Kinds of the caller's own pending machine inputs; null disables self tracking. */
110
+ readOwnPendingUpdateKinds: (() => Promise<readonly string[]>) | null;
111
+ /** Live fanout subscription for one session; the returned function unsubscribes. */
112
+ subscribe: (sessionId: string, onEvents: (events: SessionEvent[]) => void | Promise<void>) => Promise<() => void>;
113
+ /**
114
+ * Re-run target authorization for the sessions about to be returned after a
115
+ * wait (parity with SSE re-authorization). Throws to refuse the result.
116
+ */
117
+ reauthorizeTargets?: ((sessionIds: readonly string[]) => Promise<void>) | undefined;
118
+ };
119
+ export type SessionWaitInput = {
120
+ targets: readonly SessionWaitTarget[];
121
+ ownSessionId: string | null;
122
+ maxWaitMs: number;
123
+ source: SessionWaitSource;
124
+ signal?: AbortSignal | undefined;
125
+ now?: (() => number) | undefined;
126
+ maxBytes?: number | undefined;
127
+ };
128
+ export declare function waitForSessionChanges(input: SessionWaitInput): Promise<SessionWaitResult>;
129
+ /** One bounded, result-bearing summary of a durable event for a waiter. */
130
+ export declare function summarizeSessionWaitEvent(event: SessionEvent, textChars?: number): SessionWaitEventSummary;
131
+ /**
132
+ * Keep the whole model-visible result at or below the `session_events` MCP
133
+ * envelope. Text is tightened first; only then are newest rows dropped from the
134
+ * largest target, which keeps each target's `latestSequence` an exact cursor
135
+ * for the rows actually delivered and marks the remainder as `hasMore`.
136
+ */
137
+ export declare function boundSessionWaitResult(input: Omit<SessionWaitResult, "truncated" | "bytes" | "maxBytes">, maxBytes?: number): SessionWaitResult;
@@ -0,0 +1,4 @@
1
+ import { type ApiRouteDeps } from "@opengeni/core";
2
+ import type { Hono } from "hono";
3
+ export declare function registerAutomationRoutes(app: Hono, deps: ApiRouteDeps): void;
4
+ export declare function readAutomationWebhookBody(request: Request, maxBytes: number): Promise<Uint8Array>;
@@ -13,4 +13,9 @@ export declare function stripeCheckoutSessionCreateParams(input: {
13
13
  cancelUrl?: string | undefined;
14
14
  idempotencyKey: string;
15
15
  }): Stripe.Checkout.SessionCreateParams;
16
+ export declare function stripeBillingPortalSessionCreateParams(input: {
17
+ customerId: string;
18
+ publicBaseUrl?: string | undefined;
19
+ returnUrl?: string | undefined;
20
+ }): Stripe.BillingPortal.SessionCreateParams;
16
21
  export declare function stripeCustomerProvider(input: ApiRouteDeps | Stripe.Event): "stripe:live" | "stripe:test";
@@ -2,7 +2,10 @@ import { InteractionActor, type AccessGrant, type FileAsset } from "@opengeni/co
2
2
  import { type ApiRouteDeps, type ResolvedSessionAuthorization } from "@opengeni/core";
3
3
  import type { Hono } from "hono";
4
4
  export declare function registerBrowserSessionRoutes(app: Hono, deps: ApiRouteDeps): void;
5
- export declare function validateBrowserRequestOrigin(value: string | undefined, allowedPattern: string): string | null;
5
+ export declare function browserNeedsStandaloneDisplayStack(input: {
6
+ headless: boolean;
7
+ linkedComputer: boolean;
8
+ }): boolean;
6
9
  export declare function interactionActorForGrant(grant: AccessGrant): ReturnType<typeof InteractionActor.parse>;
7
10
  /** Resolve Drive authority from the same immutable session authorization that
8
11
  * admitted the browser action. Agent-attempt subjects are technical worker
@@ -0,0 +1,3 @@
1
+ import { type ApiRouteDeps } from "@opengeni/core";
2
+ import type { Hono } from "hono";
3
+ export declare function registerCompanyBrainRoutes(app: Hono, deps: ApiRouteDeps): void;
@@ -1,3 +1,4 @@
1
- import { type ApiRouteDeps } from "@opengeni/core";
1
+ import { type AccessGrantAuthorization, type ApiRouteDeps } from "@opengeni/core";
2
2
  import type { Hono } from "hono";
3
+ export declare function requireDirectAccountAdmin(access: AccessGrantAuthorization): void;
3
4
  export declare function registerCompanyProfileRoutes(app: Hono, deps: ApiRouteDeps): void;
@@ -0,0 +1,3 @@
1
+ import { type ApiRouteDeps } from "@opengeni/core";
2
+ import type { Hono } from "hono";
3
+ export declare function registerConnectionAuthorityRoutes(app: Hono, deps: ApiRouteDeps): void;
@@ -0,0 +1,29 @@
1
+ import type { ApiRouteDeps } from "@opengeni/core";
2
+ import { type PersonalGitHubGitBrokerClaims, type PersonalGitHubGitBrokerRepositoryClaim } from "@opengeni/github";
3
+ import type { Hono } from "hono";
4
+ export declare const PERSONAL_GITHUB_GIT_BROKER_PATH_PREFIX = "/v1/git/personal/";
5
+ type BrokerOperation = "info_refs" | "upload_pack" | "receive_pack";
6
+ type BrokerRepository = Omit<PersonalGitHubGitBrokerRepositoryClaim, "routeId">;
7
+ type BrokerAuthority = {
8
+ claims: PersonalGitHubGitBrokerClaims;
9
+ repository: BrokerRepository;
10
+ providerPrincipalId: string;
11
+ };
12
+ export type PersonalGitHubGitBrokerServices = {
13
+ openClaims: (token: string) => PersonalGitHubGitBrokerClaims | null;
14
+ resolveAuthority: (claims: PersonalGitHubGitBrokerClaims, routeId: string) => Promise<BrokerAuthority>;
15
+ authorizeProviderRequest: (authority: BrokerAuthority, destinationUrl: string, operation: "identity_verify" | "repository_verify" | BrokerOperation) => Promise<string>;
16
+ fetch: typeof fetch;
17
+ idleTimeoutMs?: number;
18
+ };
19
+ /**
20
+ * Register the three closed Git smart-HTTP operations. These routes are not a
21
+ * product-auth bypass: their only credential is the short-lived encrypted,
22
+ * exact-attempt broker bearer and every physical provider request is fenced
23
+ * again against current database authority.
24
+ */
25
+ export declare function registerPersonalGitHubGitBrokerRoutes(app: Hono, deps: ApiRouteDeps, services?: PersonalGitHubGitBrokerServices): void;
26
+ export declare function isPersonalGitHubGitBrokerPath(pathname: string): boolean;
27
+ export declare function isPersonalGitHubGitBrokerRequest(method: string, pathname: string): boolean;
28
+ export declare function handlePersonalGitHubGitBrokerRequest(request: Request, routeId: string, operation: BrokerOperation, services: PersonalGitHubGitBrokerServices): Promise<Response>;
29
+ export {};
@@ -0,0 +1,3 @@
1
+ import { type ApiRouteDeps } from "@opengeni/core";
2
+ import type { Hono } from "hono";
3
+ export declare function registerPersonalGitHubRoutes(app: Hono, deps: ApiRouteDeps): void;
@@ -0,0 +1,3 @@
1
+ import { type ApiRouteDeps } from "@opengeni/core";
2
+ import type { Hono } from "hono";
3
+ export declare function registerPrReviewRoutes(app: Hono, deps: ApiRouteDeps): void;
@@ -12,6 +12,7 @@ export declare function goalProposalMatchesExpectedRevision(revision: Pick<Sessi
12
12
  * host-managed mode; standalone deployments never consult this classifier.
13
13
  */
14
14
  export declare function sessionAuthorizationOperationForHttp(method: string, pathname: string, sessionId: string): SessionAuthorizationOperation | null;
15
+ export declare function sessionTenancyHttpError(error: unknown): Error;
15
16
  export type AgentTopologyCursorEnvelope = {
16
17
  cursor: SessionDiscoveryCursor;
17
18
  parentSessionId: string | null;
@@ -0,0 +1,3 @@
1
+ import { type ApiRouteDeps } from "@opengeni/core";
2
+ import type { Hono } from "hono";
3
+ export declare function registerUserResourceAuthorityRoutes(app: Hono, deps: ApiRouteDeps): void;
@@ -46,7 +46,15 @@ export declare class WorkspaceCaptureManifestCache {
46
46
  * manifest blob has been GC'd (all graceful cold-fallback states — never errors).
47
47
  * Inline manifest for ≤2MB, signed URL above.
48
48
  */
49
- export declare function serveWorkspaceCapture(row: WorkspaceCaptureRow | null, storage: CaptureStoragePort, cache?: WorkspaceCaptureManifestCache): Promise<GetWorkspaceCaptureResponse>;
49
+ /** Awaited before a signed capture URL is returned to the caller: the route
50
+ * records the metadata-only issuance audit fact. A throwing recorder fails
51
+ * the serve closed - no recorded fact, no bearer capability. */
52
+ export type CaptureSignedUrlIssuanceRecorder = (fact: {
53
+ kind: "capture_manifest" | "capture_file";
54
+ revision: number;
55
+ expiresAt: string;
56
+ }) => Promise<void>;
57
+ export declare function serveWorkspaceCapture(row: WorkspaceCaptureRow | null, storage: CaptureStoragePort, cache?: WorkspaceCaptureManifestCache, onSignedUrlIssued?: CaptureSignedUrlIssuanceRecorder): Promise<GetWorkspaceCaptureResponse>;
50
58
  /**
51
59
  * Shape the GET …/workspace/capture/file response from a loaded row (the row
52
60
  * already resolved to the requested revision, or the latest). Throws
@@ -55,5 +63,5 @@ export declare function serveWorkspaceCapture(row: WorkspaceCaptureRow | null, s
55
63
  * a captured file whose after-image blob is missing). Inline content for ≤256KB,
56
64
  * signed URL above.
57
65
  */
58
- export declare function serveWorkspaceCaptureFile(row: WorkspaceCaptureRow | null, path: string, storage: CaptureStoragePort): Promise<GetWorkspaceCaptureFileResponse>;
66
+ export declare function serveWorkspaceCaptureFile(row: WorkspaceCaptureRow | null, path: string, storage: CaptureStoragePort, onSignedUrlIssued?: CaptureSignedUrlIssuanceRecorder): Promise<GetWorkspaceCaptureFileResponse>;
59
67
  export {};
@@ -0,0 +1,3 @@
1
+ import { type ApiRouteDeps } from "@opengeni/core";
2
+ import type { Hono } from "hono";
3
+ export declare function registerWorkspaceLearningRoutes(app: Hono, deps: ApiRouteDeps): void;
@@ -1,5 +1,24 @@
1
+ import { type WorkspaceMember as WorkspaceMemberValue } from "@opengeni/contracts";
1
2
  import type { Hono } from "hono";
2
3
  import type { ApiRouteDeps } from "@opengeni/core";
3
4
  import { type Settings } from "@opengeni/config";
4
5
  export declare function canonicalWorkspacePolicyModelIds(settings: Settings, modelIds: string[] | null | undefined): string[] | null;
6
+ type WorkspaceMemberProjectionInput = Omit<WorkspaceMemberValue, "permissions"> & {
7
+ permissions: unknown;
8
+ };
9
+ /**
10
+ * Keep the roster readable across stored-permission contract changes. Unknown
11
+ * values are never re-authorized: they are omitted from the public projection,
12
+ * while every currently recognized permission is preserved in stored order.
13
+ */
14
+ export declare function workspaceMembersResponse(members: readonly WorkspaceMemberProjectionInput[]): {
15
+ members: {
16
+ subjectId: string;
17
+ subjectLabel: string | null;
18
+ role: string;
19
+ permissions: ("account:admin" | "account:read" | "api_keys:manage" | "artifacts:publish" | "artifacts:read" | "billing:manage" | "billing:read" | "codemode:call" | "connections:read" | "connections:write" | "documents:manage" | "documents:search" | "enrollments:manage" | "enrollments:read" | "environments:manage" | "environments:use" | "files:read" | "files:upload" | "files:write" | "github:manage" | "github:use" | "goals:manage" | "mcp_servers:attach" | "members:manage" | "rigs:manage" | "rigs:use" | "scheduled_tasks:manage" | "scheduled_tasks:run" | "secrets:list" | "secrets:read" | "secrets:write" | "sessions:control" | "sessions:create" | "sessions:read" | "stream:acknowledge" | "stream:control" | "stream:view" | "terminal:attach" | "variable-sets:attach" | "variable-sets:list" | "variable-sets:manage" | "variable-sets:read" | "variable-sets:use" | "variable-sets:write" | "workspace:admin" | "workspace:create" | "workspace:read")[];
20
+ createdAt: string;
21
+ }[];
22
+ };
5
23
  export declare function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void;
24
+ export {};
@@ -10,7 +10,7 @@ export type ChannelAServices = {
10
10
  bus: EventBus;
11
11
  observability?: Observability | undefined;
12
12
  };
13
- export type ChannelAOperation = "fs.list" | "fs.list-batch" | "fs.read" | "fs.write" | "fs.delete" | "fs.move" | "fs.mkdir" | "git.status" | "git.diff" | "git.read-batch" | "git.log" | "git.show" | "terminal.exec" | "terminal.pty.open" | "terminal.pty.write" | "terminal.pty.resize" | "terminal.pty.close" | "browser.create" | "browser.resume" | "browser.suspend" | "browser.end" | "browser.read" | "browser.action" | "browser.control" | "browser.download.save" | "browser.attach" | "computer.create" | "computer.end" | "computer.read" | "computer.action" | "computer.control" | "computer.attach";
13
+ export type ChannelAOperation = "fs.list" | "fs.list-batch" | "fs.read" | "artifact.publish" | "fs.write" | "fs.delete" | "fs.move" | "fs.mkdir" | "git.status" | "git.diff" | "git.read-batch" | "git.log" | "git.show" | "terminal.exec" | "terminal.pty.open" | "terminal.pty.write" | "terminal.pty.resize" | "terminal.pty.close" | "browser.create" | "browser.resume" | "browser.suspend" | "browser.end" | "browser.read" | "browser.action" | "browser.control" | "browser.download.save" | "browser.attach" | "computer.create" | "computer.end" | "computer.read" | "computer.action" | "computer.control" | "computer.attach";
14
14
  export type ChannelAContext = {
15
15
  accountId: string;
16
16
  workspaceId: string;
@@ -100,4 +100,14 @@ export declare function isChannelARequestCancellation(error: unknown, waitSignal
100
100
  /** Structural classification only: exact provider exception text, codes, URLs,
101
101
  * and identifiers never cross the telemetry boundary. */
102
102
  export declare function channelAOperationFailureDiagnostic(error: unknown, waitSignal?: AbortSignal): ChannelAOperationFailureDiagnostic;
103
+ /** Exported for the telemetry contract tests; not a route surface. */
104
+ export declare function observeChannelAOperationFailure(services: ChannelAServices, input: {
105
+ workspaceId: string;
106
+ sandboxGroupId: string;
107
+ backend: string;
108
+ operation: string;
109
+ durationMs: number;
110
+ error: unknown;
111
+ waitSignal?: AbortSignal | undefined;
112
+ }): void;
103
113
  export {};
@@ -0,0 +1,3 @@
1
+ /** Five-second heartbeats get four missed intervals before another daemon may
2
+ * claim the enrollment. Server time is authoritative. */
3
+ export declare const AGENT_CONNECTION_LEASE_MS = 20000;
@@ -35,6 +35,8 @@ export declare function startDeviceEnrollment(services: EnrollmentServices, inpu
35
35
  export declare function approveDeviceEnrollment(services: EnrollmentServices, input: {
36
36
  accountId: string;
37
37
  workspaceId: string;
38
+ scope?: "organization" | "workspace" | "user";
39
+ allowOrganization?: boolean;
38
40
  userCode: string;
39
41
  allowScreenControl: boolean;
40
42
  approvedBySubjectId: string;
@@ -1,11 +1,9 @@
1
1
  import type { Settings } from "@opengeni/config";
2
2
  import { type Database, type MachineMetricsRow } from "@opengeni/db";
3
- import type { EventBus } from "@opengeni/events";
4
3
  import { MetricSample, type MachinesResponse } from "@opengeni/contracts";
5
4
  export type MachinesServices = {
6
5
  db: Database;
7
6
  settings: Settings;
8
- bus?: EventBus;
9
7
  };
10
8
  /**
11
9
  * Project a stored `machine_metrics_latest` row to the contract `MetricSample`.
@@ -24,6 +22,8 @@ export declare function metricRowToSample(row: MachineMetricsRow): MetricSample;
24
22
  * the enrolled machines are listed.
25
23
  */
26
24
  export declare function listMachines(services: MachinesServices, input: {
25
+ accountId?: string;
27
26
  workspaceId: string;
27
+ subjectId?: string;
28
28
  sessionId?: string | null;
29
29
  }): Promise<MachinesResponse>;
@@ -4,18 +4,20 @@ import { type EventBus } from "@opengeni/events";
4
4
  import type { Observability } from "@opengeni/observability";
5
5
  import { Hello, type AttachedBrowserInventorySnapshot as WireAttachedBrowserInventorySnapshot, type MetricsSample } from "@opengeni/agent-proto";
6
6
  /** The wildcard subject the agent event plane publishes heartbeats on. */
7
- export declare const AGENT_EVENTS_SUBJECT = "agent.*.*.events";
7
+ export declare const AGENT_EVENTS_SUBJECT = "agent.*.*.connection.*.events";
8
8
  /** The wildcard subject the agent publishes its connect Hello on. */
9
- export declare const AGENT_HELLO_SUBJECT = "agent.*.*.hello";
10
- /** Parse `agent.<ws>.<id>.events` `{ workspaceId, agentId }` (heartbeat plane). */
9
+ export declare const AGENT_HELLO_SUBJECT = "agent.*.*.connection.*.hello";
10
+ /** Parse the exact process events subject (heartbeat plane). */
11
11
  export declare function parseAgentEventSubject(subject: string): {
12
12
  workspaceId: string;
13
13
  agentId: string;
14
+ connectionInstanceId: string;
14
15
  } | null;
15
- /** Parse `agent.<ws>.<id>.hello` `{ workspaceId, agentId }` (connect plane). */
16
+ /** Parse the exact process hello subject (connect plane). */
16
17
  export declare function parseAgentHelloSubject(subject: string): {
17
18
  workspaceId: string;
18
19
  agentId: string;
20
+ connectionInstanceId: string;
19
21
  } | null;
20
22
  /**
21
23
  * Project a wire `MetricsSample` (proto, ms-stamped, GPU as a repeated list) to
@@ -32,20 +34,6 @@ export declare function wireSampleToDbSample(wire: MetricsSample): MachineMetric
32
34
  * discovery. Unknown enum values and unsafe uint64 counters reject the whole
33
35
  * authoritative snapshot instead of partially disconnecting good endpoints. */
34
36
  export declare function wireAttachedBrowserInventoryToContract(wire: WireAttachedBrowserInventorySnapshot): AttachedBrowserInventoryContractValue;
35
- /**
36
- * Ingest ONE decoded heartbeat for an enrolled machine. Resolves the enrollment's
37
- * accountId (needed for the RLS-scoped writes) from the enrollment row; an
38
- * unknown/cross-workspace agentId is ignored (no row → no write). Touches
39
- * last-seen + upserts latest + downsamples the series.
40
- */
41
- export declare function ingestHeartbeat(db: Database, input: {
42
- workspaceId: string;
43
- agentId: string;
44
- sample: MetricsSample;
45
- }): Promise<{
46
- ingested: boolean;
47
- seriesAppended: boolean;
48
- }>;
49
37
  /**
50
38
  * Decode a raw `AgentEvent` payload + ingest it (the per-message handler). A
51
39
  * heartbeat carrying a metrics sample is ingested; a going-offline records the
@@ -55,7 +43,7 @@ export declare function ingestHeartbeat(db: Database, input: {
55
43
  */
56
44
  export declare function handleAgentEventPayload(db: Database, observability: Observability | undefined, payload: Uint8Array, subject: string, bus?: EventBus): Promise<void>;
57
45
  /**
58
- * Start the metrics-ingestion consumer: subscribe `agent.*.*.events` and ingest
46
+ * Start the metrics-ingestion consumer: subscribe exact process events and ingest
59
47
  * every heartbeat. Gated by sandboxSelfhostedEnabled (the caller checks the flag;
60
48
  * a disabled deployment never starts the consumer). Returns the unsubscribe fn.
61
49
  */
@@ -95,6 +83,7 @@ export declare function refreshEnrollmentDisplay(db: Database, input: {
95
83
  agentId: string;
96
84
  hasDisplay: boolean;
97
85
  desktopUnavailableReason?: string | null;
86
+ connectionInstanceId?: string;
98
87
  }): Promise<{
99
88
  updated: boolean;
100
89
  }>;
@@ -108,6 +97,7 @@ export declare function refreshEnrollmentOpStream(db: Database, input: {
108
97
  workspaceId: string;
109
98
  agentId: string;
110
99
  opStream: boolean;
100
+ connectionInstanceId?: string;
111
101
  }): Promise<{
112
102
  updated: boolean;
113
103
  }>;
@@ -121,7 +111,7 @@ export declare function refreshEnrollmentOpStream(db: Database, input: {
121
111
  */
122
112
  export declare function handleHelloPayload(db: Database, observability: Observability | undefined, payload: Uint8Array, subject: string, bus?: EventBus): Promise<void>;
123
113
  /**
124
- * Start the Hello display-refresh consumer: subscribe `agent.*.*.hello` and
114
+ * Start the Hello display-refresh consumer: subscribe exact process hellos and
125
115
  * reconcile `has_display` to the live capability the agent reports on every
126
116
  * connect. Gated by sandboxSelfhostedEnabled (the caller checks the flag). Returns
127
117
  * the unsubscribe fn.
@@ -51,7 +51,10 @@ export type ViewerAttachResult = {
51
51
  * cannot change manifest environment variables" whenever a viewer attach (an open
52
52
  * session page) won the cold-create race against the first turn.
53
53
  */
54
- export declare function sessionAttachEnvironment(services: ViewerServices, workspaceId: string, session: Session): Promise<Record<string, string>>;
54
+ export declare function sessionAttachEnvironment(services: ViewerServices, workspaceId: string, session: Session,
55
+ /** The authenticated route subject driving this attach (0282); recorded on
56
+ * the materialization audit fact. Null records the legacy service sentinel. */
57
+ attachSubjectId: string | null): Promise<Record<string, string>>;
55
58
  /**
56
59
  * Acquire a `viewer` holder on the group lease, spinning up the box IN-PROCESS
57
60
  * when cold. Mirrors the worker's resumeBoxForTurn spawner/attached branches,
@@ -65,6 +68,9 @@ export declare function attachViewer(services: ViewerServices, input: {
65
68
  workspaceId: string;
66
69
  session: Session;
67
70
  viewerId?: string;
71
+ /** The authenticated subject attaching this viewer (0281): recorded on
72
+ * the holder row together with the live session authority epoch. */
73
+ viewerSubjectId?: string;
68
74
  /** Cancel lifecycle waiting when the originating HTTP request disconnects. */
69
75
  waitSignal?: AbortSignal;
70
76
  }): Promise<ViewerAttachResult>;
@@ -84,6 +90,10 @@ export declare function ensureSessionGroupReady(services: ViewerServices, input:
84
90
  accountId: string;
85
91
  workspaceId: string;
86
92
  session: Session;
93
+ /** The authenticated subject driving the fleet attach/swap (0282): recorded
94
+ * on the viewer holder and the materialization audit fact. Omitting it
95
+ * records the explicit service sentinel, so forward the route subject. */
96
+ subjectId?: string | null;
87
97
  }): Promise<SessionGroupReadinessHold>;
88
98
  /**
89
99
  * Refresh a viewer holder's TTL (the app-level viewer heartbeat). Epoch-fenced:
@@ -148,6 +158,11 @@ export type DesktopStreamMint = {
148
158
  export type MintDesktopStreamInput = {
149
159
  accountId: string;
150
160
  workspaceId: string;
161
+ resourceSubjectId?: string;
162
+ /** True when the route grant is a signed delegated token (metadata.delegated):
163
+ * its authority is the token, not membership rows, so the mint-time
164
+ * live-authority recheck does not apply. */
165
+ resourceSubjectDelegated?: boolean;
151
166
  session: Session;
152
167
  /** The viewer holder id the scoped token is minted for. */
153
168
  viewerId: string;
@@ -197,6 +212,9 @@ type SelfhostedStreamMint = Omit<TerminalStreamMint, "transport">;
197
212
  export type MintTerminalStreamInput = {
198
213
  accountId: string;
199
214
  workspaceId: string;
215
+ resourceSubjectId?: string;
216
+ /** See MintDesktopStreamInput.resourceSubjectDelegated. */
217
+ resourceSubjectDelegated?: boolean;
200
218
  session: Session;
201
219
  /** The viewer holder / principal id the scoped token is minted for. */
202
220
  viewerId: string;
@@ -233,6 +251,11 @@ export type MintSelfhostedStreamInput = {
233
251
  * THIS as its leaseEpoch claim so the relay rejects a stale-epoch (swapped-away)
234
252
  * viewer. */
235
253
  activeEpoch: number;
254
+ /** 0281 viewer authority claims stamped into the relay stream token. */
255
+ viewerAuthority?: {
256
+ subjectId?: string;
257
+ authorityEpoch: number;
258
+ };
236
259
  /** The exposed stream port (6080 desktop / 7681 terminal). */
237
260
  port: number;
238
261
  /** The resolvable selfhosted session (the routing proxy resolves the active