@opengeni/core 3.0.1 → 3.1.2

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 (257) hide show
  1. package/README.md +4 -4
  2. package/dist/access/index.d.ts +131 -7
  3. package/dist/access/service-initiator.d.ts +3 -0
  4. package/dist/application/archived-session-imports.d.ts +6 -0
  5. package/dist/application/composer-submit.d.ts +1 -1
  6. package/dist/application/connect-operation.d.ts +6 -0
  7. package/dist/application/external-workspace-members.d.ts +13 -1
  8. package/dist/application/modal-native-live-declaration-join.d.ts +37 -0
  9. package/dist/application/modal-native-original-configuration.d.ts +79 -0
  10. package/dist/application/modal-native-worker-host-transport.d.ts +297 -0
  11. package/dist/application/new-session-drafts.d.ts +29 -2
  12. package/dist/application/organization-privacy.d.ts +57 -0
  13. package/dist/application/prepared-mcp-connection.d.ts +31 -0
  14. package/dist/application/sandbox-recovery.d.ts +58 -0
  15. package/dist/application/session-commands.d.ts +3 -0
  16. package/dist/application/session-tenancy.d.ts +13 -4
  17. package/dist/billing/agent-run-admission.d.ts +21 -0
  18. package/dist/billing/limits.d.ts +27 -1
  19. package/dist/billing/model-call-admission.d.ts +34 -0
  20. package/dist/billing/model-usage-settlement.d.ts +112 -0
  21. package/dist/canonical-human-identities.js +1 -1
  22. package/dist/{chunk-VCZFFEPB.js → chunk-7T2SZ7BI.js} +16 -2
  23. package/dist/chunk-7T2SZ7BI.js.map +1 -0
  24. package/dist/{chunk-ZYCNLYGH.js → chunk-OMJFIIWK.js} +178 -12
  25. package/dist/chunk-OMJFIIWK.js.map +1 -0
  26. package/dist/{chunk-H7X52RI2.js → chunk-QI2M2B2K.js} +83 -8
  27. package/dist/chunk-QI2M2B2K.js.map +1 -0
  28. package/dist/{chunk-OF65T3PM.js → chunk-TTWTXQB2.js} +94 -6
  29. package/dist/chunk-TTWTXQB2.js.map +1 -0
  30. package/dist/codex-model-availability.d.ts +55 -0
  31. package/dist/default-session-model.d.ts +192 -0
  32. package/dist/dependencies.d.ts +41 -7
  33. package/dist/developer-setup-credential-ceiling.d.ts +10 -0
  34. package/dist/domain/agent-config-resolution.d.ts +49 -0
  35. package/dist/domain/automations.d.ts +8 -1
  36. package/dist/domain/capabilities.d.ts +112 -8
  37. package/dist/domain/connection-account-selection-error.d.ts +8 -0
  38. package/dist/domain/connector-tool-permissions.d.ts +62 -0
  39. package/dist/domain/direct-model-provider.d.ts +3 -0
  40. package/dist/domain/editable-artifacts/agent-application.d.ts +10 -1
  41. package/dist/domain/editable-artifacts/durable-export.d.ts +22 -1
  42. package/dist/domain/editable-artifacts/ports.d.ts +10 -0
  43. package/dist/domain/editable-artifacts/service.d.ts +3 -1
  44. package/dist/domain/editable-artifacts/types.d.ts +1 -1
  45. package/dist/domain/encryption-key.d.ts +12 -0
  46. package/dist/domain/insights-timing.d.ts +16 -0
  47. package/dist/domain/insights-usage.d.ts +27 -0
  48. package/dist/domain/insights.d.ts +21 -3
  49. package/dist/domain/knowledge-files.d.ts +1 -1
  50. package/dist/domain/knowledge-preparation.d.ts +10 -0
  51. package/dist/domain/knowledge-preparation.test.d.ts +1 -0
  52. package/dist/domain/knowledge-search.d.ts +15 -76
  53. package/dist/domain/mcp-account-bindings.d.ts +17 -0
  54. package/dist/domain/mcp-account-routes.d.ts +21 -0
  55. package/dist/domain/native-mcp-connection-admission.d.ts +3 -0
  56. package/dist/domain/organization-integration-catalog.d.ts +15 -0
  57. package/dist/domain/personal-connection-delegations.d.ts +73 -12
  58. package/dist/domain/pr-review.d.ts +121 -6
  59. package/dist/domain/realtime-voice-billing.d.ts +103 -0
  60. package/dist/domain/resources.d.ts +17 -1
  61. package/dist/domain/scheduled-task-access.d.ts +265 -0
  62. package/dist/domain/scheduled-task-account-audit.d.ts +27 -0
  63. package/dist/domain/scheduled-task-audience.d.ts +70 -0
  64. package/dist/domain/scheduled-tasks.d.ts +61 -18
  65. package/dist/domain/session-connection-accounts.d.ts +53 -0
  66. package/dist/domain/session-file-access.d.ts +4 -0
  67. package/dist/domain/session-native-connection-replacement.d.ts +14 -0
  68. package/dist/domain/session-start-timing.d.ts +7 -0
  69. package/dist/domain/session-tool-policy.d.ts +102 -4
  70. package/dist/domain/sessions.d.ts +179 -15
  71. package/dist/domain/site-audience.d.ts +52 -0
  72. package/dist/domain/skills.d.ts +29 -1
  73. package/dist/domain/slack-bot.d.ts +46 -1
  74. package/dist/domain/slack-publication-secret-safety.d.ts +1 -1
  75. package/dist/domain/vaults/index.d.ts +7 -0
  76. package/dist/domain/vaults/mapping.d.ts +25 -0
  77. package/dist/domain/vaults/provider-registry.d.ts +72 -0
  78. package/dist/domain/vaults/provider-sync.d.ts +176 -0
  79. package/dist/domain/vaults/provider-writes.d.ts +57 -0
  80. package/dist/domain/vaults/secret-resolver.d.ts +34 -0
  81. package/dist/domain/vaults/types.d.ts +24 -0
  82. package/dist/domain/vaults/vault-service.d.ts +35 -0
  83. package/dist/domain/voice-input-billing.d.ts +77 -0
  84. package/dist/domain/web-search-billing.d.ts +51 -0
  85. package/dist/domain/workspace-credits.d.ts +7 -0
  86. package/dist/editable-artifact-live/application.d.ts +2 -1
  87. package/dist/editable-artifact-live/server.d.ts +5 -1
  88. package/dist/editable-artifact-live/ticket.d.ts +2 -1
  89. package/dist/editable-artifact-live/types.d.ts +9 -0
  90. package/dist/editable-artifact-live.js +2 -2
  91. package/dist/editable-artifacts.js +10 -2
  92. package/dist/goal-admission.d.ts +627 -0
  93. package/dist/host-session-usage-limit.d.ts +15 -0
  94. package/dist/index.d.ts +43 -8
  95. package/dist/index.js +22682 -11743
  96. package/dist/index.js.map +1 -1
  97. package/dist/managed-session.d.ts +110 -7
  98. package/dist/model-call.d.ts +58 -0
  99. package/dist/model-catalog.d.ts +29 -3
  100. package/dist/model-provider-credentials.d.ts +43 -0
  101. package/dist/product-usage-metrics.d.ts +30 -0
  102. package/dist/rigs/index.d.ts +1 -13
  103. package/dist/sandbox/fleet.d.ts +58 -4
  104. package/dist/sandbox/routing.d.ts +42 -2
  105. package/dist/sandbox/runtime-settings.d.ts +27 -17
  106. package/dist/session-authorization.d.ts +10 -0
  107. package/dist/session-usage-limit-metrics.d.ts +60 -0
  108. package/dist/session-usage-limits.d.ts +89 -0
  109. package/dist/site-agent-clamp.d.ts +71 -0
  110. package/dist/site-session-origin.d.ts +39 -2
  111. package/dist/transcription.d.ts +120 -3
  112. package/dist/turn-surface.d.ts +20 -0
  113. package/dist/user-presence.d.ts +32 -0
  114. package/dist/workflow-wake-contract.d.ts +13 -1
  115. package/package.json +15 -22
  116. package/src/access/index.ts +961 -38
  117. package/src/access/service-initiator.ts +50 -0
  118. package/src/application/api-integration-servers.ts +9 -0
  119. package/src/application/archived-session-imports.ts +161 -0
  120. package/src/application/composer-submit.ts +3 -2
  121. package/src/application/connect-authority.ts +3 -3
  122. package/src/application/connect-operation.ts +37 -3
  123. package/src/application/external-continuation.ts +20 -3
  124. package/src/application/external-link-work-admission.ts +3 -0
  125. package/src/application/external-workspace-members.ts +51 -3
  126. package/src/application/modal-native-live-declaration-join.ts +196 -0
  127. package/src/application/modal-native-original-configuration.ts +261 -0
  128. package/src/application/modal-native-worker-host-transport.ts +263 -0
  129. package/src/application/new-session-drafts.ts +172 -55
  130. package/src/application/organization-privacy.ts +161 -0
  131. package/src/application/prepared-mcp-connection.ts +133 -0
  132. package/src/application/sandbox-recovery.ts +78 -0
  133. package/src/application/session-commands.ts +73 -1
  134. package/src/application/session-mcp-credential-rotation.ts +61 -18
  135. package/src/application/session-tenancy.ts +262 -44
  136. package/src/application/user-resource-grants.ts +1 -29
  137. package/src/billing/agent-run-admission.ts +117 -0
  138. package/src/billing/limits.ts +138 -14
  139. package/src/billing/model-call-admission.ts +118 -0
  140. package/src/billing/model-usage-settlement.ts +472 -0
  141. package/src/codex-model-availability.ts +264 -0
  142. package/src/default-session-model.ts +692 -0
  143. package/src/dependencies.ts +48 -6
  144. package/src/developer-setup-credential-ceiling.ts +60 -0
  145. package/src/domain/agent-config-resolution.ts +148 -0
  146. package/src/domain/automations.ts +76 -2
  147. package/src/domain/capabilities.ts +830 -181
  148. package/src/domain/connection-account-selection-error.ts +19 -0
  149. package/src/domain/connector-tool-permissions.ts +572 -0
  150. package/src/domain/direct-model-provider.ts +62 -0
  151. package/src/domain/editable-artifacts/agent-application.ts +44 -6
  152. package/src/domain/editable-artifacts/durable-export.ts +100 -5
  153. package/src/domain/editable-artifacts/in-memory.ts +6 -0
  154. package/src/domain/editable-artifacts/ports.ts +11 -0
  155. package/src/domain/editable-artifacts/service.ts +20 -0
  156. package/src/domain/editable-artifacts/types.ts +1 -1
  157. package/src/domain/encryption-key.ts +26 -0
  158. package/src/domain/file-owner.ts +16 -1
  159. package/src/domain/github-action-policies.ts +1 -1
  160. package/src/domain/github-skill-source.ts +3 -1
  161. package/src/domain/insights-timing.ts +95 -0
  162. package/src/domain/insights-usage.ts +67 -0
  163. package/src/domain/insights.ts +167 -43
  164. package/src/domain/knowledge-files.ts +10 -3
  165. package/src/domain/knowledge-messages.ts +1 -0
  166. package/src/domain/knowledge-preparation.test.ts +276 -0
  167. package/src/domain/knowledge-preparation.ts +147 -0
  168. package/src/domain/knowledge-search.test.ts +617 -5
  169. package/src/domain/knowledge-search.ts +240 -23
  170. package/src/domain/mcp-account-bindings.ts +169 -0
  171. package/src/domain/mcp-account-routes.ts +152 -0
  172. package/src/domain/native-mcp-connection-admission.ts +14 -0
  173. package/src/domain/organization-integration-catalog.ts +88 -0
  174. package/src/domain/personal-connection-delegations.ts +399 -257
  175. package/src/domain/pr-review.ts +24 -8
  176. package/src/domain/realtime-voice-billing.ts +425 -0
  177. package/src/domain/resources.ts +50 -4
  178. package/src/domain/scheduled-task-access.ts +1089 -0
  179. package/src/domain/scheduled-task-account-audit.ts +90 -0
  180. package/src/domain/scheduled-task-audience.ts +249 -0
  181. package/src/domain/scheduled-tasks.ts +1313 -374
  182. package/src/domain/session-connection-accounts.ts +239 -0
  183. package/src/domain/session-file-access.ts +47 -0
  184. package/src/domain/session-native-connection-replacement.ts +64 -0
  185. package/src/domain/session-start-timing.ts +60 -0
  186. package/src/domain/session-tool-policy.ts +489 -14
  187. package/src/domain/sessions.ts +2254 -717
  188. package/src/domain/site-audience.ts +130 -0
  189. package/src/domain/skills.ts +9 -0
  190. package/src/domain/slack-bot.ts +141 -4
  191. package/src/domain/slack-publication-secret-safety.ts +1 -1
  192. package/src/domain/vaults/index.ts +19 -0
  193. package/src/domain/vaults/mapping.ts +190 -0
  194. package/src/domain/vaults/provider-registry.ts +201 -0
  195. package/src/domain/vaults/provider-sync.ts +531 -0
  196. package/src/domain/vaults/provider-writes.ts +288 -0
  197. package/src/domain/vaults/secret-resolver.ts +464 -0
  198. package/src/domain/vaults/types.ts +26 -0
  199. package/src/domain/vaults/vault-service.ts +1316 -0
  200. package/src/domain/voice-input-billing.ts +330 -0
  201. package/src/domain/web-search-billing.ts +169 -0
  202. package/src/domain/workspace-credits.ts +13 -0
  203. package/src/editable-artifact-live/application.ts +8 -1
  204. package/src/editable-artifact-live/server.ts +154 -6
  205. package/src/editable-artifact-live/ticket.ts +86 -1
  206. package/src/editable-artifact-live/types.ts +10 -0
  207. package/src/goal-admission.ts +220 -0
  208. package/src/host-session-usage-limit.ts +25 -0
  209. package/src/index.ts +75 -11
  210. package/src/managed-session.ts +137 -6
  211. package/src/model-call.ts +79 -0
  212. package/src/model-catalog.ts +345 -91
  213. package/src/model-provider-credentials.ts +394 -0
  214. package/src/product-usage-metrics.ts +101 -0
  215. package/src/rigs/index.ts +23 -111
  216. package/src/sandbox/fleet.ts +253 -28
  217. package/src/sandbox/routing.ts +204 -43
  218. package/src/sandbox/runtime-settings.ts +159 -85
  219. package/src/session-authorization.ts +172 -23
  220. package/src/session-usage-limit-metrics.ts +95 -0
  221. package/src/session-usage-limits.ts +415 -0
  222. package/src/site-agent-clamp.ts +226 -0
  223. package/src/site-session-origin.ts +84 -5
  224. package/src/transcription.ts +123 -4
  225. package/src/turn-surface.ts +47 -0
  226. package/src/user-presence.ts +134 -0
  227. package/src/workflow-wake-contract.ts +14 -1
  228. package/dist/application/host-mcp-owner.d.ts +0 -6
  229. package/dist/application/host-mcp-resolvers.d.ts +0 -13
  230. package/dist/chunk-5WZYFL45.js +0 -266
  231. package/dist/chunk-5WZYFL45.js.map +0 -1
  232. package/dist/chunk-H7X52RI2.js.map +0 -1
  233. package/dist/chunk-OF65T3PM.js.map +0 -1
  234. package/dist/chunk-VCZFFEPB.js.map +0 -1
  235. package/dist/chunk-ZYCNLYGH.js.map +0 -1
  236. package/dist/domain/connection-authority.d.ts +0 -97
  237. package/dist/domain/connection-authority.js +0 -169
  238. package/dist/domain/connection-authority.js.map +0 -1
  239. package/dist/domain/environments.d.ts +0 -33
  240. package/dist/domain/host-mcp-authority-source-admission.d.ts +0 -10
  241. package/dist/domain/host-mcp-task-admission.d.ts +0 -18
  242. package/dist/domain/packs.d.ts +0 -59
  243. package/dist/domain/product-integration-pack.d.ts +0 -44
  244. package/dist/domain/product-integration-skill.gen.d.ts +0 -5
  245. package/dist/remote-mcp-credentials.d.ts +0 -23
  246. package/dist/remote-mcp-credentials.js +0 -11
  247. package/dist/remote-mcp-credentials.js.map +0 -1
  248. package/src/application/host-mcp-owner.ts +0 -41
  249. package/src/application/host-mcp-resolvers.ts +0 -84
  250. package/src/domain/connection-authority.ts +0 -329
  251. package/src/domain/environments.ts +0 -120
  252. package/src/domain/host-mcp-authority-source-admission.ts +0 -25
  253. package/src/domain/host-mcp-task-admission.ts +0 -121
  254. package/src/domain/packs.ts +0 -699
  255. package/src/domain/product-integration-pack.ts +0 -42
  256. package/src/domain/product-integration-skill.gen.ts +0 -52
  257. package/src/remote-mcp-credentials.ts +0 -361
