@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,264 @@
1
+ import { CODEX_CLIENT_VERSION, fetchCodexModels } from "@opengeni/codex";
2
+ import { configuredModels, withCodexCatalogProvider, type Settings } from "@opengeni/config";
3
+ import {
4
+ buildSubscriptionCoreCodexConnectionTokenResolver,
5
+ buildSubscriptionCoreCodexOperationFetch,
6
+ listSubscriptionCoreCodexServingConnections,
7
+ readCodexCutoverDisposition,
8
+ subscriptionCoreCodexConnectionAllowsModel,
9
+ recordSubscriptionCoreCodexModelCatalog,
10
+ SUBSCRIPTION_MODEL_CATALOG_TTL_MS,
11
+ type CodexCredentialTokenSnapshot,
12
+ type Database,
13
+ type SubscriptionCoreCodexServingConnection,
14
+ } from "@opengeni/db";
15
+ import type { ModelAvailabilityObservation } from "./model-catalog";
16
+
17
+ const CATALOG_CACHE_MS = SUBSCRIPTION_MODEL_CATALOG_TTL_MS;
18
+ const CATALOG_ERROR_CACHE_MS = 5_000;
19
+ type CatalogCacheEntry = {
20
+ expiresAt: number;
21
+ result: Promise<{ ok: boolean; slugs: string[]; checkedAt: string }>;
22
+ };
23
+ const catalogs = new Map<string, CatalogCacheEntry>();
24
+
25
+ /** The workspace, organization and acting subject of a Codex catalog read. */
26
+ export type WorkspaceCodexCatalogContext = {
27
+ accountId: string;
28
+ workspaceId: string;
29
+ /**
30
+ * The person whose new work the catalog describes: the authenticated
31
+ * caller, or a scheduled task's execution owner. Their own personal
32
+ * connection counts only in their own Personal workspace; null or a
33
+ * non-human subject sees shared capacity only.
34
+ */
35
+ subjectId: string | null;
36
+ };
37
+
38
+ export type WorkspaceCodexCatalogReadiness = {
39
+ /** Codex models are ready in this workspace (the catalog's connection readiness). */
40
+ active: boolean;
41
+ /** Live per-model availability, keyed by model definition version. */
42
+ observations: Record<string, ModelAvailabilityObservation>;
43
+ };
44
+
45
+ type CatalogDependencies = {
46
+ recordModels: typeof recordSubscriptionCoreCodexModelCatalog;
47
+ disposition: typeof readCodexCutoverDisposition;
48
+ listServing: typeof listSubscriptionCoreCodexServingConnections;
49
+ fetchModels: typeof fetchCodexModels;
50
+ getCoreToken: (
51
+ db: Database,
52
+ settings: Settings,
53
+ context: WorkspaceCodexCatalogContext,
54
+ connectionId: string,
55
+ ) => Promise<CodexCredentialTokenSnapshot>;
56
+ };
57
+
58
+ const CATALOG_SERVICE_SUBJECT = "service:subscription-core";
59
+
60
+ const defaultCatalogDependencies = (): CatalogDependencies => ({
61
+ recordModels: recordSubscriptionCoreCodexModelCatalog,
62
+ disposition: readCodexCutoverDisposition,
63
+ listServing: listSubscriptionCoreCodexServingConnections,
64
+ fetchModels: fetchCodexModels,
65
+ // A connection-level read (no operation lease), like live usage: the 0671
66
+ // seam serves only shared organization- or workspace-scoped connections in
67
+ // this workspace's scope, and refreshes under the per-connection key.
68
+ getCoreToken: (targetDb, targetSettings, context, connectionId) =>
69
+ buildSubscriptionCoreCodexConnectionTokenResolver(
70
+ targetDb,
71
+ targetSettings,
72
+ {
73
+ kind: "workspace",
74
+ accountId: context.accountId,
75
+ workspaceId: context.workspaceId,
76
+ subjectId: context.subjectId ?? CATALOG_SERVICE_SUBJECT,
77
+ },
78
+ connectionId,
79
+ null,
80
+ ).getToken(),
81
+ });
82
+
83
+ function codexCatalogModels(settings: Settings) {
84
+ return configuredModels(withCodexCatalogProvider(settings)).filter(
85
+ (model) =>
86
+ model.credentialSource.kind === "connected_subscription" &&
87
+ model.credentialSource.provider === "codex",
88
+ );
89
+ }
90
+
91
+ /** One shared core connection's live model list (cached per refresh generation). */
92
+ async function loadCoreConnectionCatalog(
93
+ db: Database,
94
+ settings: Settings,
95
+ context: WorkspaceCodexCatalogContext,
96
+ connection: SubscriptionCoreCodexServingConnection,
97
+ deps: CatalogDependencies,
98
+ ): Promise<{ ok: boolean; slugs: string[]; checkedAt: string }> {
99
+ try {
100
+ // The token read rechecks the enabled cutover and the workspace scope
101
+ // before the cache is consulted.
102
+ const token = await deps.getCoreToken(db, settings, context, connection.connectionId);
103
+ const key = `core:${context.workspaceId}:${connection.connectionId}:${token.credentialVersion}`;
104
+ const cached = catalogs.get(key);
105
+ if (cached && cached.expiresAt > Date.now()) return await cached.result;
106
+ for (const [id, entry] of catalogs) {
107
+ if (entry.expiresAt <= Date.now()) catalogs.delete(id);
108
+ }
109
+ if (catalogs.size >= 1_024) catalogs.delete(catalogs.keys().next().value!);
110
+ const entry: CatalogCacheEntry = {
111
+ expiresAt: Date.now() + CATALOG_CACHE_MS,
112
+ result: deps
113
+ .fetchModels(
114
+ {
115
+ accessToken: token.accessToken,
116
+ chatgptAccountId: token.chatgptAccountId,
117
+ isFedramp: token.isFedramp,
118
+ clientVersion: CODEX_CLIENT_VERSION,
119
+ },
120
+ buildSubscriptionCoreCodexOperationFetch(
121
+ db,
122
+ {
123
+ kind: "workspace",
124
+ accountId: context.accountId,
125
+ workspaceId: context.workspaceId,
126
+ subjectId: context.subjectId ?? CATALOG_SERVICE_SUBJECT,
127
+ },
128
+ null,
129
+ connection.connectionId,
130
+ ),
131
+ )
132
+ .catch(() => ({ ok: false, slugs: [] as string[] }))
133
+ .then(async (result) => {
134
+ entry.expiresAt = Date.now() + (result.ok ? CATALOG_CACHE_MS : CATALOG_ERROR_CACHE_MS);
135
+ const observedAt = Date.now();
136
+ if (result.ok && token.credentialVersion !== null) {
137
+ await deps.recordModels(
138
+ db,
139
+ {
140
+ kind: "workspace",
141
+ ...context,
142
+ subjectId: context.subjectId ?? CATALOG_SERVICE_SUBJECT,
143
+ },
144
+ connection.connectionId,
145
+ { slugs: result.slugs, refreshGeneration: token.credentialVersion, observedAt },
146
+ );
147
+ }
148
+ return {
149
+ ok: result.ok,
150
+ slugs: result.slugs,
151
+ checkedAt: new Date(observedAt).toISOString(),
152
+ };
153
+ }),
154
+ };
155
+ catalogs.set(key, entry);
156
+ return await entry.result;
157
+ } catch {
158
+ return { ok: false, slugs: [], checkedAt: new Date().toISOString() };
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Placement consumes the same per-account catalog facts as the picker, never
164
+ * the union of another account's entitlements. Failed reads remain unknown.
165
+ * Personal credentials require an accepted-turn lease and are not probed by
166
+ * this workspace reader; their proven refusals remain model cooldowns.
167
+ */
168
+ export async function refreshCoreCodexModelEntitlements(
169
+ db: Database,
170
+ settings: Settings,
171
+ context: WorkspaceCodexCatalogContext,
172
+ deps: CatalogDependencies = defaultCatalogDependencies(),
173
+ ): Promise<void> {
174
+ if ((await deps.disposition(db, context.accountId, context.workspaceId)) !== "core") return;
175
+ const connections = await deps.listServing(db, context);
176
+ await Promise.all(
177
+ connections
178
+ .filter((connection) => connection.ownership === "shared")
179
+ .map((connection) => loadCoreConnectionCatalog(db, settings, context, connection, deps)),
180
+ );
181
+ }
182
+
183
+ /**
184
+ * Codex readiness and live model availability for a workspace catalog,
185
+ * default-model or picker read, by the organization's Codex cutover row:
186
+ *
187
+ * - a missing or disabled row (maintenance): Codex is not ready and no legacy Codex
188
+ * table is read;
189
+ * - an enabled row (`core`): the core connections that can serve new work of
190
+ * `context.subjectId` here. A shared connection's live model list is read
191
+ * through the connection-level core seam. A personal connection's list
192
+ * cannot be read outside an exact accepted turn, so a model it permits and
193
+ * has not been refused for (no live model cooldown) is reported without an
194
+ * observation (selectable, status unknown); placement still decides.
195
+ */
196
+ export async function loadWorkspaceCodexCatalogReadiness(
197
+ db: Database,
198
+ settings: Settings,
199
+ context: WorkspaceCodexCatalogContext,
200
+ options: {
201
+ observeAvailability?: boolean;
202
+ /** Deployment-level readiness settings, when different from the model catalog. */
203
+ activeSettings?: Pick<Settings, "codexSubscriptionEnabled">;
204
+ } = {},
205
+ deps: CatalogDependencies = defaultCatalogDependencies(),
206
+ ): Promise<WorkspaceCodexCatalogReadiness> {
207
+ const activeSettings = options.activeSettings ?? settings;
208
+ const observe = options.observeAvailability !== false;
209
+ // Codex disabled for the deployment: never ready, nothing read.
210
+ if (!activeSettings.codexSubscriptionEnabled) return { active: false, observations: {} };
211
+ const disposition = await deps.disposition(db, context.accountId, context.workspaceId);
212
+ if (disposition === "maintenance") return { active: false, observations: {} };
213
+ const serving = await deps.listServing(db, context);
214
+ if (!observe || !settings.codexSubscriptionEnabled || serving.length === 0) {
215
+ return { active: serving.length > 0, observations: {} };
216
+ }
217
+ const shared = serving.filter((connection) => connection.ownership === "shared");
218
+ const personal = serving.filter((connection) => connection.ownership === "personal");
219
+ const live = await Promise.all(
220
+ shared.map(async (connection) => ({
221
+ connection,
222
+ ...(await loadCoreConnectionCatalog(db, settings, context, connection, deps)),
223
+ })),
224
+ );
225
+ const observations: Record<string, ModelAvailabilityObservation> = {};
226
+ for (const model of codexCatalogModels(settings)) {
227
+ // Support and permission must hold on the SAME serving connection.
228
+ const permitted = live.filter(({ connection }) =>
229
+ subscriptionCoreCodexConnectionAllowsModel(connection, model.id),
230
+ );
231
+ const reachable = permitted.filter(({ ok }) => ok);
232
+ const supported = reachable.find(({ slugs }) => slugs.includes(model.upstreamModelId));
233
+ if (supported) {
234
+ observations[model.definitionVersion] = {
235
+ status: "available",
236
+ reason: null,
237
+ checkedAt: supported.checkedAt,
238
+ };
239
+ continue;
240
+ }
241
+ // The person's own connection may serve it: its list is unknown here.
242
+ if (
243
+ personal.some(
244
+ (connection) =>
245
+ subscriptionCoreCodexConnectionAllowsModel(connection, model.id) &&
246
+ !connection.cooledDownModelIds.includes(model.id),
247
+ )
248
+ ) {
249
+ continue;
250
+ }
251
+ // A reachable Free account cannot establish that an unreachable Pro
252
+ // account lacks entitlement. Only definitive observations may deny it.
253
+ // Omit a negative observation when a permitted account is unknown. The
254
+ // shared catalog projects this as selectable/unknown, not unavailable;
255
+ // actual placement still rechecks scope, health and plan per account.
256
+ if (permitted.some(({ ok }) => !ok)) continue;
257
+ observations[model.definitionVersion] = {
258
+ status: "unavailable",
259
+ reason: "not_entitled",
260
+ checkedAt: permitted[0]?.checkedAt ?? new Date().toISOString(),
261
+ };
262
+ }
263
+ return { active: true, observations };
264
+ }