@opengeni/contracts 0.50.0 → 1.0.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 (369) hide show
  1. package/dist/agent-authored-durable-text.d.ts +70 -0
  2. package/dist/agent-config.d.ts +869 -0
  3. package/dist/agent-instruction-changes.d.ts +110 -0
  4. package/dist/agent-learning.d.ts +243 -0
  5. package/dist/agent-topology.d.ts +292 -0
  6. package/dist/allowance-refusal.d.ts +9 -0
  7. package/dist/allowance-refusal.js +50 -0
  8. package/dist/allowance-refusal.js.map +1 -0
  9. package/dist/analytics-consent-report.d.ts +19 -0
  10. package/dist/analytics-consent-report.js +10 -0
  11. package/dist/analytics-consent-report.js.map +1 -0
  12. package/dist/api-key-presets.d.ts +19 -0
  13. package/dist/artifact-catalog.d.ts +161 -0
  14. package/dist/artifacts.d.ts +135 -11
  15. package/dist/atlassian-native-retirement.d.ts +16 -0
  16. package/dist/atlassian-native-retirement.js +30 -0
  17. package/dist/atlassian-native-retirement.js.map +1 -0
  18. package/dist/atlassian.d.ts +2 -0
  19. package/dist/atlassian.js +26 -12
  20. package/dist/browser-storage.d.ts +5 -0
  21. package/dist/browser-storage.js +9 -0
  22. package/dist/browser-storage.js.map +1 -0
  23. package/dist/bundled-skills.d.ts +40 -0
  24. package/dist/chunk-2ACYHZFB.js +292 -0
  25. package/dist/chunk-2ACYHZFB.js.map +1 -0
  26. package/dist/chunk-2VORLN2R.js +353 -0
  27. package/dist/chunk-2VORLN2R.js.map +1 -0
  28. package/dist/{chunk-Y3MLSLB4.js → chunk-3SIZGL3O.js} +42 -30
  29. package/dist/chunk-3SIZGL3O.js.map +1 -0
  30. package/dist/chunk-46KLD2UH.js +186 -0
  31. package/dist/chunk-46KLD2UH.js.map +1 -0
  32. package/dist/chunk-4JGHSSB7.js +11 -0
  33. package/dist/chunk-4JGHSSB7.js.map +1 -0
  34. package/dist/{chunk-M5ZGRVIQ.js → chunk-5IXYF6XN.js} +14 -5
  35. package/dist/chunk-5IXYF6XN.js.map +1 -0
  36. package/dist/chunk-BCS7WHCK.js +139 -0
  37. package/dist/chunk-BCS7WHCK.js.map +1 -0
  38. package/dist/chunk-EK7NDGFR.js +128 -0
  39. package/dist/chunk-EK7NDGFR.js.map +1 -0
  40. package/dist/{chunk-5UDNP7AO.js → chunk-FZ6BXQHL.js} +78 -38
  41. package/dist/chunk-FZ6BXQHL.js.map +1 -0
  42. package/dist/{chunk-CM6BMECR.js → chunk-GRG7PHWQ.js} +2 -1
  43. package/dist/chunk-GRG7PHWQ.js.map +1 -0
  44. package/dist/chunk-KHHZTBP7.js +11 -0
  45. package/dist/chunk-KHHZTBP7.js.map +1 -0
  46. package/dist/chunk-KR2V42UZ.js +187 -0
  47. package/dist/chunk-KR2V42UZ.js.map +1 -0
  48. package/dist/chunk-MZLBPKFE.js +168 -0
  49. package/dist/chunk-MZLBPKFE.js.map +1 -0
  50. package/dist/{chunk-LW7OH6CS.js → chunk-NRMCVHAU.js} +6 -5
  51. package/dist/chunk-NRMCVHAU.js.map +1 -0
  52. package/dist/{chunk-TZ6YEYN4.js → chunk-NVJMJWLL.js} +3 -1
  53. package/dist/chunk-NVJMJWLL.js.map +1 -0
  54. package/dist/chunk-O77VSFYZ.js +70 -0
  55. package/dist/chunk-O77VSFYZ.js.map +1 -0
  56. package/dist/chunk-PX3VCKAU.js +29 -0
  57. package/dist/chunk-PX3VCKAU.js.map +1 -0
  58. package/dist/chunk-QR5D2IQC.js +61 -0
  59. package/dist/chunk-QR5D2IQC.js.map +1 -0
  60. package/dist/chunk-RJ76DRPO.js +117 -0
  61. package/dist/chunk-RJ76DRPO.js.map +1 -0
  62. package/dist/chunk-RKX3NQYS.js +28 -0
  63. package/dist/chunk-RKX3NQYS.js.map +1 -0
  64. package/dist/{chunk-JBCIY7QD.js → chunk-SIOU2K4U.js} +45 -22
  65. package/dist/chunk-SIOU2K4U.js.map +1 -0
  66. package/dist/chunk-TSCDAGET.js +75 -0
  67. package/dist/chunk-TSCDAGET.js.map +1 -0
  68. package/dist/{chunk-LSB7GRLG.js → chunk-TXTQIYCV.js} +15 -11
  69. package/dist/chunk-TXTQIYCV.js.map +1 -0
  70. package/dist/chunk-X7ETVO4P.js +26544 -0
  71. package/dist/chunk-X7ETVO4P.js.map +1 -0
  72. package/dist/{chunk-CADSX6UN.js → chunk-Y3KNXVTD.js} +2 -2
  73. package/dist/chunk-YBW5JSA3.js +251 -0
  74. package/dist/chunk-YBW5JSA3.js.map +1 -0
  75. package/dist/chunk-YRXAWWCU.js +45 -0
  76. package/dist/chunk-YRXAWWCU.js.map +1 -0
  77. package/dist/claude-provider-account-authority.d.ts +18 -0
  78. package/dist/claude-subscription-oauth.d.ts +42 -0
  79. package/dist/claude-subscription-usage.d.ts +159 -0
  80. package/dist/client-error-report.d.ts +109 -0
  81. package/dist/client-error-report.js +87 -0
  82. package/dist/client-error-report.js.map +1 -0
  83. package/dist/code-search.d.ts +52 -0
  84. package/dist/code-search.js +40 -0
  85. package/dist/code-search.js.map +1 -0
  86. package/dist/company-brain-governed-writes.d.ts +475 -0
  87. package/dist/company-brain.d.ts +336 -0
  88. package/dist/company-profile.d.ts +566 -0
  89. package/dist/connect.d.ts +325 -0
  90. package/dist/connect.js +191 -0
  91. package/dist/connect.js.map +1 -0
  92. package/dist/connection-account-label.d.ts +2 -0
  93. package/dist/connection-account-label.js +35 -0
  94. package/dist/connection-account-label.js.map +1 -0
  95. package/dist/connection-authority.d.ts +193 -0
  96. package/dist/connection-authority.js +50 -0
  97. package/dist/connection-authority.js.map +1 -0
  98. package/dist/connector-attachments.d.ts +95 -0
  99. package/dist/connector-attachments.js +51 -0
  100. package/dist/connector-attachments.js.map +1 -0
  101. package/dist/connector-tool-permissions.d.ts +73 -0
  102. package/dist/direct-model-provider.d.ts +36 -0
  103. package/dist/editable-artifact-codec-registry.d.ts +16 -7
  104. package/dist/editable-artifact-codec-registry.js +18 -8
  105. package/dist/editable-artifact-committed-transaction.d.ts +2 -2
  106. package/dist/editable-artifact-committed-transaction.js +2 -2
  107. package/dist/editable-artifact-live.d.ts +11 -12
  108. package/dist/editable-artifact-live.js +110 -45
  109. package/dist/editable-artifact-live.js.map +1 -1
  110. package/dist/editable-artifact-serialized-commit.d.ts +2 -1
  111. package/dist/editable-artifact-serialized-commit.js +8 -7
  112. package/dist/editable-artifact-versions.d.ts +20 -5
  113. package/dist/editable-artifact-versions.js +23 -5
  114. package/dist/editable-artifacts.d.ts +2 -0
  115. package/dist/editable-artifacts.js +47 -35
  116. package/dist/external-identities.d.ts +784 -0
  117. package/dist/external-identities.js +44 -0
  118. package/dist/external-identities.js.map +1 -0
  119. package/dist/feedback.d.ts +51 -0
  120. package/dist/github-repository-contracts.d.ts +36 -0
  121. package/dist/github-repository-contracts.js +59 -0
  122. package/dist/github-repository-contracts.js.map +1 -0
  123. package/dist/github-repository.d.ts +14 -0
  124. package/dist/github-repository.js +36 -0
  125. package/dist/github-repository.js.map +1 -0
  126. package/dist/google-drive.d.ts +90 -1
  127. package/dist/google-drive.js +90 -16
  128. package/dist/google-drive.js.map +1 -1
  129. package/dist/governed-learning-activation.d.ts +154 -0
  130. package/dist/governed-learning-evaluator.d.ts +152 -0
  131. package/dist/host-mcp-bindings.d.ts +326 -0
  132. package/dist/host-mcp-bindings.js +252 -0
  133. package/dist/host-mcp-bindings.js.map +1 -0
  134. package/dist/image-generation.d.ts +1 -0
  135. package/dist/index.d.ts +32396 -11386
  136. package/dist/index.js +2198 -164
  137. package/dist/insights-usage.d.ts +877 -0
  138. package/dist/insights-usage.js +509 -0
  139. package/dist/insights-usage.js.map +1 -0
  140. package/dist/interaction.d.ts +344 -0
  141. package/dist/knowledge-entries.d.ts +982 -0
  142. package/dist/knowledge-preparation.d.ts +237 -0
  143. package/dist/knowledge.d.ts +197 -0
  144. package/dist/managed-auth-session-sets.d.ts +241 -0
  145. package/dist/managed-auth-session-sets.js +191 -0
  146. package/dist/managed-auth-session-sets.js.map +1 -0
  147. package/dist/managed-sign-in-methods.d.ts +56 -0
  148. package/dist/managed-sign-in-methods.js +46 -0
  149. package/dist/managed-sign-in-methods.js.map +1 -0
  150. package/dist/mcp-catalog-limits.d.ts +2 -0
  151. package/dist/mcp-endpoint.d.ts +7 -0
  152. package/dist/mcp-endpoint.js +9 -0
  153. package/dist/mcp-endpoint.js.map +1 -0
  154. package/dist/mcp-oauth.d.ts +71 -0
  155. package/dist/modal-native-proof-v2.d.ts +587 -0
  156. package/dist/modal-native-proof-v2.js +37 -0
  157. package/dist/modal-native-proof-v2.js.map +1 -0
  158. package/dist/model-availability.d.ts +15 -0
  159. package/dist/model-connection-access.d.ts +24 -0
  160. package/dist/model-context-inspector.d.ts +329 -0
  161. package/dist/model-display.d.ts +38 -0
  162. package/dist/model-display.js +134 -0
  163. package/dist/model-display.js.map +1 -0
  164. package/dist/model-picker-order.d.ts +25 -0
  165. package/dist/model-picker-order.js +42 -0
  166. package/dist/model-picker-order.js.map +1 -0
  167. package/dist/organization-access.d.ts +231 -0
  168. package/dist/organization-access.js +34 -0
  169. package/dist/organization-access.js.map +1 -0
  170. package/dist/organization-integration-policy.d.ts +27 -0
  171. package/dist/organization-membership-lifecycle.d.ts +1022 -0
  172. package/dist/organization-model-usage.d.ts +146 -0
  173. package/dist/organization-model-usage.js +67 -0
  174. package/dist/organization-model-usage.js.map +1 -0
  175. package/dist/organization-recovery.d.ts +337 -0
  176. package/dist/organization-recovery.js +37 -0
  177. package/dist/organization-recovery.js.map +1 -0
  178. package/dist/organization-usage.d.ts +138 -0
  179. package/dist/permissions.d.ts +54 -0
  180. package/dist/personal-github.d.ts +320 -0
  181. package/dist/personal-github.js +222 -0
  182. package/dist/personal-github.js.map +1 -0
  183. package/dist/plugin-discovery.d.ts +35 -0
  184. package/dist/plugin-discovery.js +7 -0
  185. package/dist/plugin-discovery.js.map +1 -0
  186. package/dist/preference-registry.d.ts +44 -1
  187. package/dist/product-analytics.d.ts +113 -0
  188. package/dist/product-lifecycle-facts.d.ts +73 -0
  189. package/dist/remember.d.ts +350 -0
  190. package/dist/retained-output.d.ts +8 -0
  191. package/dist/sandbox-file-artifacts.d.ts +57 -0
  192. package/dist/sandbox-provider-command.d.ts +113 -0
  193. package/dist/sandbox-recovery.d.ts +146 -0
  194. package/dist/sandbox-snapshots.d.ts +39 -0
  195. package/dist/session-final-reply.d.ts +6 -0
  196. package/dist/session-final-reply.js +9 -0
  197. package/dist/session-final-reply.js.map +1 -0
  198. package/dist/session-goal-reports.d.ts +21 -0
  199. package/dist/session-history-import.d.ts +947 -0
  200. package/dist/session-list-entries.d.ts +4 -0
  201. package/dist/session-list-entries.js +51 -0
  202. package/dist/session-list-entries.js.map +1 -0
  203. package/dist/session-mcp-projections.d.ts +215 -0
  204. package/dist/session-message-search.d.ts +68 -0
  205. package/dist/session-titles.d.ts +68 -0
  206. package/dist/session-titles.js +25 -0
  207. package/dist/session-titles.js.map +1 -0
  208. package/dist/session-topology-primitives.d.ts +22 -0
  209. package/dist/signup-attribution.d.ts +39 -0
  210. package/dist/site-request-headers.test.d.ts +1 -0
  211. package/dist/site-session-http.d.ts +11 -0
  212. package/dist/site-session-http.js +11 -0
  213. package/dist/site-session-http.js.map +1 -0
  214. package/dist/skill-catalog-context.d.ts +7 -0
  215. package/dist/skill-files.d.ts +12 -0
  216. package/dist/skill-metadata.d.ts +9 -0
  217. package/dist/skill-use.d.ts +61 -0
  218. package/dist/skills.d.ts +185 -0
  219. package/dist/slack-bot-scopes.d.ts +46 -21
  220. package/dist/slack-bot-scopes.js +14 -3
  221. package/dist/slack-rest-mcp.d.ts +31 -0
  222. package/dist/slack-rest-mcp.js +19 -0
  223. package/dist/slack-rest-mcp.js.map +1 -0
  224. package/dist/spreadsheet-artifact-commands.d.ts +2 -3
  225. package/dist/spreadsheet-artifact-commands.js +4 -2
  226. package/dist/spreadsheet-artifact-query.js +3 -2
  227. package/dist/subscription-account-pools.d.ts +292 -0
  228. package/dist/task-notes.d.ts +42 -1
  229. package/dist/tool-catalog.d.ts +286 -0
  230. package/dist/tool-result-spill.d.ts +16 -0
  231. package/dist/usage-allowances.d.ts +285 -0
  232. package/dist/usage-allowances.js +49 -0
  233. package/dist/usage-allowances.js.map +1 -0
  234. package/dist/video-generation.d.ts +3 -0
  235. package/dist/video-generation.js +1 -1
  236. package/dist/work-claims.d.ts +411 -0
  237. package/dist/workspace-instruction-policies.d.ts +94 -0
  238. package/dist/workspace-integration-wire.d.ts +36 -0
  239. package/dist/workspace-integration-wire.js +23 -0
  240. package/dist/workspace-integration-wire.js.map +1 -0
  241. package/dist/workspace-integrations.d.ts +948 -0
  242. package/dist/workspace-learning-administration.d.ts +289 -0
  243. package/dist/workspace-learning-policy.d.ts +1 -1
  244. package/dist/workspace-state.d.ts +85 -416
  245. package/dist/xai-provider-account-authority.d.ts +3 -0
  246. package/dist/xai-provider-account-authority.js +1 -1
  247. package/package.json +134 -1
  248. package/src/agent-authored-durable-text.ts +116 -0
  249. package/src/agent-config.ts +1527 -0
  250. package/src/agent-instruction-changes.ts +98 -0
  251. package/src/agent-learning.ts +161 -0
  252. package/src/agent-topology.ts +69 -0
  253. package/src/allowance-refusal.ts +81 -0
  254. package/src/analytics-consent-report.ts +20 -0
  255. package/src/api-key-presets.ts +25 -0
  256. package/src/artifact-catalog.ts +60 -0
  257. package/src/artifacts.ts +146 -18
  258. package/src/atlassian-native-retirement.ts +33 -0
  259. package/src/browser-storage.ts +10 -0
  260. package/src/bundled-skills.ts +73 -0
  261. package/src/claude-provider-account-authority.ts +12 -0
  262. package/src/claude-subscription-oauth.ts +62 -0
  263. package/src/claude-subscription-usage.ts +59 -0
  264. package/src/client-error-report.ts +184 -0
  265. package/src/code-search.ts +105 -0
  266. package/src/company-brain-governed-writes.ts +356 -0
  267. package/src/company-brain.ts +201 -0
  268. package/src/company-profile.ts +167 -1
  269. package/src/connect.ts +202 -0
  270. package/src/connection-account-label.ts +46 -0
  271. package/src/connection-authority.ts +213 -0
  272. package/src/connector-attachments.ts +327 -0
  273. package/src/connector-tool-permissions.ts +60 -0
  274. package/src/direct-model-provider.ts +98 -0
  275. package/src/editable-artifact-codec-registry.ts +55 -17
  276. package/src/editable-artifact-committed-transaction.ts +44 -31
  277. package/src/editable-artifact-live.ts +123 -57
  278. package/src/editable-artifact-serialized-commit.ts +2 -1
  279. package/src/editable-artifact-versions.ts +26 -5
  280. package/src/editable-artifacts.ts +2 -0
  281. package/src/external-identities.ts +285 -0
  282. package/src/feedback.ts +39 -0
  283. package/src/github-repository-contracts.ts +85 -0
  284. package/src/github-repository.ts +59 -0
  285. package/src/google-drive.ts +76 -4
  286. package/src/governed-learning-activation.ts +191 -0
  287. package/src/governed-learning-evaluator.ts +176 -0
  288. package/src/host-mcp-bindings.ts +298 -0
  289. package/src/image-generation.ts +8 -2
  290. package/src/index.ts +7093 -1466
  291. package/src/insights-usage.ts +679 -0
  292. package/src/interaction.ts +220 -5
  293. package/src/knowledge-entries.ts +375 -0
  294. package/src/knowledge-preparation.ts +50 -0
  295. package/src/knowledge.ts +134 -6
  296. package/src/managed-auth-session-sets.ts +253 -0
  297. package/src/managed-sign-in-methods.ts +37 -0
  298. package/src/mcp-catalog-limits.ts +2 -0
  299. package/src/mcp-endpoint.ts +30 -0
  300. package/src/mcp-oauth.ts +66 -0
  301. package/src/modal-native-proof-v2.ts +398 -0
  302. package/src/model-availability.ts +22 -0
  303. package/src/model-connection-access.ts +17 -0
  304. package/src/model-context-inspector.ts +139 -0
  305. package/src/model-display.ts +195 -0
  306. package/src/model-picker-order.ts +97 -0
  307. package/src/organization-access.ts +176 -0
  308. package/src/organization-integration-policy.ts +54 -0
  309. package/src/organization-membership-lifecycle.ts +559 -0
  310. package/src/organization-model-usage.ts +72 -0
  311. package/src/organization-recovery.ts +186 -0
  312. package/src/organization-usage.ts +79 -0
  313. package/src/permissions.ts +58 -0
  314. package/src/personal-github.ts +267 -0
  315. package/src/plugin-discovery.ts +33 -0
  316. package/src/preference-registry.ts +20 -1
  317. package/src/product-analytics.ts +253 -0
  318. package/src/product-lifecycle-facts.ts +121 -0
  319. package/src/remember.ts +243 -0
  320. package/src/retained-output.ts +20 -3
  321. package/src/sandbox-file-artifacts.ts +73 -0
  322. package/src/sandbox-provider-command.ts +82 -0
  323. package/src/sandbox-recovery.ts +116 -0
  324. package/src/sandbox-snapshots.ts +142 -0
  325. package/src/session-final-reply.ts +16 -0
  326. package/src/session-goal-reports.ts +55 -0
  327. package/src/session-history-import.ts +159 -0
  328. package/src/session-list-entries.ts +91 -0
  329. package/src/session-mcp-projections.ts +273 -0
  330. package/src/session-message-search.ts +54 -0
  331. package/src/session-titles.ts +467 -0
  332. package/src/session-topology-primitives.ts +21 -0
  333. package/src/signup-attribution.ts +81 -0
  334. package/src/site-request-headers.test.ts +28 -0
  335. package/src/site-session-http.ts +63 -0
  336. package/src/skill-catalog-context.ts +50 -0
  337. package/src/skill-files.ts +52 -0
  338. package/src/skill-metadata.ts +40 -0
  339. package/src/skill-use.ts +77 -0
  340. package/src/skills.ts +136 -0
  341. package/src/slack-bot-scopes.ts +106 -42
  342. package/src/slack-rest-mcp.ts +194 -0
  343. package/src/spreadsheet-artifact-commands.ts +12 -13
  344. package/src/subscription-account-pools.ts +44 -0
  345. package/src/task-notes.ts +14 -1
  346. package/src/tool-catalog.ts +155 -0
  347. package/src/tool-result-spill.ts +35 -0
  348. package/src/usage-allowances.ts +187 -0
  349. package/src/work-claims.ts +266 -0
  350. package/src/workspace-instruction-policies.ts +31 -0
  351. package/src/workspace-integration-wire.ts +99 -0
  352. package/src/workspace-integrations.ts +640 -0
  353. package/src/workspace-learning-administration.ts +88 -0
  354. package/src/workspace-learning-policy.ts +4 -3
  355. package/src/workspace-state.ts +16 -126
  356. package/src/xai-provider-account-authority.ts +1 -0
  357. package/dist/chunk-5UDNP7AO.js.map +0 -1
  358. package/dist/chunk-BVGIYW7D.js +0 -11
  359. package/dist/chunk-BVGIYW7D.js.map +0 -1
  360. package/dist/chunk-CM6BMECR.js.map +0 -1
  361. package/dist/chunk-JBCIY7QD.js.map +0 -1
  362. package/dist/chunk-LSB7GRLG.js.map +0 -1
  363. package/dist/chunk-LW7OH6CS.js.map +0 -1
  364. package/dist/chunk-M5ZGRVIQ.js.map +0 -1
  365. package/dist/chunk-Q6A7XT2N.js +0 -16734
  366. package/dist/chunk-Q6A7XT2N.js.map +0 -1
  367. package/dist/chunk-TZ6YEYN4.js.map +0 -1
  368. package/dist/chunk-Y3MLSLB4.js.map +0 -1
  369. /package/dist/{chunk-CADSX6UN.js.map → chunk-Y3KNXVTD.js.map} +0 -0