@@ -0,0 +1,90 @@
1
+ import type { AccessGrant, ScheduledTaskAgentConfig } from "@opengeni/contracts";
2
+ import { recordAuditEvent, type Database } from "@opengeni/db";
3
+ import { isDeepStrictEqual } from "node:util";
4
+
5
+ /** The audit action written whenever a schedule's account or connector choices change. */
6
+ export const SCHEDULED_TASK_ACCOUNT_CHOICES_AUDIT_ACTION = "scheduled_task.account_choices_changed";
7
+
8
+ type Choices = {
9
+ pinnedAccounts: { serverId: string; connectionId: string }[];
10
+ pinnedAccountsRequired: boolean;
11
+ connectors: {
12
+ followsWorkspaceDefaults: boolean;
13
+ excludedMcpServerIds: string[];
14
+ tools: string[];
15
+ };
16
+ };
17
+
18
+ function choicesOf(config: ScheduledTaskAgentConfig | null): Choices {
19
+ return {
20
+ pinnedAccounts: [...(config?.pinnedAccounts ?? [])]
21
+ .map(({ serverId, connectionId }) => ({ serverId, connectionId }))
22
+ .sort((a, b) =>
23
+ a.serverId === b.serverId
24
+ ? a.connectionId.localeCompare(b.connectionId)
25
+ : a.serverId.localeCompare(b.serverId),
26
+ ),
27
+ pinnedAccountsRequired: config?.pinnedAccountsRequired === true,
28
+ connectors: {
29
+ followsWorkspaceDefaults: config?.toolPolicy !== undefined,
30
+ excludedMcpServerIds: [...(config?.toolPolicy?.excludedMcpServerIds ?? [])].sort(),
31
+ tools: (config?.tools ?? [])
32
+ .filter((tool) => tool.kind === "mcp")
33
+ .map((tool) => tool.id)
34
+ .sort(),
35
+ },
36
+ };
37
+ }
38
+
39
+ /**
40
+ * What changed in a schedule's account and connector choices, as audit
41
+ * metadata: each changed choice with its value before and after. Only the
42
+ * choices are recorded (server and connection ids), never a credential or an
43
+ * account label. Returns null when nothing changed; a new schedule without
44
+ * any choice records nothing.
45
+ */
46
+ export function scheduledTaskAccountChoiceChanges(
47
+ before: ScheduledTaskAgentConfig | null,
48
+ after: ScheduledTaskAgentConfig,
49
+ ): Record<string, { before: unknown; after: unknown }> | null {
50
+ const prior = choicesOf(before);
51
+ const next = choicesOf(after);
52
+ const changes: Record<string, { before: unknown; after: unknown }> = {};
53
+ for (const key of ["pinnedAccounts", "pinnedAccountsRequired", "connectors"] as const) {
54
+ if (!isDeepStrictEqual(prior[key], next[key]))
55
+ changes[key] = { before: prior[key], after: next[key] };
56
+ }
57
+ return Object.keys(changes).length > 0 ? changes : null;
58
+ }
59
+
60
+ /**
61
+ * Record a change to a schedule's account or connector choices in the same
62
+ * transaction as the change, with who made it and through which kind of
63
+ * caller (a person, an agent, an API key or a service).
64
+ */
65
+ export async function recordScheduledTaskAccountChoiceChanges(
66
+ tx: Database,
67
+ input: {
68
+ grant: AccessGrant;
69
+ taskId: string;
70
+ operation: "create" | "update";
71
+ before: ScheduledTaskAgentConfig | null;
72
+ after: ScheduledTaskAgentConfig;
73
+ },
74
+ ): Promise<void> {
75
+ const changes = scheduledTaskAccountChoiceChanges(input.before, input.after);
76
+ if (!changes) return;
77
+ await recordAuditEvent(tx, {
78
+ accountId: input.grant.accountId,
79
+ workspaceId: input.grant.workspaceId,
80
+ subjectId: input.grant.subjectId,
81
+ action: SCHEDULED_TASK_ACCOUNT_CHOICES_AUDIT_ACTION,
82
+ targetType: "scheduled_task",
83
+ targetId: input.taskId,
84
+ metadata: {
85
+ operation: input.operation,
86
+ principalKind: input.grant.principalKind ?? null,
87
+ changes,
88
+ },
89
+ });
90
+ }
@@ -0,0 +1,249 @@
1
+ import type {
2
+ AccessGrant,
3
+ PrivateScheduledTaskSummary,
4
+ ScheduledTask,
5
+ SessionVisibility,
6
+ } from "@opengeni/contracts";
7
+ import {
8
+ getPrivateSessionCreatePolicy,
9
+ getScheduledTask,
10
+ getVisibleSessionTenancyVisibility,
11
+ listPrivateScheduledTaskSummaries,
12
+ pausePrivateScheduledTask,
13
+ scheduledTaskViewerSubject,
14
+ type Database,
15
+ } from "@opengeni/db";
16
+ import { HTTPException } from "hono/http-exception";
17
+ import { hasPermission } from "../access";
18
+ import { assertNotSiteClampedAgent } from "../site-agent-clamp";
19
+ import {
20
+ privacyDeploymentLimits,
21
+ resolveOrganizationPrivacy,
22
+ type PrivacySettings,
23
+ } from "../application/organization-privacy";
24
+ import { creationInitiatorForGrant } from "./sessions";
25
+
26
+ /**
27
+ * Who is reading schedules: the person (or the person an agent acts for),
28
+ * whether they administer the workspace, and whether, as an admin, they see
29
+ * that other people's Only me schedules exist. The organization can turn that
30
+ * last part off; a deployment can require it.
31
+ */
32
+ export type ScheduledTaskViewer = {
33
+ subjectId: string | null;
34
+ admin: boolean;
35
+ seesPrivateSummaries: boolean;
36
+ };
37
+
38
+ /**
39
+ * `full`: everything. `summary`: an admin's view of someone else's Only me
40
+ * schedule (owner, cadence, cost) and pause. `none`: indistinguishable from a
41
+ * schedule that does not exist.
42
+ */
43
+ export type ScheduledTaskAccess = "full" | "summary" | "none";
44
+
45
+ export async function scheduledTaskViewerForGrant(
46
+ db: Database,
47
+ grant: AccessGrant,
48
+ settings: PrivacySettings,
49
+ ): Promise<ScheduledTaskViewer> {
50
+ const { subjectId } = await scheduledTaskFullViewerForGrant(db, grant);
51
+ const admin = hasPermission(grant.permissions, "workspace:admin", grant.permissionMode);
52
+ return {
53
+ subjectId,
54
+ admin,
55
+ seesPrivateSummaries:
56
+ admin &&
57
+ (await resolveOrganizationPrivacy({ db, settings }, grant.accountId))
58
+ .adminsSeePrivateSchedules,
59
+ };
60
+ }
61
+
62
+ /**
63
+ * The viewer for a check that only asks "may they see it in full?". Summary
64
+ * access never matters there, so it needs no organization setting.
65
+ */
66
+ async function scheduledTaskFullViewerForGrant(
67
+ db: Database,
68
+ grant: AccessGrant,
69
+ ): Promise<ScheduledTaskViewer> {
70
+ const creator = creationInitiatorForGrant(grant);
71
+ const subjectId = await scheduledTaskViewerSubject(db, {
72
+ workspaceId: grant.workspaceId,
73
+ ...(creator.initiator ? { createdBy: creator.initiator } : {}),
74
+ ...(creator.context ? { createdByContext: creator.context } : {}),
75
+ createdByActor: creator.actor ?? null,
76
+ });
77
+ return { subjectId, admin: false, seesPrivateSummaries: false };
78
+ }
79
+
80
+ export function scheduledTaskAccess(
81
+ viewer: ScheduledTaskViewer,
82
+ task: Pick<ScheduledTask, "visibility" | "ownerSubjectId">,
83
+ ): ScheduledTaskAccess {
84
+ if (task.visibility !== "private") return "full";
85
+ if (viewer.subjectId !== null && task.ownerSubjectId === viewer.subjectId) return "full";
86
+ return viewer.seesPrivateSummaries ? "summary" : "none";
87
+ }
88
+
89
+ function scheduledTaskNotFound(): HTTPException {
90
+ return new HTTPException(404, { message: "scheduled task not found" });
91
+ }
92
+
93
+ /** A schedule this caller may see in full; anything else is a plain 404. */
94
+ export async function requireVisibleScheduledTask(
95
+ db: Database,
96
+ grant: AccessGrant,
97
+ taskId: string,
98
+ viewer?: ScheduledTaskViewer,
99
+ ): Promise<ScheduledTask> {
100
+ const task = await getScheduledTask(db, grant.workspaceId, taskId);
101
+ if (!task) throw scheduledTaskNotFound();
102
+ const resolved = viewer ?? (await scheduledTaskFullViewerForGrant(db, grant));
103
+ if (scheduledTaskAccess(resolved, task) !== "full") throw scheduledTaskNotFound();
104
+ return task;
105
+ }
106
+
107
+ const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
108
+
109
+ /** An admin's summary of someone else's Only me schedule, or null. */
110
+ export async function privateScheduledTaskSummaryForAdmin(
111
+ db: Database,
112
+ grant: AccessGrant,
113
+ taskId: string,
114
+ viewer: ScheduledTaskViewer,
115
+ ): Promise<PrivateScheduledTaskSummary | null> {
116
+ if (!viewer.seesPrivateSummaries || !UUID_PATTERN.test(taskId)) return null;
117
+ const [summary] = await listPrivateScheduledTaskSummaries(db, {
118
+ workspaceId: grant.workspaceId,
119
+ excludeOwnerSubjectId: viewer.subjectId,
120
+ taskId,
121
+ });
122
+ return summary ?? null;
123
+ }
124
+
125
+ /**
126
+ * A schedule this caller may pause: one they see in full, or, for an admin,
127
+ * someone else's Only me schedule, which they only ever see as a summary. That
128
+ * schedule often posts into a chat the admin cannot see, so it is read through
129
+ * the summary and never loaded in full.
130
+ */
131
+ export async function requirePausableScheduledTask(
132
+ db: Database,
133
+ grant: AccessGrant,
134
+ taskId: string,
135
+ viewer: ScheduledTaskViewer,
136
+ ): Promise<
137
+ | { access: "full"; task: ScheduledTask }
138
+ | { access: "summary"; summary: PrivateScheduledTaskSummary }
139
+ > {
140
+ const resolved = viewer;
141
+ const task = await getScheduledTask(db, grant.workspaceId, taskId);
142
+ if (task && scheduledTaskAccess(resolved, task) === "full") return { access: "full", task };
143
+ const summary = await privateScheduledTaskSummaryForAdmin(db, grant, taskId, resolved);
144
+ if (!summary) throw scheduledTaskNotFound();
145
+ return { access: "summary", summary };
146
+ }
147
+
148
+ /**
149
+ * Pause someone else's Only me schedule as a workspace admin and return its
150
+ * refreshed summary. Only its owner can change, run or resume it.
151
+ */
152
+ export async function pausePrivateScheduledTaskAsAdmin(
153
+ db: Database,
154
+ grant: AccessGrant,
155
+ taskId: string,
156
+ viewer: ScheduledTaskViewer,
157
+ ): Promise<PrivateScheduledTaskSummary> {
158
+ await assertNotSiteClampedAgent(db, grant, "schedules");
159
+ if (!viewer.seesPrivateSummaries) throw scheduledTaskNotFound();
160
+ const paused = await pausePrivateScheduledTask(db, {
161
+ workspaceId: grant.workspaceId,
162
+ taskId,
163
+ excludeOwnerSubjectId: viewer.subjectId,
164
+ });
165
+ const summary = paused
166
+ ? await privateScheduledTaskSummaryForAdmin(db, grant, taskId, viewer)
167
+ : null;
168
+ if (!summary) throw scheduledTaskNotFound();
169
+ return summary;
170
+ }
171
+
172
+ export const SCHEDULED_TASK_PRIVATE_TARGET_MESSAGE =
173
+ "This schedule posts into an Only me chat, so it is Only me too.";
174
+ export const SCHEDULED_TASK_PRIVATE_OWNER_MESSAGE = "Only a person can have an Only me schedule.";
175
+ export const SCHEDULED_TASK_PRIVATE_DISABLED_MESSAGE =
176
+ "Only me schedules are turned off for this organization.";
177
+
178
+ /**
179
+ * Whether this person may start something new as Only me in this workspace: a
180
+ * chat, a schedule or a Site. In their Personal workspace, whenever the
181
+ * platform offers private sessions; elsewhere, when the organization allows
182
+ * Only me and the deployment does not turn it off.
183
+ */
184
+ export async function mayStartOnlyMe(
185
+ db: Database,
186
+ settings: PrivacySettings,
187
+ workspaceId: string,
188
+ subjectId: string,
189
+ ): Promise<boolean> {
190
+ const policy = await getPrivateSessionCreatePolicy(db, {
191
+ workspaceId,
192
+ actorSubjectId: subjectId,
193
+ }).catch(() => null);
194
+ return policy
195
+ ? policy.personalWorkspace
196
+ ? policy.platformAvailable
197
+ : policy.organizationEnabled && privacyDeploymentLimits(settings).onlyMeAllowed
198
+ : false;
199
+ }
200
+
201
+ /**
202
+ * The audience to store for a created or edited schedule. A schedule that
203
+ * posts into an Only me chat, or writes to its owner's personal knowledge, is
204
+ * always Only me. Choosing Only me needs a human owner who may create Only me
205
+ * chats in this workspace.
206
+ */
207
+ export async function resolveScheduledTaskVisibility(input: {
208
+ db: Database;
209
+ settings: PrivacySettings;
210
+ grant: AccessGrant;
211
+ requested: SessionVisibility | undefined;
212
+ current: Pick<ScheduledTask, "visibility"> | null;
213
+ targetSessionId: string | null;
214
+ personalKnowledge: boolean;
215
+ ownerSubjectId: string | null;
216
+ }): Promise<"user_private" | "workspace_shared"> {
217
+ const targetPrivate =
218
+ input.targetSessionId !== null &&
219
+ (await getVisibleSessionTenancyVisibility(
220
+ input.db,
221
+ input.grant.workspaceId,
222
+ input.targetSessionId,
223
+ )) === "user_private";
224
+ const forced = targetPrivate || input.personalKnowledge;
225
+ if (forced && input.requested === "workspace")
226
+ throw new HTTPException(422, {
227
+ message: targetPrivate
228
+ ? SCHEDULED_TASK_PRIVATE_TARGET_MESSAGE
229
+ : "This schedule saves to your personal knowledge, so it is Only me.",
230
+ });
231
+ const wanted = forced ? "private" : (input.requested ?? input.current?.visibility ?? "workspace");
232
+ if (wanted === "workspace") return "workspace_shared";
233
+ if (!input.ownerSubjectId)
234
+ throw new HTTPException(422, { message: SCHEDULED_TASK_PRIVATE_OWNER_MESSAGE });
235
+ // Narrowing an existing Only me schedule never needs a fresh permission; a
236
+ // newly private one needs the organization to allow Only me.
237
+ if (input.current?.visibility !== "private" && !forced) {
238
+ if (
239
+ !(await mayStartOnlyMe(
240
+ input.db,
241
+ input.settings,
242
+ input.grant.workspaceId,
243
+ input.ownerSubjectId,
244
+ ))
245
+ )
246
+ throw new HTTPException(403, { message: SCHEDULED_TASK_PRIVATE_DISABLED_MESSAGE });
247
+ }
248
+ return "user_private";
249
+ }