@@ -1,4 +1,11 @@
1
1
  import { z } from "zod";
2
+ import {
3
+ AGENT_AUTHORED_COMPANY_PROFILE_CONTENT_MAX_UTF8_BYTES,
4
+ AGENT_AUTHORED_COMPANY_PROFILE_ENTRY_MAX_CHARS,
5
+ AGENT_AUTHORED_COMPANY_PROFILE_SCALAR_MAX_CHARS,
6
+ AGENT_AUTHORED_COMPANY_PROFILE_TOO_LONG_MESSAGE,
7
+ } from "./agent-authored-durable-text";
8
+ import { HumanInputQuestion } from "./index";
2
9
 
3
10
  export const COMPANY_PROFILE_SCALAR_MAX_CHARS = 2_048;
4
11
  export const COMPANY_PROFILE_ENTRY_MAX_CHARS = 1_024;
@@ -100,10 +107,56 @@ export const CompanyProfileContent = z
100
107
  });
101
108
  export type CompanyProfileContent = z.infer<typeof CompanyProfileContent>;
102
109
 
110
+ /**
111
+ * The same profile, bounded for an **agent** author. The human `account:admin`
112
+ * route keeps `CompanyProfileContent` and its wider limits; this is the shape
113
+ * persisted by the first-party `company_profile_propose` tool. The current tool
114
+ * accepts only identity and mission and writes empty compatibility lists, but
115
+ * the validator must still read historical revisions without rewriting them.
116
+ */
117
+ export const AgentAuthoredCompanyProfileContent = CompanyProfileContent.superRefine(
118
+ (value, context) => {
119
+ for (const field of ["identity", "mission"] as const) {
120
+ const scalar = value[field];
121
+ if (scalar !== null && scalar.length > AGENT_AUTHORED_COMPANY_PROFILE_SCALAR_MAX_CHARS) {
122
+ context.addIssue({
123
+ code: "custom",
124
+ path: [field],
125
+ message: `${field} is ${scalar.length} characters. ${AGENT_AUTHORED_COMPANY_PROFILE_TOO_LONG_MESSAGE}`,
126
+ });
127
+ }
128
+ }
129
+ for (const field of ["products", "customers", "goals", "constraints"] as const) {
130
+ for (const [index, entry] of value[field].entries()) {
131
+ if (entry.content.length > AGENT_AUTHORED_COMPANY_PROFILE_ENTRY_MAX_CHARS) {
132
+ context.addIssue({
133
+ code: "custom",
134
+ path: [field, index, "content"],
135
+ message: `this entry is ${entry.content.length} characters. ${AGENT_AUTHORED_COMPANY_PROFILE_TOO_LONG_MESSAGE}`,
136
+ });
137
+ }
138
+ }
139
+ }
140
+ const contentBytes = new TextEncoder().encode(JSON.stringify(value)).byteLength;
141
+ if (contentBytes > AGENT_AUTHORED_COMPANY_PROFILE_CONTENT_MAX_UTF8_BYTES) {
142
+ context.addIssue({
143
+ code: "custom",
144
+ message: `this profile is ${contentBytes} UTF-8 bytes. ${AGENT_AUTHORED_COMPANY_PROFILE_TOO_LONG_MESSAGE}`,
145
+ });
146
+ }
147
+ },
148
+ );
149
+ export type AgentAuthoredCompanyProfileContent = z.infer<typeof AgentAuthoredCompanyProfileContent>;
150
+
103
151
  export const CompanyProfileRevisionIntent = z.enum(["active", "proposal"]);
104
152
  export type CompanyProfileRevisionIntent = z.infer<typeof CompanyProfileRevisionIntent>;
105
153
 
106
- export const CompanyProfileProvenanceSource = z.enum(["human", "durable_learning", "migration"]);
154
+ export const CompanyProfileProvenanceSource = z.enum([
155
+ "human",
156
+ "agent_admin",
157
+ "durable_learning",
158
+ "migration",
159
+ ]);
107
160
  export type CompanyProfileProvenanceSource = z.infer<typeof CompanyProfileProvenanceSource>;
108
161
 
109
162
  export const CompanyProfilePrincipalKind = z.enum(["human_session", "agent_attempt", "service"]);
@@ -240,6 +293,119 @@ export const CompanyProfileMutationResponse = z.object({
240
293
  });
241
294
  export type CompanyProfileMutationResponse = z.infer<typeof CompanyProfileMutationResponse>;
242
295
 
296
+ export const COMPANY_PROFILE_AGENT_APPROVE_OPTION = "activate" as const;
297
+ export const COMPANY_PROFILE_AGENT_REJECT_OPTION = "skip" as const;
298
+
299
+ export const CompanyProfileAgentPolicyMode = z.enum(["off", "suggest", "automatic"]);
300
+ export type CompanyProfileAgentPolicyMode = z.infer<typeof CompanyProfileAgentPolicyMode>;
301
+
302
+ export const CompanyProfileAgentPolicy = z.object({
303
+ organizationId: z.string().uuid(),
304
+ mode: CompanyProfileAgentPolicyMode,
305
+ version: z.number().int().nonnegative(),
306
+ updatedAt: z.string().datetime({ offset: true }),
307
+ changed: z.boolean().optional(),
308
+ });
309
+ export type CompanyProfileAgentPolicy = z.infer<typeof CompanyProfileAgentPolicy>;
310
+
311
+ export const UpdateCompanyProfileAgentPolicyRequest = z
312
+ .object({
313
+ mode: CompanyProfileAgentPolicyMode,
314
+ expectedVersion: z.number().int().nonnegative(),
315
+ operationId: z.string().uuid(),
316
+ })
317
+ .strict();
318
+ export type UpdateCompanyProfileAgentPolicyRequest = z.infer<
319
+ typeof UpdateCompanyProfileAgentPolicyRequest
320
+ >;
321
+
322
+ export const CompanyProfileAgentAttempt = z
323
+ .object({
324
+ accountId: z.string().uuid(),
325
+ workspaceId: z.string().uuid(),
326
+ sessionId: z.string().uuid(),
327
+ turnId: z.string().uuid(),
328
+ attemptId: z.string().uuid(),
329
+ executionGeneration: z.number().int().positive(),
330
+ agentSubjectId: z.string().trim().min(1).max(1_024),
331
+ })
332
+ .strict();
333
+ export type CompanyProfileAgentAttempt = z.infer<typeof CompanyProfileAgentAttempt>;
334
+
335
+ export const CompanyProfileAgentProposalRequest = z
336
+ .object({
337
+ operationId: z.string().uuid(),
338
+ profile: CompanyProfileContent,
339
+ reason: z.string().trim().min(1).max(COMPANY_PROFILE_REASON_MAX_CHARS),
340
+ })
341
+ .strict();
342
+ export type CompanyProfileAgentProposalRequest = z.infer<typeof CompanyProfileAgentProposalRequest>;
343
+
344
+ // z.lazy avoids an import cycle because HumanInputQuestion is declared in the
345
+ // root contracts module that re-exports this file.
346
+ export const CompanyProfileAgentHumanInputPrompt = z.object({
347
+ questions: z.array(z.lazy(() => HumanInputQuestion)).length(1),
348
+ allowSkip: z.literal(false),
349
+ });
350
+ export type CompanyProfileAgentHumanInputPrompt = z.infer<
351
+ typeof CompanyProfileAgentHumanInputPrompt
352
+ >;
353
+
354
+ export const CompanyProfileAgentReviewRequiredReceipt = z.object({
355
+ status: z.literal("confirmation_required"),
356
+ operationId: z.string().uuid(),
357
+ proposalReceiptId: z.string().uuid(),
358
+ revision: CompanyProfileRevision,
359
+ policyMode: z.literal("suggest"),
360
+ humanInput: CompanyProfileAgentHumanInputPrompt,
361
+ confirmWith: z.literal("company_profile_confirm"),
362
+ replayed: z.boolean(),
363
+ });
364
+ export type CompanyProfileAgentReviewRequiredReceipt = z.infer<
365
+ typeof CompanyProfileAgentReviewRequiredReceipt
366
+ >;
367
+
368
+ export const CompanyProfileAgentAutomaticActivationReceipt = z.object({
369
+ status: z.literal("activated"),
370
+ operationId: z.string().uuid(),
371
+ proposalReceiptId: z.string().uuid(),
372
+ automaticActivationReceiptId: z.string().uuid(),
373
+ policyMode: z.literal("automatic"),
374
+ mutation: CompanyProfileMutationResponse,
375
+ replayed: z.boolean(),
376
+ });
377
+ export type CompanyProfileAgentAutomaticActivationReceipt = z.infer<
378
+ typeof CompanyProfileAgentAutomaticActivationReceipt
379
+ >;
380
+
381
+ export const CompanyProfileAgentProposalReceipt = z.discriminatedUnion("status", [
382
+ CompanyProfileAgentReviewRequiredReceipt,
383
+ CompanyProfileAgentAutomaticActivationReceipt,
384
+ ]);
385
+ export type CompanyProfileAgentProposalReceipt = z.infer<typeof CompanyProfileAgentProposalReceipt>;
386
+
387
+ export const CompanyProfileAgentConfirmRequest = z
388
+ .object({
389
+ operationId: z.string().uuid(),
390
+ proposalReceiptId: z.string().uuid(),
391
+ humanInputRequestId: z.string().uuid(),
392
+ })
393
+ .strict();
394
+ export type CompanyProfileAgentConfirmRequest = z.infer<typeof CompanyProfileAgentConfirmRequest>;
395
+
396
+ export const CompanyProfileAgentConfirmationReceipt = z.object({
397
+ status: z.literal("activated"),
398
+ operationId: z.string().uuid(),
399
+ confirmationReceiptId: z.string().uuid(),
400
+ proposalReceiptId: z.string().uuid(),
401
+ humanInputRequestId: z.string().uuid(),
402
+ mutation: CompanyProfileMutationResponse,
403
+ replayed: z.boolean(),
404
+ });
405
+ export type CompanyProfileAgentConfirmationReceipt = z.infer<
406
+ typeof CompanyProfileAgentConfirmationReceipt
407
+ >;
408
+
243
409
  export const CompanyProfileDiffRequest = z
244
410
  .object({ fromRevisionId: z.string().uuid(), toRevisionId: z.string().uuid() })
245
411
  .refine((value) => value.fromRevisionId !== value.toRevisionId, {
package/src/connect.ts ADDED
@@ -0,0 +1,202 @@
1
+ import { z } from "zod";
2
+ import { IntegrationInstanceKey, IntegrationSource } from "./index";
3
+
4
+ const opaqueId = z.string().min(1).max(512);
5
+ export const ConnectOwnership = z.enum(["personal", "workspace"]);
6
+ export type ConnectOwnership = z.infer<typeof ConnectOwnership>;
7
+ export const ConnectProvider = z
8
+ .object({
9
+ id: opaqueId,
10
+ label: z.string().min(1).max(256),
11
+ family: opaqueId,
12
+ readiness: z.enum(["available", "needs_configuration", "operator_only", "unsupported"]),
13
+ reason: z.string().max(1024).optional(),
14
+ ownership: z.array(ConnectOwnership).max(2),
15
+ setup: z
16
+ .array(
17
+ z.enum(["none", "oauth", "credentials", "device", "installation", "openapi", "graphql"]),
18
+ )
19
+ .max(7),
20
+ })
21
+ .strict();
22
+ export type ConnectProvider = z.infer<typeof ConnectProvider>;
23
+ export const ConnectAccount = z
24
+ .object({
25
+ id: opaqueId,
26
+ providerId: opaqueId,
27
+ version: z.number().int().positive().optional(),
28
+ label: z.string().max(256),
29
+ ownership: ConnectOwnership,
30
+ status: z.enum(["connected", "auth_needed", "disabled"]),
31
+ })
32
+ .strict();
33
+ export type ConnectAccount = z.infer<typeof ConnectAccount>;
34
+ export const ConnectResource = z
35
+ .object({ id: opaqueId, label: z.string().max(512), kind: opaqueId })
36
+ .strict();
37
+ export type ConnectResource = z.infer<typeof ConnectResource>;
38
+ export const ConnectNextAction = z.discriminatedUnion("type", [
39
+ z.object({ type: z.literal("authorize"), url: z.string().url().max(16_384) }).strict(),
40
+ z
41
+ .object({
42
+ type: z.literal("credentials"),
43
+ fields: z
44
+ .array(
45
+ z
46
+ .object({
47
+ name: opaqueId,
48
+ label: z.string().max(256),
49
+ required: z.boolean(),
50
+ secret: z.boolean(),
51
+ options: z
52
+ .array(z.object({ value: opaqueId, label: z.string().max(512) }).strict())
53
+ .max(1000)
54
+ .optional(),
55
+ })
56
+ .strict(),
57
+ )
58
+ .max(32),
59
+ })
60
+ .strict(),
61
+ z
62
+ .object({
63
+ type: z.literal("wait"),
64
+ pollAfterMs: z.number().int().min(250).max(60_000),
65
+ userCode: z.string().max(128).optional(),
66
+ verificationUrl: z.string().url().max(2048).optional(),
67
+ })
68
+ .strict(),
69
+ z
70
+ .object({ type: z.literal("select_account"), accounts: z.array(ConnectAccount).max(100) })
71
+ .strict(),
72
+ z
73
+ .object({
74
+ type: z.literal("select_resources"),
75
+ resources: z.array(ConnectResource).max(100),
76
+ cursor: z.string().max(2048).optional(),
77
+ })
78
+ .strict(),
79
+ z
80
+ .object({
81
+ type: z.literal("preview"),
82
+ previewId: opaqueId,
83
+ contentHash: opaqueId,
84
+ operations: z.array(ConnectResource).max(2000),
85
+ })
86
+ .strict(),
87
+ z.object({ type: z.literal("none") }).strict(),
88
+ ]);
89
+ export type ConnectNextAction = z.infer<typeof ConnectNextAction>;
90
+ export const ConnectInstallationTarget = z
91
+ .object({
92
+ instanceKey: IntegrationInstanceKey,
93
+ displayName: z.string().min(1).max(200),
94
+ expectedInstanceVersion: z.number().int().positive().optional(),
95
+ })
96
+ .strict();
97
+ export type ConnectInstallationTarget = z.infer<typeof ConnectInstallationTarget>;
98
+ export const ConnectAttemptState = z.enum([
99
+ "ready",
100
+ "requires_user_action",
101
+ "credential_input",
102
+ "provider_wait",
103
+ "account_selection",
104
+ "resource_selection",
105
+ "preview",
106
+ "installing",
107
+ "connected_but_incomplete",
108
+ "complete",
109
+ "cancelled",
110
+ "expired",
111
+ "failed",
112
+ "uncertain",
113
+ ]);
114
+ export const ConnectAttempt = z
115
+ .object({
116
+ id: opaqueId,
117
+ workspaceId: opaqueId,
118
+ providerId: opaqueId,
119
+ ownership: ConnectOwnership,
120
+ revision: z.number().int().positive(),
121
+ state: ConnectAttemptState,
122
+ credentialsCommitted: z.boolean(),
123
+ integrationInstalled: z.boolean(),
124
+ completionRequirement: z.enum(["connection", "integration", "provider_setup"]),
125
+ nextAction: ConnectNextAction,
126
+ expiresAt: z.string().datetime({ offset: true }),
127
+ account: ConnectAccount.optional(),
128
+ installationTarget: ConnectInstallationTarget.optional(),
129
+ source: IntegrationSource.optional(),
130
+ error: z
131
+ .object({ code: opaqueId, message: z.string().max(2048), retryable: z.boolean() })
132
+ .strict()
133
+ .optional(),
134
+ })
135
+ .strict()
136
+ .superRefine((value, context) => {
137
+ if (
138
+ value.state === "complete" &&
139
+ value.completionRequirement === "integration" &&
140
+ !value.integrationInstalled
141
+ ) {
142
+ context.addIssue({
143
+ code: "custom",
144
+ message: "Complete setup requires an installed integration",
145
+ });
146
+ }
147
+ if (
148
+ value.state === "complete" &&
149
+ value.completionRequirement === "connection" &&
150
+ !value.credentialsCommitted
151
+ ) {
152
+ context.addIssue({
153
+ code: "custom",
154
+ message: "Connection setup requires committed credentials",
155
+ });
156
+ }
157
+ if (
158
+ ["complete", "cancelled", "expired"].includes(value.state) &&
159
+ value.nextAction.type !== "none"
160
+ ) {
161
+ context.addIssue({ code: "custom", message: "A terminal setup has no next action" });
162
+ }
163
+ });
164
+ export type ConnectAttempt = z.infer<typeof ConnectAttempt>;
165
+ export const ConnectAdvance = z.discriminatedUnion("type", [
166
+ z
167
+ .object({
168
+ type: z.literal("credentials"),
169
+ values: z.record(z.string().max(256), z.string().max(16_384)),
170
+ })
171
+ .strict(),
172
+ z.object({ type: z.literal("account"), accountId: opaqueId }).strict(),
173
+ z.object({ type: z.literal("resources"), resourceIds: z.array(opaqueId).max(1000) }).strict(),
174
+ z
175
+ .object({
176
+ type: z.literal("install"),
177
+ previewId: opaqueId,
178
+ contentHash: opaqueId,
179
+ operationIds: z.array(opaqueId).max(2000),
180
+ })
181
+ .strict(),
182
+ z.object({ type: z.literal("retry") }).strict(),
183
+ ]);
184
+ export type ConnectAdvance = z.infer<typeof ConnectAdvance>;
185
+ export const ConnectOperationRequest = z
186
+ .object({
187
+ expectedRevision: z.number().int().positive().safe(),
188
+ idempotencyKey: opaqueId,
189
+ })
190
+ .strict();
191
+ export const AdvanceConnectRequest = ConnectOperationRequest.extend({ action: ConnectAdvance });
192
+ export const BeginConnectRequest = z
193
+ .object({
194
+ providerId: opaqueId,
195
+ ownership: ConnectOwnership,
196
+ // URL parsing validates separately; never transform this original string.
197
+ returnUrl: z.string().min(1).max(4096),
198
+ idempotencyKey: opaqueId,
199
+ reconnectAccountId: opaqueId.optional(),
200
+ installationTarget: ConnectInstallationTarget.optional(),
201
+ })
202
+ .strict();
@@ -0,0 +1,46 @@
1
+ /** Display identity from an already authorized connection. Never used to select credentials. */
2
+ export function connectionAccountIdentityLabel(
3
+ metadata: Record<string, unknown>,
4
+ fallback: string,
5
+ ): string {
6
+ const text = (value: unknown): string | undefined =>
7
+ typeof value === "string" && value.trim()
8
+ ? value
9
+ .replace(/[\u0000-\u001f\u007f]/gu, " ")
10
+ .trim()
11
+ .slice(0, 180)
12
+ : undefined;
13
+ const nestedName = (value: unknown): unknown =>
14
+ value && typeof value === "object" ? (value as Record<string, unknown>).name : value;
15
+ const name =
16
+ [
17
+ metadata.email,
18
+ metadata.providerEmail,
19
+ metadata.googleEmail,
20
+ metadata.gmailEmail,
21
+ metadata.accountLabel,
22
+ metadata.displayName,
23
+ metadata.providerDisplayName,
24
+ metadata.googleDisplayName,
25
+ metadata.accountName,
26
+ metadata.name,
27
+ metadata.slackUserName,
28
+ metadata.username,
29
+ metadata.slackUserId,
30
+ ]
31
+ .map(text)
32
+ .find(Boolean) ?? fallback;
33
+ const workspace = [
34
+ metadata.slackTeamName,
35
+ metadata.teamName,
36
+ metadata.workspaceName,
37
+ metadata.team_name,
38
+ metadata.workspace_name,
39
+ nestedName(metadata.team),
40
+ nestedName(metadata.workspace),
41
+ metadata.slackTeamId,
42
+ ]
43
+ .map(text)
44
+ .find(Boolean);
45
+ return [...new Set([name, workspace].filter(Boolean))].join(" · ");
46
+ }
@@ -0,0 +1,213 @@
1
+ import { z } from "zod";
2
+ import { ConnectionKind, SessionTenancyVisibility } from "./index";
3
+
4
+ export const ConnectionAuthoritySelectionSource = z.enum(["explicit_workspace", "sender"]);
5
+ export type ConnectionAuthoritySelectionSource = z.infer<typeof ConnectionAuthoritySelectionSource>;
6
+
7
+ export const ConnectionUseSelectionSource = z
8
+ .string()
9
+ .min(1)
10
+ .max(128)
11
+ .regex(/^[a-z0-9](?:[a-z0-9._:-]*[a-z0-9])?$/u);
12
+ export type ConnectionUseSelectionSource = z.infer<typeof ConnectionUseSelectionSource>;
13
+
14
+ const AcceptedConnectionWork = z.discriminatedUnion("kind", [
15
+ z
16
+ .object({
17
+ kind: z.literal("turn"),
18
+ turnId: z.string().uuid(),
19
+ })
20
+ .strict(),
21
+ z
22
+ .object({
23
+ kind: z.literal("scheduled_task"),
24
+ taskId: z.string().uuid(),
25
+ taskAuthorityRevision: z.number().int().positive(),
26
+ runId: z.string().uuid(),
27
+ })
28
+ .strict(),
29
+ ]);
30
+
31
+ /**
32
+ * Internal, credential-free authority frozen when work is accepted. Personal
33
+ * owner identity is retained only for live authorization and usage/audit
34
+ * attribution; it is never part of the public delegation envelope.
35
+ */
36
+ export const ConnectionUseAuthoritySnapshot = z
37
+ .object({
38
+ organizationId: z.string().uuid(),
39
+ originWorkspaceId: z.string().uuid(),
40
+ targetWorkspaceId: z.string().uuid(),
41
+ targetSessionId: z.string().uuid(),
42
+ targetSessionVisibility: SessionTenancyVisibility,
43
+ targetSessionAuthorityEpoch: z.number().int().positive(),
44
+ acceptedWork: AcceptedConnectionWork,
45
+ connectionId: z.string().uuid(),
46
+ connectionGeneration: z.number().int().positive(),
47
+ connectionStatus: z.literal("active"),
48
+ providerDomain: z.string().min(1).max(2048),
49
+ connectionKind: ConnectionKind,
50
+ scope: z.enum(["workspace", "user"]),
51
+ ownerSubjectId: z.string().min(1).max(512).nullable(),
52
+ ownerOrganizationMembershipId: z.string().uuid().nullable(),
53
+ ownerMembershipAuthorizationRevision: z.number().int().positive().nullable().default(null),
54
+ authoritySource: ConnectionAuthoritySelectionSource,
55
+ selectionSources: z.array(ConnectionUseSelectionSource).min(1).max(128),
56
+ userDelegation: z.null(),
57
+ })
58
+ .strict()
59
+ .superRefine((value, context) => {
60
+ const ownedBySubject = value.scope !== "workspace";
61
+ const delegated = value.scope === "user";
62
+ if (ownedBySubject !== (value.ownerSubjectId !== null)) {
63
+ context.addIssue({
64
+ code: "custom",
65
+ path: ["ownerSubjectId"],
66
+ message: "personal connections retain an owner subject",
67
+ });
68
+ }
69
+ if (delegated !== (value.ownerOrganizationMembershipId !== null)) {
70
+ context.addIssue({
71
+ code: "custom",
72
+ path: ["ownerOrganizationMembershipId"],
73
+ message: "only user connections retain an owner membership",
74
+ });
75
+ }
76
+ if (delegated !== (value.ownerMembershipAuthorizationRevision !== null)) {
77
+ context.addIssue({
78
+ code: "custom",
79
+ path: ["ownerMembershipAuthorizationRevision"],
80
+ message: "only user connections retain an owner membership revision",
81
+ });
82
+ }
83
+ if (delegated && value.authoritySource !== "sender") {
84
+ context.addIssue({
85
+ code: "custom",
86
+ path: ["authoritySource"],
87
+ message: "user connections require authenticated sender provenance",
88
+ });
89
+ }
90
+ if (!delegated && value.authoritySource === "sender") {
91
+ context.addIssue({
92
+ code: "custom",
93
+ path: ["authoritySource"],
94
+ message: "workspace connections cannot claim sender provenance",
95
+ });
96
+ }
97
+ if (!delegated && value.originWorkspaceId !== value.targetWorkspaceId) {
98
+ context.addIssue({
99
+ code: "custom",
100
+ path: ["originWorkspaceId"],
101
+ message: "workspace connections must be owned by the target workspace",
102
+ });
103
+ }
104
+ });
105
+ export type ConnectionUseAuthoritySnapshot = z.infer<typeof ConnectionUseAuthoritySnapshot>;
106
+
107
+ export const ConnectionUseDenialReason = z.enum([
108
+ "tenant_mismatch",
109
+ "workspace_access_inactive",
110
+ "session_inactive",
111
+ "session_identity_changed",
112
+ "session_visibility_changed",
113
+ "session_authority_epoch_changed",
114
+ "accepted_attempt_authority_required",
115
+ "accepted_snapshot_digest_changed",
116
+ "connection_missing",
117
+ "connection_identity_changed",
118
+ "connection_generation_changed",
119
+ "connection_status_inactive",
120
+ "connection_owner_changed",
121
+ "owner_membership_inactive",
122
+ "authority_missing",
123
+ "authority_identity_changed",
124
+ "authority_generation_changed",
125
+ "authority_status_inactive",
126
+ "grant_missing",
127
+ "grant_identity_changed",
128
+ "grant_generation_changed",
129
+ "grant_status_inactive",
130
+ "grant_expired",
131
+ "grant_already_consumed",
132
+ ]);
133
+ export type ConnectionUseDenialReason = z.infer<typeof ConnectionUseDenialReason>;
134
+
135
+ const ConnectionUseAttributionFields = z
136
+ .object({
137
+ organizationId: z.string().uuid(),
138
+ workspaceId: z.string().uuid(),
139
+ sessionId: z.string().uuid(),
140
+ connectionId: z.string().uuid(),
141
+ connectionGeneration: z.number().int().positive(),
142
+ scope: z.enum(["workspace", "user", "legacy_user"]),
143
+ ownerSubjectId: z.string().min(1).max(512).nullable(),
144
+ authorityId: z.string().uuid().nullable(),
145
+ grantId: z.string().uuid().nullable(),
146
+ })
147
+ .strict();
148
+
149
+ function refineConnectionUseAttribution(
150
+ value: z.infer<typeof ConnectionUseAttributionFields>,
151
+ context: z.RefinementCtx,
152
+ ): void {
153
+ const personal = value.scope !== "workspace";
154
+ for (const field of ["ownerSubjectId"] as const) {
155
+ if (personal !== (value[field] !== null)) {
156
+ context.addIssue({
157
+ code: "custom",
158
+ path: [field],
159
+ message: personal
160
+ ? `personal attribution requires ${field}`
161
+ : `workspace attribution cannot carry ${field}`,
162
+ });
163
+ }
164
+ }
165
+ const owned = value.scope === "user";
166
+ for (const field of ["authorityId"] as const) {
167
+ if (owned !== (value[field] !== null)) {
168
+ context.addIssue({
169
+ code: "custom",
170
+ path: [field],
171
+ message: owned
172
+ ? `personal attribution requires ${field}`
173
+ : `non-personal attribution cannot carry ${field}`,
174
+ });
175
+ }
176
+ }
177
+ if (!owned && value.grantId !== null) {
178
+ context.addIssue({
179
+ code: "custom",
180
+ path: ["grantId"],
181
+ message: "only historical personal attribution can carry a grant",
182
+ });
183
+ }
184
+ }
185
+
186
+ /** Metadata-only attribution emitted after pre-use authorization. */
187
+ export const ConnectionUseAttribution = ConnectionUseAttributionFields.extend({
188
+ scope: z.enum(["workspace", "user"]),
189
+ grantId: z.null(),
190
+ }).superRefine(refineConnectionUseAttribution);
191
+ export type ConnectionUseAttribution = z.infer<typeof ConnectionUseAttribution>;
192
+
193
+ export const ConnectionUseAuditFact = ConnectionUseAttributionFields.extend({
194
+ outcome: z.enum(["authorized", "denied"]),
195
+ denialReason: ConnectionUseDenialReason.nullable(),
196
+ occurredAt: z.string().datetime({ offset: true }),
197
+ }).superRefine((value, context) => {
198
+ refineConnectionUseAttribution(value, context);
199
+ if ((value.outcome === "denied") !== (value.denialReason !== null)) {
200
+ context.addIssue({
201
+ code: "custom",
202
+ path: ["denialReason"],
203
+ message: "only denied connection use carries a denial reason",
204
+ });
205
+ }
206
+ });
207
+ export type ConnectionUseAuditFact = z.infer<typeof ConnectionUseAuditFact>;
208
+
209
+ export const ConnectionUseAuthorizationResult = z.discriminatedUnion("status", [
210
+ z.object({ status: z.literal("authorized"), attribution: ConnectionUseAttribution }).strict(),
211
+ z.object({ status: z.literal("denied"), reason: ConnectionUseDenialReason }).strict(),
212
+ ]);
213
+ export type ConnectionUseAuthorizationResult = z.infer<typeof ConnectionUseAuthorizationResult>;