@opengeni/contracts 0.39.0 → 0.44.1

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 (130) hide show
  1. package/dist/atlassian.d.ts +278 -0
  2. package/dist/atlassian.js +55 -0
  3. package/dist/atlassian.js.map +1 -0
  4. package/dist/chunk-52SGB2QO.js +688 -0
  5. package/dist/chunk-52SGB2QO.js.map +1 -0
  6. package/dist/{chunk-7JZMI22I.js → chunk-5UDNP7AO.js} +34 -2
  7. package/dist/chunk-5UDNP7AO.js.map +1 -0
  8. package/dist/chunk-BVGIYW7D.js +11 -0
  9. package/dist/chunk-BVGIYW7D.js.map +1 -0
  10. package/dist/chunk-CADSX6UN.js +1145 -0
  11. package/dist/chunk-CADSX6UN.js.map +1 -0
  12. package/dist/chunk-D2HKF2EF.js +1460 -0
  13. package/dist/chunk-D2HKF2EF.js.map +1 -0
  14. package/dist/chunk-FJBG5E4O.js +194 -0
  15. package/dist/chunk-FJBG5E4O.js.map +1 -0
  16. package/dist/chunk-H5BVCZKF.js +382 -0
  17. package/dist/chunk-H5BVCZKF.js.map +1 -0
  18. package/dist/chunk-LSB7GRLG.js +779 -0
  19. package/dist/chunk-LSB7GRLG.js.map +1 -0
  20. package/dist/chunk-MYBZRDTY.js +340 -0
  21. package/dist/chunk-MYBZRDTY.js.map +1 -0
  22. package/dist/chunk-RIY7GYQS.js +1204 -0
  23. package/dist/chunk-RIY7GYQS.js.map +1 -0
  24. package/dist/chunk-TZ6YEYN4.js +386 -0
  25. package/dist/chunk-TZ6YEYN4.js.map +1 -0
  26. package/dist/chunk-VA22KRHS.js +15177 -0
  27. package/dist/chunk-VA22KRHS.js.map +1 -0
  28. package/dist/chunk-Y3MLSLB4.js +392 -0
  29. package/dist/chunk-Y3MLSLB4.js.map +1 -0
  30. package/dist/chunk-YRKRZ6OF.js +134 -0
  31. package/dist/chunk-YRKRZ6OF.js.map +1 -0
  32. package/dist/company-profile.d.ts +629 -0
  33. package/dist/document-artifact-commands.d.ts +282 -0
  34. package/dist/document-artifact-commands.js +54 -0
  35. package/dist/document-artifact-commands.js.map +1 -0
  36. package/dist/document-artifact-query.d.ts +2 -0
  37. package/dist/document-artifact-query.js +54 -0
  38. package/dist/document-artifact-query.js.map +1 -0
  39. package/dist/editable-artifact-binary.d.ts +56 -0
  40. package/dist/editable-artifact-causal-frontier.d.ts +12 -0
  41. package/dist/editable-artifact-causal-frontier.js +18 -0
  42. package/dist/editable-artifact-causal-frontier.js.map +1 -0
  43. package/dist/editable-artifact-codec-registry.d.ts +48 -0
  44. package/dist/editable-artifact-codec-registry.js +20 -0
  45. package/dist/editable-artifact-codec-registry.js.map +1 -0
  46. package/dist/editable-artifact-committed-transaction.d.ts +35 -0
  47. package/dist/editable-artifact-committed-transaction.js +19 -0
  48. package/dist/editable-artifact-committed-transaction.js.map +1 -0
  49. package/dist/editable-artifact-live.d.ts +276 -0
  50. package/dist/editable-artifact-live.js +907 -0
  51. package/dist/editable-artifact-live.js.map +1 -0
  52. package/dist/editable-artifact-serialized-commit.d.ts +53 -0
  53. package/dist/editable-artifact-serialized-commit.js +26 -0
  54. package/dist/editable-artifact-serialized-commit.js.map +1 -0
  55. package/dist/editable-artifact-versions.d.ts +6 -0
  56. package/dist/editable-artifact-versions.js +11 -0
  57. package/dist/editable-artifact-versions.js.map +1 -0
  58. package/dist/editable-artifacts.d.ts +46 -0
  59. package/dist/editable-artifacts.js +236 -0
  60. package/dist/editable-artifacts.js.map +1 -0
  61. package/dist/event-preview.d.ts +7 -7
  62. package/dist/google-drive.d.ts +114 -2
  63. package/dist/google-drive.js +70 -14
  64. package/dist/google-drive.js.map +1 -1
  65. package/dist/image-generation.d.ts +70 -0
  66. package/dist/index.d.ts +5180 -329
  67. package/dist/index.js +1173 -40
  68. package/dist/interaction.d.ts +6895 -0
  69. package/dist/mcp-receipts.d.ts +96 -0
  70. package/dist/memory-slack-delivery.d.ts +397 -0
  71. package/dist/presentation-artifact-commands.d.ts +349 -0
  72. package/dist/presentation-artifact-commands.js +66 -0
  73. package/dist/presentation-artifact-commands.js.map +1 -0
  74. package/dist/presentation-artifact-query.d.ts +2 -0
  75. package/dist/presentation-artifact-query.js +66 -0
  76. package/dist/presentation-artifact-query.js.map +1 -0
  77. package/dist/retained-output.d.ts +83 -6
  78. package/dist/sandbox-snapshots.d.ts +9 -0
  79. package/dist/scoped-knowledge.d.ts +14 -13
  80. package/dist/slack-bot-scopes.d.ts +4 -0
  81. package/dist/slack-bot-scopes.js +3 -1
  82. package/dist/spreadsheet-artifact-commands.d.ts +101 -0
  83. package/dist/spreadsheet-artifact-commands.js +27 -0
  84. package/dist/spreadsheet-artifact-commands.js.map +1 -0
  85. package/dist/spreadsheet-artifact-date.d.ts +4 -0
  86. package/dist/spreadsheet-artifact-query.d.ts +120 -0
  87. package/dist/spreadsheet-artifact-query.js +48 -0
  88. package/dist/spreadsheet-artifact-query.js.map +1 -0
  89. package/dist/tool-catalog.d.ts +576 -0
  90. package/dist/video-generation.d.ts +532 -0
  91. package/dist/video-generation.js +51 -0
  92. package/dist/video-generation.js.map +1 -0
  93. package/dist/workspace-learning-policy.d.ts +208 -0
  94. package/package.json +61 -1
  95. package/src/atlassian.ts +160 -0
  96. package/src/company-profile.ts +306 -0
  97. package/src/document-artifact-commands.ts +1709 -0
  98. package/src/document-artifact-query.ts +2 -0
  99. package/src/editable-artifact-binary.ts +396 -0
  100. package/src/editable-artifact-causal-frontier.ts +154 -0
  101. package/src/editable-artifact-codec-registry.ts +261 -0
  102. package/src/editable-artifact-committed-transaction.ts +478 -0
  103. package/src/editable-artifact-live.ts +1379 -0
  104. package/src/editable-artifact-serialized-commit.ts +494 -0
  105. package/src/editable-artifact-versions.ts +8 -0
  106. package/src/editable-artifacts.ts +473 -0
  107. package/src/event-preview.ts +6 -6
  108. package/src/google-drive.ts +68 -15
  109. package/src/image-generation.ts +106 -0
  110. package/src/index.ts +2535 -282
  111. package/src/interaction.ts +2292 -0
  112. package/src/mcp-receipts.ts +281 -0
  113. package/src/memory-slack-delivery.ts +183 -0
  114. package/src/presentation-artifact-commands.ts +2035 -0
  115. package/src/presentation-artifact-query.ts +2 -0
  116. package/src/retained-output.ts +248 -8
  117. package/src/sandbox-snapshots.ts +28 -1
  118. package/src/scoped-knowledge.ts +18 -4
  119. package/src/slack-bot-scopes.ts +34 -1
  120. package/src/spreadsheet-artifact-commands.ts +999 -0
  121. package/src/spreadsheet-artifact-date.ts +21 -0
  122. package/src/spreadsheet-artifact-query.ts +1411 -0
  123. package/src/tool-catalog.ts +334 -0
  124. package/src/video-generation.ts +394 -0
  125. package/src/workspace-learning-policy.ts +233 -0
  126. package/dist/chunk-7JZMI22I.js.map +0 -1
  127. package/dist/chunk-PCTCJEAF.js +0 -10799
  128. package/dist/chunk-PCTCJEAF.js.map +0 -1
  129. package/dist/secret-redaction.d.ts +0 -40
  130. package/src/secret-redaction.ts +0 -364
package/src/index.ts CHANGED
@@ -1,15 +1,27 @@
1
1
  import { z } from "zod";
2
+ import { ScopedKnowledgeScope } from "./scoped-knowledge";
2
3
  import {
3
4
  boundSessionEventPayload,
4
5
  measureSessionEventJson,
5
6
  sessionEventJsonBytes,
6
7
  type SessionEventBoundarySurface,
7
8
  } from "./event-preview";
9
+ import { MemorySlackPublicationDistribution } from "./memory-slack-delivery";
8
10
  import { WorkspaceInstructionPolicyRoleKeyInput } from "./workspace-instruction-policies";
9
11
  import { ClientResumableVoiceInputConfig } from "./transcription-recordings";
12
+ import { MediaGenerationResult } from "./video-generation";
10
13
 
11
14
  export * from "./slack-bot-scopes";
15
+ export * from "./atlassian";
12
16
  export * from "./connector-destinations";
17
+ export * from "./memory-slack-delivery";
18
+ export * from "./image-generation";
19
+ export * from "./video-generation";
20
+ export * from "./editable-artifacts";
21
+ export * from "./editable-artifact-committed-transaction";
22
+ export * from "./editable-artifact-serialized-commit";
23
+ export * from "./tool-catalog";
24
+ export * from "./interaction";
13
25
 
14
26
  export {
15
27
  CreateWorkspaceArtifactRequest,
@@ -36,6 +48,19 @@ export {
36
48
  normalizeWorkspaceArtifactSlug,
37
49
  } from "./artifacts";
38
50
 
51
+ export {
52
+ MCP_MUTATION_RECEIPT_MAX_BYTES,
53
+ MCP_MUTATION_RECEIPT_VERSION,
54
+ McpMutationReceipt,
55
+ McpMutationReceiptIdempotencyStatus,
56
+ McpMutationReceiptOutcome,
57
+ McpMutationResource,
58
+ type McpMutationReceipt as McpMutationReceiptType,
59
+ type McpMutationReceiptIdempotencyStatus as McpMutationReceiptIdempotencyStatusType,
60
+ type McpMutationReceiptOutcome as McpMutationReceiptOutcomeType,
61
+ type McpMutationResource as McpMutationResourceType,
62
+ } from "./mcp-receipts";
63
+
39
64
  export {
40
65
  SESSION_EVENT_PAYLOAD_MAX_BYTES,
41
66
  approximateSessionEventTokens,
@@ -53,6 +78,13 @@ export {
53
78
  } from "./event-preview";
54
79
 
55
80
  export {
81
+ COMPUTER_SCREENSHOT_MAX_BYTES,
82
+ COMPUTER_SCREENSHOT_MAX_DIMENSION,
83
+ COMPUTER_SCREENSHOT_MAX_PIXELS,
84
+ COMPUTER_SCREENSHOT_RETENTION_MS,
85
+ COMPUTER_SCREENSHOT_WORKSPACE_QUOTA_BYTES,
86
+ GENERATED_IMAGE_MAX_BYTES,
87
+ GENERATED_VIDEO_MAX_BYTES,
56
88
  RETAINED_OUTPUT_DEFAULT_PAGE_BYTES,
57
89
  RETAINED_OUTPUT_MAX_PAGE_BYTES,
58
90
  RETAINED_OUTPUT_RECEIPT_MAX_BYTES,
@@ -63,12 +95,18 @@ export {
63
95
  RetainedOutputKind,
64
96
  RetainedOutputUnavailableReason,
65
97
  retainedArtifactReferenceFromFile,
98
+ retainedGeneratedImageReferenceFromFile,
99
+ retainedGeneratedVideoReferenceFromFile,
100
+ retainedScreenshotReferenceFromFile,
66
101
  retainedOutputUnavailable,
67
102
  resolveRetainedOutputRange,
68
103
  validateRetainedOutputEvidence,
69
104
  type RetainedArtifactFileInput,
70
105
  type RetainedArtifactMetadata,
71
106
  type RetainedArtifactReference,
107
+ type RetainedGeneratedImageArtifactInput,
108
+ type RetainedGeneratedVideoArtifactInput,
109
+ type RetainedScreenshotArtifactInput,
72
110
  type RetainedArtifactUnavailable,
73
111
  type RetainedOutputAvailableEvidence,
74
112
  type RetainedOutputEvidence,
@@ -81,6 +119,7 @@ export {
81
119
  WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION,
82
120
  backendForNativeSnapshotProvider,
83
121
  decodeNativeSnapshotRef,
122
+ encodeNativeSnapshotRef,
84
123
  parseWorkspaceArchiveDescriptor,
85
124
  type NativeSnapshotDescriptor,
86
125
  type NativeSnapshotProvider,
@@ -127,6 +166,54 @@ export const SandboxBackend = z.enum([
127
166
  ]);
128
167
  export type SandboxBackend = z.infer<typeof SandboxBackend>;
129
168
 
169
+ // OpenGeni-owned identity carried beside the provider's opaque SDK envelope.
170
+ // Provider serializers intentionally use different keys (`sandboxId`,
171
+ // `devboxId`, `sandboxName`, ...); durable lease logic must not need to learn a
172
+ // new provider's private state shape. Existing envelopes remain readable via
173
+ // the legacy keys below, while every newly-serialized envelope carries this
174
+ // stable field.
175
+ export const OPENGENI_SANDBOX_PROVIDER_INSTANCE_ID_FIELD = "opengeniProviderInstanceId" as const;
176
+ export const SANDBOX_PROVIDER_INSTANCE_ID_FIELDS_BY_BACKEND = {
177
+ docker: ["containerId"],
178
+ modal: ["sandboxId"],
179
+ local: ["workspaceRootPath"],
180
+ none: [],
181
+ daytona: ["sandboxId"],
182
+ runloop: ["devboxId"],
183
+ e2b: ["sandboxId"],
184
+ // A Blaxel name is reusable after deletion. The SDK persists a canonical
185
+ // metadata identity (name + creation timestamp + workspace) specifically to
186
+ // distinguish a later sandbox created under the same name.
187
+ blaxel: ["sandboxIdentity"],
188
+ cloudflare: ["sandboxId"],
189
+ vercel: ["sandboxId"],
190
+ selfhosted: ["agentId"],
191
+ } as const satisfies Record<SandboxBackend, readonly string[]>;
192
+ export const LEGACY_SANDBOX_PROVIDER_INSTANCE_ID_FIELDS = [
193
+ "sandboxId",
194
+ "devboxId",
195
+ "sandboxName",
196
+ "sandboxIdentity",
197
+ "containerId",
198
+ "workspaceRootPath",
199
+ "agentId",
200
+ ] as const;
201
+
202
+ /**
203
+ * Durable proof that a provider may replace an execution wrapper without
204
+ * replacing the workspace OpenGeni owns. This is intentionally narrower than
205
+ * generic provider resume: only a provider adapter that can prove the same
206
+ * continuity key may consume it, and only a cold->warming owner or teardown
207
+ * claimant may authorize that replacement.
208
+ */
209
+ export type SandboxProviderContinuityRecovery = {
210
+ version: 1;
211
+ backend: SandboxBackend;
212
+ kind: "docker_workspace";
213
+ sourceInstanceId: string;
214
+ continuityKey: string;
215
+ };
216
+
130
217
  // OS axis. Only "linux" is reachable in v1; macos/windows are seam placeholders.
131
218
  export const SandboxOs = z.enum(["linux", "macos", "windows"]);
132
219
  export type SandboxOs = z.infer<typeof SandboxOs>;
@@ -197,6 +284,7 @@ export const DESKTOP_STREAM_PORT = 6080;
197
284
  // ttyd's default; the box bakes ttyd and launches it on this port. The pty-ws
198
285
  // Terminal cell's `url` is the tunnel address resolved against this port.
199
286
  export const TERMINAL_STREAM_PORT = 7681;
287
+ export const BROWSER_CONTROL_PORT = 7682;
200
288
 
201
289
  // The provider capability matrix (sandbox contract PART D + module 03-providers). One row per
202
290
  // backend (10 rows). v1 reachable cells are all Linux; macos/windows are seam
@@ -596,9 +684,9 @@ export const Permission = z.enum([
596
684
  "sessions:control",
597
685
  // sandbox workspace (sandbox contract §C.3 / crosscut PART 1.2). stream:view is a
598
686
  // REAL, distinct permission — strictly BROADER than sessions:read — because the
599
- // pixel plane (Channel B) is UN-REDACTED: a viewer of raw pixels can see cloud
600
- // creds the agent cat's into a terminal, which the redacted Channel-A event log
601
- // never exposes. sessions:read is NOT permission to watch raw pixels.
687
+ // pixel plane (Channel B) exposes raw pixels: a viewer can see content the
688
+ // structured Channel-A event log never captured. sessions:read is NOT
689
+ // permission to watch raw pixels.
602
690
  "stream:view",
603
691
  // SEPARATE from stream:view: raw input to the desktop (bypasses approvalQueue /
604
692
  // interrupt). NEVER granted by default in v1 (the input plane is OFF —
@@ -629,8 +717,14 @@ export const Permission = z.enum([
629
717
  "environments:manage",
630
718
  /** @deprecated alias of variable-sets:use */
631
719
  "environments:use",
720
+ "variable-sets:list",
721
+ "variable-sets:read",
722
+ "variable-sets:write",
632
723
  "variable-sets:manage",
633
724
  "variable-sets:use",
725
+ "secrets:list",
726
+ "secrets:read",
727
+ "secrets:write",
634
728
  // Attach or rotate per-session third-party MCP server credentials. Deliberately
635
729
  // not part of the worker's default first-party MCP permission set: a sandboxed
636
730
  // agent must not be able to hand itself new bearer credentials.
@@ -638,7 +732,7 @@ export const Permission = z.enum([
638
732
  // Programmatic sandbox -> tool access through the first-party MCP gate. This is
639
733
  // intentionally narrow and is never part of first-party MCP defaults; callers
640
734
  // must receive it through an explicit delegated `ogd_` mint carrying sessionId.
641
- "toolspace:call",
735
+ "codemode:call",
642
736
  "goals:manage",
643
737
  // Bring-your-own-compute (M5). enrollments:read lists a workspace's machines;
644
738
  // enrollments:manage approves a device-flow enrollment (the LOUD whole-machine
@@ -671,6 +765,7 @@ export type Permission = z.infer<typeof Permission>;
671
765
  */
672
766
  export const DEFAULT_FIRST_PARTY_MCP_PERMISSIONS = [
673
767
  "workspace:read",
768
+ "files:upload",
674
769
  "files:read",
675
770
  "documents:search",
676
771
  "scheduled_tasks:manage",
@@ -715,6 +810,7 @@ export const FIRST_PARTY_MCP_TOOL_NAMES = [
715
810
  "sandbox_swap",
716
811
  "run_on",
717
812
  "sandbox_provision",
813
+ "connected_machine_remove",
718
814
  "rig_list",
719
815
  "rig_get",
720
816
  "rig_propose_change",
@@ -729,10 +825,27 @@ export const FIRST_PARTY_MCP_TOOL_NAMES = [
729
825
  "session_resume",
730
826
  "session_steer",
731
827
  "set_other_session_title",
828
+ "interaction_discover",
829
+ "browser_open",
830
+ "browser_tabs",
831
+ "browser_observe",
832
+ "browser_act",
833
+ "browser_debug",
834
+ "browser_identity",
835
+ "browser_publish",
836
+ "browser_lifecycle",
837
+ "computer_open",
838
+ "computer_targets",
839
+ "computer_observe",
840
+ "computer_act",
841
+ "computer_lifecycle",
732
842
  "variable_set_list",
733
843
  "environment_list",
844
+ "variable_set_get_variable",
734
845
  "variable_set_set_variable",
735
846
  "environment_set_variable",
847
+ "capability_catalog_search",
848
+ "capability_authorization_request",
736
849
  "github_connect_link",
737
850
  "github_repositories_list",
738
851
  "social_connections_list",
@@ -743,6 +856,18 @@ export const FIRST_PARTY_MCP_TOOL_NAMES = [
743
856
  "social_thread_fetch",
744
857
  "social_posts_sync",
745
858
  "social_post_reply",
859
+ "x_accounts_list",
860
+ "x_search_live",
861
+ "x_mentions_live",
862
+ "x_thread_fetch",
863
+ "x_posts_sync",
864
+ "x_post_reply",
865
+ "reddit_accounts_list",
866
+ "reddit_search_live",
867
+ "reddit_mentions_live",
868
+ "reddit_thread_fetch",
869
+ "reddit_posts_sync",
870
+ "reddit_post_reply",
746
871
  "scheduled_tasks_list",
747
872
  "scheduled_tasks_get",
748
873
  "scheduled_tasks_create",
@@ -761,22 +886,81 @@ export const FIRST_PARTY_MCP_TOOL_NAMES = [
761
886
  "slack_bot_file_content",
762
887
  "slack_bot_post_message",
763
888
  "slack_bot_delete_message",
889
+ "atlassian_sources_list",
890
+ "atlassian_search",
891
+ "atlassian_get",
764
892
  "artifacts_list",
765
893
  "artifacts_get_source",
766
894
  "artifacts_create",
767
895
  "artifacts_publish",
768
896
  "artifacts_rollback",
897
+ "editable_artifact_list",
898
+ "editable_artifact_create",
899
+ "editable_artifact_import",
900
+ "editable_artifact_get",
901
+ "editable_artifact_inspect",
902
+ "editable_artifact_apply",
903
+ "editable_artifact_export",
904
+ "editable_artifact_export_status",
769
905
  ] as const;
770
906
  export const FirstPartyMcpToolName = z.enum(FIRST_PARTY_MCP_TOOL_NAMES);
771
907
  export type FirstPartyMcpToolName = z.infer<typeof FirstPartyMcpToolName>;
772
908
 
909
+ /**
910
+ * First-party interaction tools executed inside the frozen attempt rather than
911
+ * registered on the remote `opengeni` MCP server. They still belong to the
912
+ * same user-selectable first-party catalog and use the same attempt executor.
913
+ */
914
+ export const FIRST_PARTY_IN_PROCESS_TOOL_NAMES = [
915
+ "interaction_discover",
916
+ "browser_open",
917
+ "browser_tabs",
918
+ "browser_observe",
919
+ "browser_act",
920
+ "browser_debug",
921
+ "browser_identity",
922
+ "browser_publish",
923
+ "browser_lifecycle",
924
+ "computer_open",
925
+ "computer_targets",
926
+ "computer_observe",
927
+ "computer_act",
928
+ "computer_lifecycle",
929
+ ] as const satisfies readonly FirstPartyMcpToolName[];
930
+
931
+ const FIRST_PARTY_IN_PROCESS_TOOL_NAME_SET = new Set<FirstPartyMcpToolName>(
932
+ FIRST_PARTY_IN_PROCESS_TOOL_NAMES,
933
+ );
934
+
935
+ /** Exact catalog registered by the remote first-party `opengeni` MCP server. */
936
+ export const FIRST_PARTY_REMOTE_MCP_TOOL_NAMES = FIRST_PARTY_MCP_TOOL_NAMES.filter(
937
+ (name) => !FIRST_PARTY_IN_PROCESS_TOOL_NAME_SET.has(name),
938
+ ) satisfies readonly FirstPartyMcpToolName[];
939
+
940
+ /** Authored CodeMode paths for the canonical collaborative artifact surface. */
941
+ export const EDITABLE_ARTIFACT_MCP_CODEMODE_PATHS = {
942
+ editable_artifact_list: ["artifacts", "list"],
943
+ editable_artifact_create: ["artifacts", "create"],
944
+ editable_artifact_import: ["artifacts", "import"],
945
+ editable_artifact_get: ["artifacts", "get"],
946
+ editable_artifact_inspect: ["artifacts", "inspect"],
947
+ editable_artifact_apply: ["artifacts", "apply"],
948
+ editable_artifact_export: ["artifacts", "export"],
949
+ editable_artifact_export_status: ["artifacts", "exportStatus"],
950
+ } as const satisfies Partial<Record<FirstPartyMcpToolName, readonly [string, string]>>;
951
+
773
952
  /**
774
953
  * Connector-wide tools are explicit-only. Ordinary session omission selects
775
954
  * the non-connector catalog, while an explicit session policy may still select
776
955
  * any catalogued connector tool and remains independently permission-gated.
777
956
  */
778
957
  export const DEFAULT_FIRST_PARTY_MCP_TOOLS = FIRST_PARTY_MCP_TOOL_NAMES.filter(
779
- (name) => !name.startsWith("social_") && !name.startsWith("slack_bot_"),
958
+ (name) =>
959
+ !name.startsWith("social_") &&
960
+ !name.startsWith("x_") &&
961
+ !name.startsWith("reddit_") &&
962
+ !name.startsWith("slack_bot_") &&
963
+ !name.startsWith("atlassian_"),
780
964
  ) satisfies readonly FirstPartyMcpToolName[];
781
965
 
782
966
  export function prefixedMcpToolName(registryId: string, toolName: string): string {
@@ -1192,12 +1376,7 @@ export * from "./transcription-recordings";
1192
1376
  export const CodexCompactionMode = z.enum(["remote_v2", "portable"]);
1193
1377
  export type CodexCompactionMode = z.infer<typeof CodexCompactionMode>;
1194
1378
 
1195
- export const SlackReactionEmojiName = z
1196
- .string()
1197
- .trim()
1198
- .min(1)
1199
- .max(64)
1200
- .regex(/^[a-z0-9_+-]+$/, "use the exact Slack emoji name without surrounding colons");
1379
+ export const SlackReactionEmojiName = z.literal("genie");
1201
1380
  export type SlackReactionEmojiName = z.infer<typeof SlackReactionEmojiName>;
1202
1381
 
1203
1382
  export const WorkspaceSlackReactionChannelPolicy = z.discriminatedUnion("mode", [
@@ -1262,6 +1441,9 @@ export const WorkspaceSettingsSchema = z
1262
1441
  // Default compaction strategy for NEW Codex sessions created in this
1263
1442
  // workspace. Absent ⇒ remote_v2. Non-Codex sessions always freeze portable.
1264
1443
  codexCompactionDefault: CodexCompactionMode.optional(),
1444
+ // Whether agents may expose and invoke the built-in structured human-input
1445
+ // tool. Absent preserves the historical enabled behavior.
1446
+ agentHumanInputEnabled: z.boolean().optional(),
1265
1447
  // Optional Slack reaction invocation. Absent/invalid fails closed to the
1266
1448
  // disabled default via resolveWorkspaceSlackReactionSummonSettings.
1267
1449
  slackReactionSummon: WorkspaceSlackReactionSummonSettings.optional(),
@@ -1282,6 +1464,12 @@ export function resolveWorkspaceCodexCompactionDefault(settings: unknown): Codex
1282
1464
  return parsed.data.codexCompactionDefault ?? "remote_v2";
1283
1465
  }
1284
1466
 
1467
+ /** Whether agents may request structured human input (enabled when unset). */
1468
+ export function resolveWorkspaceAgentHumanInputEnabled(settings: unknown): boolean {
1469
+ const parsed = WorkspaceSettingsSchema.safeParse(settings ?? {});
1470
+ return parsed.success ? parsed.data.agentHumanInputEnabled !== false : true;
1471
+ }
1472
+
1285
1473
  /**
1286
1474
  * Resolve whether voice input is enabled for a workspace.
1287
1475
  *
@@ -1307,7 +1495,9 @@ export function resolveWorkspaceSlackReactionSummonSettings(
1307
1495
  return {
1308
1496
  enabled: DEFAULT_WORKSPACE_SLACK_REACTION_SUMMON_SETTINGS.enabled,
1309
1497
  emoji: DEFAULT_WORKSPACE_SLACK_REACTION_SUMMON_SETTINGS.emoji,
1310
- channelPolicy: { ...DEFAULT_WORKSPACE_SLACK_REACTION_SUMMON_SETTINGS.channelPolicy },
1498
+ channelPolicy: {
1499
+ ...DEFAULT_WORKSPACE_SLACK_REACTION_SUMMON_SETTINGS.channelPolicy,
1500
+ },
1311
1501
  };
1312
1502
  }
1313
1503
  return configured.channelPolicy.mode === "allowlist"
@@ -1342,6 +1532,7 @@ export const UpdateWorkspaceSettingsRequest = z
1342
1532
  transcription: WorkspaceTranscriptionPolicy.optional(),
1343
1533
  maxNestedAgentDepth: NestedAgentDepthValue.nullable().optional(),
1344
1534
  codexCompactionDefault: CodexCompactionMode.optional(),
1535
+ agentHumanInputEnabled: z.boolean().optional(),
1345
1536
  slackReactionSummon: WorkspaceSlackReactionSummonSettings.optional(),
1346
1537
  })
1347
1538
  .passthrough();
@@ -1669,6 +1860,11 @@ export const EnrollmentBearerPayload = z.object({
1669
1860
  workspaceId: z.string().uuid(),
1670
1861
  agentId: z.string().uuid(),
1671
1862
  enrollmentId: z.string().uuid(),
1863
+ // Backward-compatible credential-family fence. Generationless bearers minted
1864
+ // before migration 0061 parse ONLY as generation 1, matching the migration's
1865
+ // default for existing rows. signEnrollmentBearer serializes the parsed output,
1866
+ // so every newly signed bearer carries this claim explicitly.
1867
+ credentialGeneration: z.number().int().positive().default(1),
1672
1868
  // The Account-scoped control-plane subject prefix the agent subscribes to.
1673
1869
  subjectPrefix: z.string().min(1),
1674
1870
  exp: z.number().int().positive(),
@@ -1703,7 +1899,13 @@ export async function verifyEnrollmentBearer(
1703
1899
  if (!constantTimeEqual(signature, expected)) {
1704
1900
  return null;
1705
1901
  }
1706
- const payload = EnrollmentBearerPayload.safeParse(JSON.parse(base64UrlDecode(encodedPayload)));
1902
+ let decoded: unknown;
1903
+ try {
1904
+ decoded = JSON.parse(base64UrlDecode(encodedPayload));
1905
+ } catch {
1906
+ return null;
1907
+ }
1908
+ const payload = EnrollmentBearerPayload.safeParse(decoded);
1707
1909
  if (!payload.success || payload.data.exp < nowSeconds) {
1708
1910
  return null;
1709
1911
  }
@@ -2035,6 +2237,61 @@ export const UpdateWorkspaceMemberRequest = z.object({
2035
2237
  });
2036
2238
  export type UpdateWorkspaceMemberRequest = z.infer<typeof UpdateWorkspaceMemberRequest>;
2037
2239
 
2240
+ export const SlackUserLinkAccessRequestStatus = z.enum([
2241
+ "prepared",
2242
+ "pending",
2243
+ "completed",
2244
+ "denied",
2245
+ "cancelled",
2246
+ "expired",
2247
+ ]);
2248
+ export type SlackUserLinkAccessRequestStatus = z.infer<typeof SlackUserLinkAccessRequestStatus>;
2249
+
2250
+ /**
2251
+ * Durable, token-free projection of one signed Slack identity-link intent.
2252
+ * The original bearer and its digest are deliberately absent from every
2253
+ * public response.
2254
+ */
2255
+ export const SlackUserLinkAccessRequest = z.object({
2256
+ id: z.string().uuid(),
2257
+ workspaceId: z.string().uuid(),
2258
+ workspaceDisplayName: z.string().min(1).max(256).nullable(),
2259
+ subjectLabel: z.string().min(1).max(512).nullable(),
2260
+ status: SlackUserLinkAccessRequestStatus,
2261
+ version: z.number().int().positive(),
2262
+ expiresAt: z.string().datetime({ offset: true }),
2263
+ requestedAt: z.string().datetime({ offset: true }).nullable(),
2264
+ decidedAt: z.string().datetime({ offset: true }).nullable(),
2265
+ completedAt: z.string().datetime({ offset: true }).nullable(),
2266
+ createdAt: z.string().datetime({ offset: true }),
2267
+ updatedAt: z.string().datetime({ offset: true }),
2268
+ });
2269
+ export type SlackUserLinkAccessRequest = z.infer<typeof SlackUserLinkAccessRequest>;
2270
+
2271
+ export const PrepareSlackUserLinkAccessRequest = z.object({
2272
+ linkToken: z.string().min(1).max(2_048),
2273
+ });
2274
+ export type PrepareSlackUserLinkAccessRequest = z.infer<typeof PrepareSlackUserLinkAccessRequest>;
2275
+
2276
+ export const SlackUserLinkAccessMutationRequest = z.object({
2277
+ expectedVersion: z.number().int().positive(),
2278
+ idempotencyKey: z.string().trim().min(1).max(200),
2279
+ });
2280
+ export type SlackUserLinkAccessMutationRequest = z.infer<typeof SlackUserLinkAccessMutationRequest>;
2281
+
2282
+ export const ApproveSlackUserLinkAccessRequest = SlackUserLinkAccessMutationRequest.extend({
2283
+ role: z.string().trim().min(1).max(128).optional(),
2284
+ permissions: z.array(Permission).min(1),
2285
+ });
2286
+ export type ApproveSlackUserLinkAccessRequest = z.infer<typeof ApproveSlackUserLinkAccessRequest>;
2287
+
2288
+ export const ListSlackUserLinkAccessRequestsResponse = z.object({
2289
+ requests: z.array(SlackUserLinkAccessRequest),
2290
+ });
2291
+ export type ListSlackUserLinkAccessRequestsResponse = z.infer<
2292
+ typeof ListSlackUserLinkAccessRequestsResponse
2293
+ >;
2294
+
2038
2295
  export const UsageEventType = z.enum([
2039
2296
  "agent_run.created",
2040
2297
  "agent_run.completed",
@@ -2044,6 +2301,10 @@ export const UsageEventType = z.enum([
2044
2301
  "file.deleted",
2045
2302
  "document.indexed",
2046
2303
  "scheduled_task.fired",
2304
+ "knowledge_source_sync.fired",
2305
+ "knowledge_source_sync.completed",
2306
+ "knowledge_source_sync.items",
2307
+ "knowledge_source_sync.bytes",
2047
2308
  "api_key.request",
2048
2309
  // --- sandbox warm-time metering (P2.1) ---
2049
2310
  // Wall-clock seconds a box was warm — the billable warm-time meter. Accrued on
@@ -2082,6 +2343,9 @@ export type InsightsRange = z.infer<typeof InsightsRange>;
2082
2343
  export const InsightsBillingPath = z.enum(["opengeni_credits", "external"]);
2083
2344
  export type InsightsBillingPath = z.infer<typeof InsightsBillingPath>;
2084
2345
 
2346
+ export const InsightsPricingSource = z.enum(["configured_list_price", "gateway_reported"]);
2347
+ export type InsightsPricingSource = z.infer<typeof InsightsPricingSource>;
2348
+
2085
2349
  export const InsightsModelUsageRow = z.object({
2086
2350
  id: z.string().min(1),
2087
2351
  model: z.string().min(1),
@@ -2091,10 +2355,17 @@ export const InsightsModelUsageRow = z.object({
2091
2355
  inputTokens: z.number().nonnegative(),
2092
2356
  outputTokens: z.number().nonnegative(),
2093
2357
  cachedTokens: z.number().nonnegative(),
2358
+ cacheInputTokens: z.number().nonnegative(),
2094
2359
  cacheWriteTokens: z.number().nonnegative(),
2095
2360
  reasoningTokens: z.number().nonnegative(),
2361
+ totalTokens: z.number().nonnegative(),
2362
+ tokenKnownCalls: z.number().int().nonnegative(),
2363
+ cacheKnownCalls: z.number().int().nonnegative(),
2096
2364
  /** Priced OpenGeni credit $ for this model×provider (from model_call_facts). */
2097
2365
  creditUsd: z.number().nonnegative(),
2366
+ /** Hypothetical provider-rate USD; never an OpenGeni charge. */
2367
+ estimatedProviderUsd: z.number().nonnegative(),
2368
+ estimatedProviderCostKnownCalls: z.number().int().nonnegative(),
2098
2369
  });
2099
2370
  export type InsightsModelUsageRow = z.infer<typeof InsightsModelUsageRow>;
2100
2371
 
@@ -2102,9 +2373,19 @@ export const InsightsSeriesPoint = z.object({
2102
2373
  label: z.string().min(1),
2103
2374
  /** Day-bucketed sum of usage_events.model.cost (workspace-wide) or filtered facts when provider/model set. */
2104
2375
  modelCostUsd: z.number().nonnegative(),
2376
+ /** Day-bucketed hypothetical provider-rate USD for calls with captured pricing. */
2377
+ estimatedProviderUsd: z.number().nonnegative(),
2378
+ estimatedProviderCostKnownCalls: z.number().int().nonnegative(),
2105
2379
  warmSeconds: z.number().nonnegative(),
2106
2380
  inputTokens: z.number().nonnegative(),
2381
+ outputTokens: z.number().nonnegative(),
2107
2382
  cachedTokens: z.number().nonnegative(),
2383
+ cacheInputTokens: z.number().nonnegative(),
2384
+ cacheWriteTokens: z.number().nonnegative(),
2385
+ reasoningTokens: z.number().nonnegative(),
2386
+ totalTokens: z.number().nonnegative(),
2387
+ tokenKnownCalls: z.number().int().nonnegative(),
2388
+ cacheKnownCalls: z.number().int().nonnegative(),
2108
2389
  cacheHitPct: z.number().int().min(0).max(100),
2109
2390
  calls: z.number().int().nonnegative(),
2110
2391
  });
@@ -2127,9 +2408,12 @@ export const InsightsSpendDriver = z.object({
2127
2408
  groupBy: z.enum(["root_session", "schedule"]),
2128
2409
  label: z.string().min(1),
2129
2410
  creditUsd: z.number().nonnegative(),
2411
+ estimatedProviderUsd: z.number().nonnegative(),
2412
+ estimatedProviderCostKnownCalls: z.number().int().nonnegative(),
2130
2413
  tokens: z.number().nonnegative(),
2131
2414
  cacheHitPct: z.number().int().min(0).max(100),
2132
2415
  pctOfCreditUsd: z.number().int().min(0).max(100),
2416
+ pctOfTokens: z.number().int().min(0).max(100),
2133
2417
  deltaUsdVsPrior: z.number(),
2134
2418
  });
2135
2419
  export type InsightsSpendDriver = z.infer<typeof InsightsSpendDriver>;
@@ -2176,18 +2460,48 @@ export const InsightsScheduleRow = z.object({
2176
2460
  fires: z.number().int().nonnegative(),
2177
2461
  /** Null when no facts carry scheduled_task_id for this window. */
2178
2462
  creditUsd: z.number().nonnegative().nullable(),
2463
+ estimatedProviderUsd: z.number().nonnegative().nullable(),
2464
+ estimatedProviderCostKnownCalls: z.number().int().nonnegative().nullable(),
2179
2465
  tokens: z.number().nonnegative().nullable(),
2180
2466
  cacheHitPct: z.number().int().min(0).max(100).nullable(),
2181
2467
  billing: InsightsBillingPath.nullable(),
2182
2468
  });
2183
2469
  export type InsightsScheduleRow = z.infer<typeof InsightsScheduleRow>;
2184
2470
 
2471
+ export const InsightsModelCallRow = z.object({
2472
+ id: z.string().uuid(),
2473
+ occurredAt: z.string().datetime(),
2474
+ recordedAt: z.string().datetime(),
2475
+ sessionId: z.string().uuid(),
2476
+ sessionTitle: z.string(),
2477
+ turnId: z.string().uuid(),
2478
+ provider: z.string().min(1),
2479
+ providerApi: z.string().min(1),
2480
+ model: z.string().min(1),
2481
+ billing: InsightsBillingPath,
2482
+ inputTokens: z.number().nonnegative().nullable(),
2483
+ outputTokens: z.number().nonnegative().nullable(),
2484
+ cachedTokens: z.number().nonnegative().nullable(),
2485
+ cacheWriteTokens: z.number().nonnegative().nullable(),
2486
+ reasoningTokens: z.number().nonnegative().nullable(),
2487
+ totalTokens: z.number().nonnegative().nullable(),
2488
+ /** OpenGeni credit price for this call. External calls are always zero. */
2489
+ creditUsd: z.number().nonnegative(),
2490
+ /** Hypothetical provider-rate USD; null when historical pricing is unavailable. */
2491
+ estimatedProviderUsd: z.number().nonnegative().nullable(),
2492
+ pricingSource: InsightsPricingSource.nullable(),
2493
+ });
2494
+ export type InsightsModelCallRow = z.infer<typeof InsightsModelCallRow>;
2495
+
2185
2496
  export const WorkspaceInsightsSnapshot = z.object({
2186
2497
  range: InsightsRange,
2187
2498
  rangeLabel: z.string().min(1),
2188
2499
  priorLabel: z.string().min(1),
2189
2500
  seriesLabel: z.string().min(1),
2190
2501
  cacheSeriesLabel: z.string().min(1),
2502
+ windowStart: z.string().datetime(),
2503
+ windowEnd: z.string().datetime(),
2504
+ generatedAt: z.string().datetime(),
2191
2505
  /** All ranges/series are UTC. */
2192
2506
  timezone: z.literal("UTC"),
2193
2507
  models: z.array(InsightsModelUsageRow),
@@ -2197,6 +2511,7 @@ export const WorkspaceInsightsSnapshot = z.object({
2197
2511
  depth: z.array(InsightsDepthBucket),
2198
2512
  drivers: z.array(InsightsSpendDriver),
2199
2513
  schedules: z.array(InsightsScheduleRow),
2514
+ recentCalls: z.array(InsightsModelCallRow),
2200
2515
  warmSeconds: z.number().nonnegative(),
2201
2516
  priorWarmSeconds: z.number().nonnegative(),
2202
2517
  warmGroups: z.array(InsightsWarmGroupRow),
@@ -2210,7 +2525,14 @@ export const WorkspaceInsightsSnapshot = z.object({
2210
2525
  /** Model-filterable credit $ from facts (equals workspace when unfiltered, ignoring late-reject drift). */
2211
2526
  creditUsd: z.number().nonnegative(),
2212
2527
  priorCreditUsd: z.number().nonnegative(),
2528
+ /** Hypothetical provider-rate USD for calls whose historical price was captured. */
2529
+ estimatedProviderUsd: z.number().nonnegative(),
2530
+ priorEstimatedProviderUsd: z.number().nonnegative(),
2531
+ estimatedProviderCostKnownCalls: z.number().int().nonnegative(),
2532
+ priorEstimatedProviderCostKnownCalls: z.number().int().nonnegative(),
2533
+ modelCalls: z.number().int().nonnegative(),
2213
2534
  priorInputTokens: z.number().nonnegative(),
2535
+ priorTotalTokens: z.number().nonnegative(),
2214
2536
  priorCacheHitPct: z.number().int().min(0).max(100),
2215
2537
  priorCalls: z.number().int().nonnegative(),
2216
2538
  /** Lifetime workspace topology (not scoped to the selected Insights range). */
@@ -2357,7 +2679,7 @@ export type GitCredentialRepositoryRef = z.infer<typeof GitCredentialRepositoryR
2357
2679
  // `loadVariableSetForRun` (today decrypted with
2358
2680
  // `environmentsEncryptionKeyBytes(settings)`).
2359
2681
  // - MCP credentials: request-time transport headers for connection-backed
2360
- // servers, shared by normal model tools and Toolspace/Code Mode.
2682
+ // servers, shared by normal model tools and Codemode/Code Mode.
2361
2683
  //
2362
2684
  // In embedded/separate topologies the HOST owns these external connections
2363
2685
  // (its GitHub App, its secret vault + encryption key). When a host binds this
@@ -2510,13 +2832,6 @@ export type RunCredentialAuthNeeded = {
2510
2832
  message?: string;
2511
2833
  };
2512
2834
 
2513
- export type RunCredentialRedaction = {
2514
- /** Bounded diagnostic label used only in the replacement marker. */
2515
- name: string;
2516
- /** One atomic secret value that must be removed from streamed/audit output. */
2517
- value: string;
2518
- };
2519
-
2520
2835
  export type RunCredentialsRequest = {
2521
2836
  accountId: string;
2522
2837
  workspaceId: string;
@@ -2562,12 +2877,6 @@ export type RunCredentialsResolution =
2562
2877
  files?: RunCredentialFile[];
2563
2878
  /** Environment name to one returned relative file path. */
2564
2879
  fileEnvironment?: Record<string, string>;
2565
- /**
2566
- * Atomic sensitive values embedded inside credential files or derived
2567
- * material. Environment values are registered automatically; hosts list
2568
- * additional file-contained values here so chunked output is redacted.
2569
- */
2570
- redactions?: RunCredentialRedaction[];
2571
2880
  /** Earliest material expiry. Null/omitted uses a bounded refresh cadence. */
2572
2881
  expiresAt?: string | null;
2573
2882
  /** Partial degradation: usable material may coexist with reconnect notices. */
@@ -2653,7 +2962,7 @@ export const McpPersonalConnectionDelegation = z
2653
2962
  ownerSubjectId: z.string().min(1).max(512),
2654
2963
  providerDomain: z.string().min(1).max(2048),
2655
2964
  kind: z.enum(["oauth2", "api_key", "app_install", "delegated"]).optional(),
2656
- connectionType: z.enum(["mcp", "social"]).optional(),
2965
+ connectionType: z.enum(["mcp", "social", "atlassian"]).optional(),
2657
2966
  })
2658
2967
  .strict();
2659
2968
  export type McpPersonalConnectionDelegation = z.infer<typeof McpPersonalConnectionDelegation>;
@@ -2689,7 +2998,7 @@ export type McpPersonalConnectionSummary = z.infer<typeof McpPersonalConnectionS
2689
2998
  export type McpCredentialsRequest = {
2690
2999
  accountId: string;
2691
3000
  workspaceId: string;
2692
- /** Immediate session whose model or Toolspace call needs the credential. */
3001
+ /** Immediate session whose model or Codemode call needs the credential. */
2693
3002
  sessionId: string;
2694
3003
  /** Workspace-scoped lineage root for host authorization and binding lookup. */
2695
3004
  rootSessionId: string;
@@ -2702,9 +3011,16 @@ export type McpCredentialsRequest = {
2702
3011
  initiatorContext: TurnInitiatorContext;
2703
3012
  /** Immediate technical caller, retained only as non-authoritative audit context. */
2704
3013
  callerSubjectId?: string;
2705
- surface: "model" | "toolspace";
3014
+ surface: "model" | "codemode";
2706
3015
  /** Canonical MCP destination that will receive the resolved headers. */
2707
3016
  destinationUrl: string;
3017
+ /**
3018
+ * Credential transport requested by the caller. Omitted means the existing
3019
+ * header-only MCP transport. The additive `http_api` target allows embedding
3020
+ * hosts to return query/cookie API-key placements for local API integrations
3021
+ * without making those placements eligible for a remote MCP request.
3022
+ */
3023
+ credentialTarget?: "mcp" | "http_api";
2708
3024
  serverId: string;
2709
3025
  toolName?: string;
2710
3026
  connectionRef: McpServerConnectionRef;
@@ -2717,6 +3033,13 @@ export type McpCredentialAuthNeededReason =
2717
3033
  | "unsupported_auth"
2718
3034
  | "resource_scope_unavailable";
2719
3035
 
3036
+ export type ConnectionCredentialPlacement = {
3037
+ carrier: "header" | "query" | "cookie";
3038
+ name: string;
3039
+ value: string;
3040
+ prefix?: string;
3041
+ };
3042
+
2720
3043
  export type McpCredentialResolution =
2721
3044
  | {
2722
3045
  status: "ok";
@@ -2725,6 +3048,12 @@ export type McpCredentialResolution =
2725
3048
  workspaceId: string;
2726
3049
  sessionId: string;
2727
3050
  headers: Record<string, string>;
3051
+ /**
3052
+ * Optional normalized HTTP credential placements. When present, header
3053
+ * placements must exactly match `headers`. Query/cookie placements are
3054
+ * accepted only for a request whose credentialTarget is `http_api`.
3055
+ */
3056
+ placements?: ConnectionCredentialPlacement[];
2728
3057
  connectionId: string;
2729
3058
  providerDomain: string;
2730
3059
  provider?: string;
@@ -2765,7 +3094,7 @@ export type ConnectionCredentialsPort = {
2765
3094
  * Resolve rotating MCP transport credentials at request time. Embedded hosts
2766
3095
  * use this to keep their provider connection as the sole credential source;
2767
3096
  * OpenGeni never requires a duplicate connection record. The same resolver is
2768
- * used by model-visible MCP tools and the additive Toolspace/Code Mode proxy.
3097
+ * used by model-visible MCP tools and the exact-attempt Codemode projection.
2769
3098
  */
2770
3099
  mcpCredentials?(input: McpCredentialsRequest): Promise<McpCredentialResolution>;
2771
3100
  };
@@ -2959,6 +3288,93 @@ export function gitCredentialBindingIdForRepository(
2959
3288
  );
2960
3289
  }
2961
3290
 
3291
+ type GitRemotePathSemantics = "dot_git_alias" | "exact";
3292
+
3293
+ /**
3294
+ * Provider-declared remote-path behavior. Keeping this exhaustive makes a new
3295
+ * provider choose its semantics instead of inheriting GitHub conventions.
3296
+ */
3297
+ const GIT_REMOTE_PATH_SEMANTICS = {
3298
+ github: "dot_git_alias",
3299
+ gitlab: "dot_git_alias",
3300
+ azure_devops: "exact",
3301
+ } as const satisfies Record<GitCredentialProvider, GitRemotePathSemantics>;
3302
+
3303
+ function gitRemotePathSemantics(
3304
+ provider: GitCredentialProvider | null | undefined,
3305
+ ): GitRemotePathSemantics {
3306
+ return provider ? GIT_REMOTE_PATH_SEMANTICS[provider] : "exact";
3307
+ }
3308
+
3309
+ export class RepositoryUriError extends Error {
3310
+ constructor(message: string) {
3311
+ super(message);
3312
+ this.name = "RepositoryUriError";
3313
+ }
3314
+ }
3315
+
3316
+ /**
3317
+ * Normalize only the safe, provider-neutral parts of an HTTPS clone URI.
3318
+ *
3319
+ * The provider-defined path is opaque: this helper never adds or removes a
3320
+ * `.git` suffix. Embedded user info, query parameters, and fragments are not
3321
+ * durable resource identity and are omitted, matching the existing secret-free
3322
+ * resource contract.
3323
+ */
3324
+ export function normalizeRepositoryTransportUri(uri: string): string {
3325
+ let url: URL;
3326
+ try {
3327
+ url = new URL(uri.trim());
3328
+ } catch {
3329
+ throw new RepositoryUriError(`invalid repository URI: ${uri}`);
3330
+ }
3331
+ if (url.protocol !== "https:" || !url.hostname) {
3332
+ throw new RepositoryUriError("repository resources must use HTTPS Git URLs");
3333
+ }
3334
+ const path = url.pathname.replace(/^\/+|\/+$/g, "");
3335
+ if (path.split("/").filter(Boolean).length < 2) {
3336
+ throw new RepositoryUriError("repository URL must include owner and repo");
3337
+ }
3338
+ return `https://${url.host.toLowerCase()}/${path}`;
3339
+ }
3340
+
3341
+ /**
3342
+ * Return every URI spelling that a provider explicitly declares equivalent.
3343
+ * Exact-path and unqualified providers return only the normalized input URI.
3344
+ */
3345
+ export function gitRemoteUriAliases(
3346
+ uri: string,
3347
+ provider: GitCredentialProvider | null | undefined,
3348
+ ): string[] {
3349
+ const normalizedUri = normalizeRepositoryTransportUri(uri);
3350
+ if (gitRemotePathSemantics(provider) === "exact") {
3351
+ return [normalizedUri];
3352
+ }
3353
+ const base = normalizedUri.replace(/\.git$/, "");
3354
+ return [...new Set([normalizedUri, base, `${base}.git`])];
3355
+ }
3356
+
3357
+ /** Stable remote identity for deduplication and credential-binding ownership. */
3358
+ export function gitRemoteIdentity(
3359
+ uri: string,
3360
+ provider: GitCredentialProvider | null | undefined,
3361
+ ): string {
3362
+ const normalizedUri = normalizeRepositoryTransportUri(uri);
3363
+ return gitRemotePathSemantics(provider) === "dot_git_alias"
3364
+ ? normalizedUri.replace(/\.git$/, "")
3365
+ : normalizedUri;
3366
+ }
3367
+
3368
+ /** Provider-aware Git credential-helper path aliases, without a leading slash. */
3369
+ export function gitRemotePathAliases(
3370
+ uri: string,
3371
+ provider: GitCredentialProvider | null | undefined,
3372
+ ): string[] {
3373
+ return gitRemoteUriAliases(uri, provider).map((alias) =>
3374
+ new URL(alias).pathname.replace(/^\/+|\/+$/g, ""),
3375
+ );
3376
+ }
3377
+
2962
3378
  export const FileResourceRef = z.object({
2963
3379
  kind: z.literal("file"),
2964
3380
  fileId: z.string().uuid(),
@@ -2973,6 +3389,12 @@ export type FileResourceRef = z.infer<typeof FileResourceRef>;
2973
3389
  * reconstruct the same typed attachment input after a model switch or retry.
2974
3390
  */
2975
3391
  export const MODEL_ATTACHMENT_REFS_FIELD = "opengeni_attachment_refs" as const;
3392
+ /**
3393
+ * Structured timeline annotations retained beside the deterministic user-text
3394
+ * projection in canonical history. Provider adapters remove this OpenGeni
3395
+ * extension field; the numbered projection in `content` remains model-visible.
3396
+ */
3397
+ export const MODEL_TIMELINE_ANNOTATIONS_FIELD = "opengeni_timeline_annotations" as const;
2976
3398
 
2977
3399
  export const ResourceRef = z.discriminatedUnion("kind", [RepositoryResourceRef, FileResourceRef]);
2978
3400
  export type ResourceRef = z.infer<typeof ResourceRef>;
@@ -3039,7 +3461,10 @@ export function resourceMountPathCollisionKey(path: string): string {
3039
3461
  * GitLab, Azure DevOps, or a custom host do not collide. Encoding the host keeps
3040
3462
  * IPv6/custom-port identities inside one portable path segment.
3041
3463
  */
3042
- export function defaultRepositoryMountPath(uri: string): string {
3464
+ export function defaultRepositoryMountPath(
3465
+ uri: string,
3466
+ provider?: GitCredentialProvider | null,
3467
+ ): string {
3043
3468
  let url: URL;
3044
3469
  try {
3045
3470
  url = new URL(uri);
@@ -3049,7 +3474,11 @@ export function defaultRepositoryMountPath(uri: string): string {
3049
3474
  if (url.protocol !== "https:" || !url.host) {
3050
3475
  throw new ResourceMountPathError(`invalid repository URI for mount path: ${uri}`);
3051
3476
  }
3052
- const repositoryPath = url.pathname.replace(/^\/+|\/+$/g, "").replace(/\.git$/, "");
3477
+ const remotePath = url.pathname.replace(/^\/+|\/+$/g, "");
3478
+ const repositoryPath =
3479
+ gitRemotePathSemantics(provider) === "dot_git_alias"
3480
+ ? remotePath.replace(/\.git$/, "")
3481
+ : remotePath;
3053
3482
  const segments = repositoryPath.split("/").filter(Boolean);
3054
3483
  if (segments.length < 2) {
3055
3484
  throw new ResourceMountPathError(`repository URI must include owner and repo: ${uri}`);
@@ -3066,7 +3495,7 @@ export function resourceMountPath(resource: ResourceRef): string {
3066
3495
  if (resource.mountPath) return normalizeResourceMountPath(resource.mountPath);
3067
3496
  return resource.kind === "file"
3068
3497
  ? normalizeResourceMountPath(`${DEFAULT_FILE_RESOURCE_MOUNT_ROOT}/${resource.fileId}`)
3069
- : defaultRepositoryMountPath(resource.uri);
3498
+ : defaultRepositoryMountPath(resource.uri, gitCredentialProviderForRepository(resource));
3070
3499
  }
3071
3500
 
3072
3501
  /** Fail before sandbox execution when two resources share a portable path. */
@@ -3276,6 +3705,56 @@ export const DocumentSearchResponse = z.object({
3276
3705
  });
3277
3706
  export type DocumentSearchResponse = z.infer<typeof DocumentSearchResponse>;
3278
3707
 
3708
+ export const IndexedDocumentSource = z.object({
3709
+ kind: KnowledgeSourceKind,
3710
+ uri: z.string().nullable(),
3711
+ externalId: z.string().nullable(),
3712
+ title: z.string().nullable(),
3713
+ author: z.string().nullable(),
3714
+ createdAt: z.string().nullable(),
3715
+ updatedAt: z.string().nullable(),
3716
+ version: z.string().nullable(),
3717
+ });
3718
+ export type IndexedDocumentSource = z.infer<typeof IndexedDocumentSource>;
3719
+
3720
+ export const IndexedDocumentProvenance = z.object({
3721
+ ingestionWorkspaceId: z.string().uuid(),
3722
+ baseId: z.string().uuid(),
3723
+ fileId: z.string().uuid(),
3724
+ authorityKind: DocumentAuthorityKind,
3725
+ authorityWorkspaceId: z.string().uuid().nullable(),
3726
+ authoritySubjectId: z.string().nullable(),
3727
+ createdBy: z.string().nullable(),
3728
+ createdAt: z.string(),
3729
+ });
3730
+ export type IndexedDocumentProvenance = z.infer<typeof IndexedDocumentProvenance>;
3731
+
3732
+ export const IndexedDocumentSummary = z.object({
3733
+ id: z.string().uuid(),
3734
+ title: z.string(),
3735
+ parser: z.string(),
3736
+ chunkCount: z.number().int().nonnegative(),
3737
+ indexedAt: z.string(),
3738
+ summary: z.string().nullable(),
3739
+ topics: z.array(z.string()),
3740
+ source: IndexedDocumentSource,
3741
+ provenance: IndexedDocumentProvenance,
3742
+ });
3743
+ export type IndexedDocumentSummary = z.infer<typeof IndexedDocumentSummary>;
3744
+
3745
+ export const ListIndexedDocumentsRequest = z.object({
3746
+ checkpoint: z.string().min(1).max(1_024).optional(),
3747
+ limit: z.number().int().positive().max(100).default(50),
3748
+ });
3749
+ export type ListIndexedDocumentsRequest = z.infer<typeof ListIndexedDocumentsRequest>;
3750
+
3751
+ export const ListIndexedDocumentsResponse = z.object({
3752
+ documents: z.array(IndexedDocumentSummary),
3753
+ nextCheckpoint: z.string().min(1).max(1_024),
3754
+ hasMore: z.boolean(),
3755
+ });
3756
+ export type ListIndexedDocumentsResponse = z.infer<typeof ListIndexedDocumentsResponse>;
3757
+
3279
3758
  export const CreateDocumentBaseRequest = z.object({
3280
3759
  name: z.string().min(1),
3281
3760
  description: z.string().optional(),
@@ -3415,6 +3894,7 @@ export const CreateKnowledgeMemoryRequest = z.object({
3415
3894
  createdBySessionId: z.string().uuid().optional(),
3416
3895
  pinned: z.boolean().optional(),
3417
3896
  replacesId: z.string().min(1).optional(),
3897
+ slackPublication: MemorySlackPublicationDistribution.optional(),
3418
3898
  });
3419
3899
  export type CreateKnowledgeMemoryRequest = z.infer<typeof CreateKnowledgeMemoryRequest>;
3420
3900
 
@@ -3757,7 +4237,10 @@ export function resourceIdentityKey(resource: ResourceRef): string {
3757
4237
  if (resource.kind === "file") {
3758
4238
  return `file:${resource.fileId}`;
3759
4239
  }
3760
- return `repository:${resource.uri}`;
4240
+ return `repository:${gitRemoteIdentity(
4241
+ resource.uri,
4242
+ gitCredentialProviderForRepository(resource),
4243
+ )}`;
3761
4244
  }
3762
4245
 
3763
4246
  function sortJson(value: unknown): unknown {
@@ -4026,7 +4509,7 @@ export const SessionAuthorizationSurface = z.enum([
4026
4509
  "core",
4027
4510
  "stream",
4028
4511
  "first_party_mcp",
4029
- "toolspace",
4512
+ "codemode",
4030
4513
  ]);
4031
4514
  export type SessionAuthorizationSurface = z.infer<typeof SessionAuthorizationSurface>;
4032
4515
 
@@ -4314,7 +4797,8 @@ export const SessionAuthorizationOperation = z.enum([
4314
4797
  "session.viewer.read",
4315
4798
  "session.viewer.control",
4316
4799
  "session.first_party_mcp.call",
4317
- "session.toolspace.call",
4800
+ "session.secret.read",
4801
+ "session.codemode.call",
4318
4802
  "session.pin.write",
4319
4803
  "session.codex_account.write",
4320
4804
  "session.realtime.start",
@@ -4350,6 +4834,8 @@ export const SessionAuthorizationActor = z.discriminatedUnion("kind", [
4350
4834
  /** Frozen authority that admitted the calling turn. */
4351
4835
  initiator: TurnInitiator,
4352
4836
  initiatorContext: TurnInitiatorContext,
4837
+ /** Durable causal human for delegated/service work; null for pure service work. */
4838
+ initiatingHumanSubjectId: z.string().min(1).max(1024).nullable(),
4353
4839
  }),
4354
4840
  ]);
4355
4841
  export type SessionAuthorizationActor = z.infer<typeof SessionAuthorizationActor>;
@@ -4428,44 +4914,276 @@ export type SessionAuthorizationPort = {
4428
4914
  ): Promise<SessionAuthorizationListScope>;
4429
4915
  };
4430
4916
 
4431
- export const SessionTurn = z.object({
4432
- id: z.string().uuid(),
4433
- workspaceId: z.string().uuid(),
4434
- sessionId: z.string().uuid(),
4435
- triggerEventId: z.string().uuid(),
4436
- temporalWorkflowId: z.string(),
4437
- status: SessionTurnStatus,
4438
- source: SessionTurnSource,
4439
- position: z.number().int(),
4440
- prompt: z.string().min(1),
4441
- resources: z.array(ResourceRef),
4442
- tools: z.array(ToolRef),
4443
- // Omitted/default discovery and explicit `tools: []` are distinct. False
4444
- // inherits the durable session policy; true replaces it for this turn after
4445
- // admission proves the selection is a subset.
4446
- toolsProvided: z.boolean().optional(),
4447
- model: z.string().min(1),
4448
- reasoningEffort: ReasoningEffort,
4449
- latencyMode: LatencyMode.default("standard"),
4450
- sandboxBackend: SandboxBackend,
4451
- // Per-turn OS override. NULL = inherit the session's sandboxOs.
4452
- sandboxOs: SandboxOs.nullable(),
4453
- metadata: z.record(z.string(), z.unknown()),
4454
- version: z.number().int().positive(),
4455
- executionGeneration: z.number().int().nonnegative(),
4456
- activeAttemptId: z.string().uuid().nullable(),
4457
- lineage: z.record(z.string(), z.unknown()),
4458
- initiator: TurnInitiator,
4459
- initiatorContext: TurnInitiatorContext,
4460
- /** Secret-safe projection of the exact personal authority frozen on this turn. */
4461
- personalConnections: z.array(McpPersonalConnectionSummary).default([]),
4462
- cancelledBy: z.string().nullable(),
4463
- cancelReason: z.string().nullable(),
4464
- startedAt: z.string().nullable(),
4465
- finishedAt: z.string().nullable(),
4466
- createdAt: z.string(),
4467
- updatedAt: z.string(),
4468
- });
4917
+ export const TIMELINE_ANNOTATION_MAX_COUNT = 12;
4918
+ export const TIMELINE_ANNOTATION_QUOTE_MAX_BYTES = 16 * 1024;
4919
+ export const TIMELINE_ANNOTATION_NOTE_MAX_BYTES = 2 * 1024;
4920
+ export const TIMELINE_ANNOTATION_CONTEXT_MAX_BYTES = 512;
4921
+ export const TIMELINE_ANNOTATION_LABEL_MAX_BYTES = 256;
4922
+ export const TIMELINE_ANNOTATIONS_MAX_BYTES = 64 * 1024;
4923
+
4924
+ export const TimelineAnnotationSourceKind = z.enum([
4925
+ "user_message",
4926
+ "assistant_message",
4927
+ "tool_output",
4928
+ ]);
4929
+ export type TimelineAnnotationSourceKind = z.infer<typeof TimelineAnnotationSourceKind>;
4930
+
4931
+ export const TimelineAnnotationSourceEventType = z.enum([
4932
+ "user.message",
4933
+ "agent.message.completed",
4934
+ "agent.toolCall.output",
4935
+ ]);
4936
+ export type TimelineAnnotationSourceEventType = z.infer<typeof TimelineAnnotationSourceEventType>;
4937
+
4938
+ function timelineAnnotationUtf8Bytes(value: string): number {
4939
+ return new TextEncoder().encode(value).byteLength;
4940
+ }
4941
+
4942
+ function timelineAnnotationBoundedText(maxBytes: number, label: string) {
4943
+ return z.string().superRefine((value, ctx) => {
4944
+ if (timelineAnnotationUtf8Bytes(value) > maxBytes) {
4945
+ ctx.addIssue({
4946
+ code: z.ZodIssueCode.custom,
4947
+ message: `${label} must be at most ${maxBytes} UTF-8 bytes`,
4948
+ });
4949
+ }
4950
+ });
4951
+ }
4952
+
4953
+ export const TimelineAnnotationSource = z
4954
+ .object({
4955
+ kind: TimelineAnnotationSourceKind,
4956
+ eventId: z.string().uuid(),
4957
+ eventType: TimelineAnnotationSourceEventType,
4958
+ sequence: z.number().int().positive(),
4959
+ turnId: z.string().uuid().nullable(),
4960
+ startOffset: z.number().int().nonnegative(),
4961
+ endOffset: z.number().int().nonnegative(),
4962
+ contextBefore: timelineAnnotationBoundedText(
4963
+ TIMELINE_ANNOTATION_CONTEXT_MAX_BYTES,
4964
+ "annotation source contextBefore",
4965
+ ),
4966
+ contextAfter: timelineAnnotationBoundedText(
4967
+ TIMELINE_ANNOTATION_CONTEXT_MAX_BYTES,
4968
+ "annotation source contextAfter",
4969
+ ),
4970
+ label: timelineAnnotationBoundedText(
4971
+ TIMELINE_ANNOTATION_LABEL_MAX_BYTES,
4972
+ "annotation source label",
4973
+ ).optional(),
4974
+ })
4975
+ .strict()
4976
+ .superRefine((source, ctx) => {
4977
+ if (source.endOffset < source.startOffset) {
4978
+ ctx.addIssue({
4979
+ code: z.ZodIssueCode.custom,
4980
+ path: ["endOffset"],
4981
+ message: "annotation source endOffset must not precede startOffset",
4982
+ });
4983
+ }
4984
+ const expectedKind =
4985
+ source.eventType === "user.message"
4986
+ ? "user_message"
4987
+ : source.eventType === "agent.message.completed"
4988
+ ? "assistant_message"
4989
+ : "tool_output";
4990
+ if (source.kind !== expectedKind) {
4991
+ ctx.addIssue({
4992
+ code: z.ZodIssueCode.custom,
4993
+ path: ["kind"],
4994
+ message: "annotation source kind does not match eventType",
4995
+ });
4996
+ }
4997
+ });
4998
+ export type TimelineAnnotationSource = z.infer<typeof TimelineAnnotationSource>;
4999
+
5000
+ export const DraftTimelineAnnotation = z
5001
+ .object({
5002
+ id: z.string().uuid(),
5003
+ source: TimelineAnnotationSource,
5004
+ quote: timelineAnnotationBoundedText(TIMELINE_ANNOTATION_QUOTE_MAX_BYTES, "annotation quote"),
5005
+ note: timelineAnnotationBoundedText(TIMELINE_ANNOTATION_NOTE_MAX_BYTES, "annotation note"),
5006
+ })
5007
+ .strict()
5008
+ .superRefine((annotation, ctx) => {
5009
+ if (!annotation.quote.trim()) {
5010
+ ctx.addIssue({
5011
+ code: z.ZodIssueCode.custom,
5012
+ path: ["quote"],
5013
+ message: "annotation quote must contain non-whitespace text",
5014
+ });
5015
+ }
5016
+ });
5017
+ export type DraftTimelineAnnotation = z.infer<typeof DraftTimelineAnnotation>;
5018
+
5019
+ export const SubmittedTimelineAnnotation = DraftTimelineAnnotation.superRefine(
5020
+ (annotation, ctx) => {
5021
+ if (!annotation.note.trim()) {
5022
+ ctx.addIssue({
5023
+ code: z.ZodIssueCode.custom,
5024
+ path: ["note"],
5025
+ message: "annotation note must contain non-whitespace text",
5026
+ });
5027
+ }
5028
+ },
5029
+ );
5030
+ export type SubmittedTimelineAnnotation = z.infer<typeof SubmittedTimelineAnnotation>;
5031
+
5032
+ export const TimelineAnnotation = z
5033
+ .object({
5034
+ id: z.string().uuid(),
5035
+ source: TimelineAnnotationSource,
5036
+ quote: timelineAnnotationBoundedText(TIMELINE_ANNOTATION_QUOTE_MAX_BYTES, "annotation quote"),
5037
+ note: timelineAnnotationBoundedText(
5038
+ TIMELINE_ANNOTATION_NOTE_MAX_BYTES,
5039
+ "annotation note",
5040
+ ).refine((value) => value.trim().length > 0, {
5041
+ message: "annotation note must contain non-whitespace text",
5042
+ }),
5043
+ ordinal: z.number().int().positive(),
5044
+ })
5045
+ .strict();
5046
+ export type TimelineAnnotation = z.infer<typeof TimelineAnnotation>;
5047
+
5048
+ function timelineAnnotationArray<T extends z.ZodTypeAny>(item: T) {
5049
+ return z
5050
+ .array(item)
5051
+ .max(TIMELINE_ANNOTATION_MAX_COUNT)
5052
+ .superRefine((annotations, ctx) => {
5053
+ const ids = new Set<string>();
5054
+ for (let index = 0; index < annotations.length; index += 1) {
5055
+ const id = (annotations[index] as { id?: unknown }).id;
5056
+ if (typeof id === "string" && ids.has(id)) {
5057
+ ctx.addIssue({
5058
+ code: z.ZodIssueCode.custom,
5059
+ path: [index, "id"],
5060
+ message: "annotation ids must be unique",
5061
+ });
5062
+ }
5063
+ if (typeof id === "string") ids.add(id);
5064
+ }
5065
+ if (
5066
+ timelineAnnotationUtf8Bytes(JSON.stringify(annotations)) > TIMELINE_ANNOTATIONS_MAX_BYTES
5067
+ ) {
5068
+ ctx.addIssue({
5069
+ code: z.ZodIssueCode.custom,
5070
+ message: `annotations must be at most ${TIMELINE_ANNOTATIONS_MAX_BYTES} UTF-8 bytes`,
5071
+ });
5072
+ }
5073
+ });
5074
+ }
5075
+
5076
+ export const DraftTimelineAnnotations = timelineAnnotationArray(DraftTimelineAnnotation);
5077
+ export type DraftTimelineAnnotations = z.infer<typeof DraftTimelineAnnotations>;
5078
+
5079
+ export const SubmittedTimelineAnnotations = timelineAnnotationArray(SubmittedTimelineAnnotation);
5080
+ export type SubmittedTimelineAnnotations = z.infer<typeof SubmittedTimelineAnnotations>;
5081
+
5082
+ export const TimelineAnnotations = timelineAnnotationArray(TimelineAnnotation).superRefine(
5083
+ (annotations, ctx) => {
5084
+ for (let index = 0; index < annotations.length; index += 1) {
5085
+ if (annotations[index]!.ordinal !== index + 1) {
5086
+ ctx.addIssue({
5087
+ code: z.ZodIssueCode.custom,
5088
+ path: [index, "ordinal"],
5089
+ message: "annotation ordinals must be contiguous and match array order",
5090
+ });
5091
+ }
5092
+ }
5093
+ },
5094
+ );
5095
+ export type TimelineAnnotations = z.infer<typeof TimelineAnnotations>;
5096
+
5097
+ export function numberTimelineAnnotations(
5098
+ annotations: readonly SubmittedTimelineAnnotation[],
5099
+ ): TimelineAnnotation[] {
5100
+ return annotations.map((annotation, index) => ({
5101
+ ...annotation,
5102
+ source: { ...annotation.source },
5103
+ ordinal: index + 1,
5104
+ }));
5105
+ }
5106
+
5107
+ export function renderTimelineAnnotationsForModel(
5108
+ text: string,
5109
+ annotations: readonly TimelineAnnotation[],
5110
+ ): string {
5111
+ if (annotations.length === 0) return text;
5112
+ const sections = annotations.flatMap((annotation) => [
5113
+ `Annotation ${annotation.ordinal}`,
5114
+ `Source: ${JSON.stringify({
5115
+ kind: annotation.source.kind,
5116
+ eventId: annotation.source.eventId,
5117
+ eventType: annotation.source.eventType,
5118
+ sequence: annotation.source.sequence,
5119
+ turnId: annotation.source.turnId,
5120
+ startOffset: annotation.source.startOffset,
5121
+ endOffset: annotation.source.endOffset,
5122
+ contextBefore: annotation.source.contextBefore,
5123
+ contextAfter: annotation.source.contextAfter,
5124
+ ...(annotation.source.label ? { label: annotation.source.label } : {}),
5125
+ })}`,
5126
+ `Exact quote: ${JSON.stringify(annotation.quote)}`,
5127
+ `User note: ${JSON.stringify(annotation.note)}`,
5128
+ ]);
5129
+ return [
5130
+ ...(text.length > 0 ? [text, ""] : []),
5131
+ "[OpenGeni timeline annotations]",
5132
+ ...sections.flatMap((line, index) =>
5133
+ index > 0 && line.startsWith("Annotation ") ? ["", line] : [line],
5134
+ ),
5135
+ ].join("\n");
5136
+ }
5137
+
5138
+ export const SessionTurn = z
5139
+ .object({
5140
+ id: z.string().uuid(),
5141
+ workspaceId: z.string().uuid(),
5142
+ sessionId: z.string().uuid(),
5143
+ triggerEventId: z.string().uuid(),
5144
+ temporalWorkflowId: z.string(),
5145
+ status: SessionTurnStatus,
5146
+ source: SessionTurnSource,
5147
+ position: z.number().int(),
5148
+ prompt: z.string(),
5149
+ annotations: TimelineAnnotations.default([]),
5150
+ resources: z.array(ResourceRef),
5151
+ tools: z.array(ToolRef),
5152
+ // Omitted/default discovery and explicit `tools: []` are distinct. False
5153
+ // inherits the durable session policy; true replaces it for this turn after
5154
+ // admission proves the selection is a subset.
5155
+ toolsProvided: z.boolean().optional(),
5156
+ model: z.string().min(1),
5157
+ reasoningEffort: ReasoningEffort,
5158
+ latencyMode: LatencyMode.default("standard"),
5159
+ sandboxBackend: SandboxBackend,
5160
+ // Per-turn OS override. NULL = inherit the session's sandboxOs.
5161
+ sandboxOs: SandboxOs.nullable(),
5162
+ metadata: z.record(z.string(), z.unknown()),
5163
+ version: z.number().int().positive(),
5164
+ executionGeneration: z.number().int().nonnegative(),
5165
+ activeAttemptId: z.string().uuid().nullable(),
5166
+ lineage: z.record(z.string(), z.unknown()),
5167
+ initiator: TurnInitiator,
5168
+ initiatorContext: TurnInitiatorContext,
5169
+ /** Secret-safe projection of the exact personal authority frozen on this turn. */
5170
+ personalConnections: z.array(McpPersonalConnectionSummary).default([]),
5171
+ cancelledBy: z.string().nullable(),
5172
+ cancelReason: z.string().nullable(),
5173
+ startedAt: z.string().nullable(),
5174
+ finishedAt: z.string().nullable(),
5175
+ createdAt: z.string(),
5176
+ updatedAt: z.string(),
5177
+ })
5178
+ .superRefine((turn, ctx) => {
5179
+ if (turn.prompt.length === 0 && turn.annotations.length === 0) {
5180
+ ctx.addIssue({
5181
+ code: z.ZodIssueCode.custom,
5182
+ path: ["prompt"],
5183
+ message: "turn prompt or annotations are required",
5184
+ });
5185
+ }
5186
+ });
4469
5187
  export type SessionTurn = z.infer<typeof SessionTurn>;
4470
5188
 
4471
5189
  export const EffectiveControlBlocker = z.object({
@@ -4534,6 +5252,7 @@ export type SessionCommandReceipt = z.infer<typeof SessionCommandReceipt>;
4534
5252
  export const ComposerDraft = z.object({
4535
5253
  revision: z.number().int().nonnegative(),
4536
5254
  text: z.string(),
5255
+ annotations: DraftTimelineAnnotations.default([]),
4537
5256
  resources: z.array(ResourceRef),
4538
5257
  model: z.string().min(1),
4539
5258
  reasoningEffort: ReasoningEffort,
@@ -4575,6 +5294,7 @@ export type DeleteSessionQueueItemRequest = z.infer<typeof DeleteSessionQueueIte
4575
5294
 
4576
5295
  export const SaveComposerDraftRequest = ComposerDraft.pick({
4577
5296
  text: true,
5297
+ annotations: true,
4578
5298
  resources: true,
4579
5299
  model: true,
4580
5300
  reasoningEffort: true,
@@ -4848,6 +5568,7 @@ export const SessionSystemUpdateKind = z.enum([
4848
5568
  "agent_message",
4849
5569
  "agent_steer_instruction",
4850
5570
  "child_terminal_result",
5571
+ "media_generation_result",
4851
5572
  ]);
4852
5573
  export type SessionSystemUpdateKind = z.infer<typeof SessionSystemUpdateKind>;
4853
5574
 
@@ -4892,6 +5613,7 @@ export const SessionSystemUpdatePayload = z.discriminatedUnion("type", [
4892
5613
  status: z.enum(["idle", "failed", "cancelled"]),
4893
5614
  })
4894
5615
  .passthrough(),
5616
+ MediaGenerationResult,
4895
5617
  ]);
4896
5618
  export type SessionSystemUpdatePayload = z.infer<typeof SessionSystemUpdatePayload>;
4897
5619
 
@@ -5035,9 +5757,9 @@ function withVariableSetIdAlias<T extends z.ZodRawShape>(shape: T) {
5035
5757
  }, z.object(shape));
5036
5758
  }
5037
5759
 
5038
- // Metadata only by design: no schema in this file ever carries a variable value
5039
- // back to a client. Values are write-only and decrypted exclusively inside the
5040
- // worker at sandbox materialization time.
5760
+ // Generic variable-set reads remain metadata-only. Exact plaintext has one
5761
+ // dedicated response schema so callers cannot accidentally widen another
5762
+ // workspace/session response with secret material.
5041
5763
  export const VariableSetVariableMetadata = z.object({
5042
5764
  name: VariableSetVariableName,
5043
5765
  version: z.number().int().positive(),
@@ -5050,6 +5772,14 @@ export const WorkspaceEnvironmentVariableMetadata = VariableSetVariableMetadata;
5050
5772
  /** @deprecated use VariableSetVariableMetadata */
5051
5773
  export type WorkspaceEnvironmentVariableMetadata = VariableSetVariableMetadata;
5052
5774
 
5775
+ export const VariableSetSecret = z.object({
5776
+ variableSetId: z.string().uuid(),
5777
+ name: VariableSetVariableName,
5778
+ version: z.number().int().positive(),
5779
+ value: z.string(),
5780
+ });
5781
+ export type VariableSetSecret = z.infer<typeof VariableSetSecret>;
5782
+
5053
5783
  export const VariableSet = z.object({
5054
5784
  id: z.string().uuid(),
5055
5785
  accountId: z.string().uuid(),
@@ -5115,6 +5845,126 @@ export const RigCheck = z.object({
5115
5845
  });
5116
5846
  export type RigCheck = z.infer<typeof RigCheck>;
5117
5847
 
5848
+ export const RigProviderImageBuildStatus = z.enum(["building", "ready", "failed", "unsupported"]);
5849
+ export type RigProviderImageBuildStatus = z.infer<typeof RigProviderImageBuildStatus>;
5850
+
5851
+ export const RigProviderImage = z
5852
+ .object({
5853
+ backend: SandboxBackend,
5854
+ provider: z.string().min(1).max(64),
5855
+ status: RigProviderImageBuildStatus,
5856
+ // Exact immutable rig-definition/setup identity used to reject stale image
5857
+ // reuse when a version or its effective base image changes.
5858
+ contentHash: z.string().regex(/^sha256:[0-9a-f]{64}$/u),
5859
+ setupHash: z.string().regex(/^sha256:[0-9a-f]{64}$/u),
5860
+ sourceImage: z.string().max(2048).nullable(),
5861
+ buildRequestId: z.string().uuid(),
5862
+ imageId: z.string().min(1).max(512).nullable(),
5863
+ imageDigest: z.string().min(1).max(512).nullable(),
5864
+ artifactId: z.string().uuid().nullable(),
5865
+ providerBindingKeyHash: z
5866
+ .string()
5867
+ .regex(/^sha256:[0-9a-f]{64}$/u)
5868
+ .nullable(),
5869
+ // Added after provider-image v1 shipped. Absence is retained for rolling
5870
+ // compatibility but means runtime must use logical-image + setup fallback
5871
+ // until an explicit verification cold-boots this exact image.
5872
+ coldBootValidation: z
5873
+ .object({
5874
+ version: z.literal(1),
5875
+ checkedAt: z.string().datetime(),
5876
+ })
5877
+ .optional(),
5878
+ provenance: z.object({
5879
+ kind: z.literal("rig_verification"),
5880
+ targetKind: z.enum(["change", "version"]),
5881
+ targetId: z.string().uuid(),
5882
+ }),
5883
+ startedAt: z.string().datetime(),
5884
+ finishedAt: z.string().datetime().nullable(),
5885
+ error: z
5886
+ .object({
5887
+ code: z.string().min(1).max(120),
5888
+ message: z.string().min(1).max(2000),
5889
+ retryable: z.boolean(),
5890
+ })
5891
+ .nullable(),
5892
+ })
5893
+ .superRefine((value, ctx) => {
5894
+ if (value.status === "ready" && !value.imageId && !value.imageDigest) {
5895
+ ctx.addIssue({
5896
+ code: "custom",
5897
+ path: ["imageId"],
5898
+ message: "ready provider images require an immutable image id or digest",
5899
+ });
5900
+ }
5901
+ if (
5902
+ value.status === "ready" &&
5903
+ value.backend === "modal" &&
5904
+ (value.artifactId === null || value.providerBindingKeyHash === null)
5905
+ ) {
5906
+ ctx.addIssue({
5907
+ code: "custom",
5908
+ path: [value.artifactId === null ? "artifactId" : "providerBindingKeyHash"],
5909
+ message: "ready Modal provider images require durable artifact ownership and binding",
5910
+ });
5911
+ }
5912
+ if (value.status !== "ready" && value.artifactId !== null) {
5913
+ ctx.addIssue({
5914
+ code: "custom",
5915
+ path: ["artifactId"],
5916
+ message: "only ready provider images may retain a durable artifact",
5917
+ });
5918
+ }
5919
+ if (value.status === "building") {
5920
+ if (value.finishedAt !== null) {
5921
+ ctx.addIssue({
5922
+ code: "custom",
5923
+ path: ["finishedAt"],
5924
+ message: "building provider images cannot be finished",
5925
+ });
5926
+ }
5927
+ if (value.error !== null) {
5928
+ ctx.addIssue({
5929
+ code: "custom",
5930
+ path: ["error"],
5931
+ message: "building provider images cannot have a terminal error",
5932
+ });
5933
+ }
5934
+ } else if (value.finishedAt === null) {
5935
+ ctx.addIssue({
5936
+ code: "custom",
5937
+ path: ["finishedAt"],
5938
+ message: "terminal provider images require a finish timestamp",
5939
+ });
5940
+ }
5941
+ if ((value.status === "failed" || value.status === "unsupported") && value.error === null) {
5942
+ ctx.addIssue({
5943
+ code: "custom",
5944
+ path: ["error"],
5945
+ message: `${value.status} provider images require failure truth`,
5946
+ });
5947
+ }
5948
+ if (value.status === "ready" && value.error !== null) {
5949
+ ctx.addIssue({
5950
+ code: "custom",
5951
+ path: ["error"],
5952
+ message: "ready provider images cannot retain an error",
5953
+ });
5954
+ }
5955
+ if (value.status !== "ready" && value.coldBootValidation !== undefined) {
5956
+ ctx.addIssue({
5957
+ code: "custom",
5958
+ path: ["coldBootValidation"],
5959
+ message: "only ready provider images may retain cold-boot validation",
5960
+ });
5961
+ }
5962
+ });
5963
+ export type RigProviderImage = z.infer<typeof RigProviderImage>;
5964
+
5965
+ export const RigProviderImages = z.partialRecord(SandboxBackend, RigProviderImage);
5966
+ export type RigProviderImages = z.infer<typeof RigProviderImages>;
5967
+
5118
5968
  export const RigVersion = z.object({
5119
5969
  id: z.string().uuid(),
5120
5970
  rigId: z.string().uuid(),
@@ -5125,6 +5975,9 @@ export const RigVersion = z.object({
5125
5975
  credentialHooks: z.array(z.string()),
5126
5976
  defaultVariableSetIds: z.array(z.string().uuid()),
5127
5977
  changelog: z.string().nullable(),
5978
+ // Operational build metadata is version-bound but not part of the immutable
5979
+ // rig definition. Each backend records its own truthful build state.
5980
+ providerImages: RigProviderImages.default({}),
5128
5981
  // Attribution: 'user:<subject>' | 'session:<id>' | 'system'.
5129
5982
  createdBy: z.string().nullable(),
5130
5983
  active: z.boolean(),
@@ -5245,22 +6098,112 @@ export const ProposeRigChangeRequest = z.discriminatedUnion("kind", [
5245
6098
  ]);
5246
6099
  export type ProposeRigChangeRequest = z.infer<typeof ProposeRigChangeRequest>;
5247
6100
 
5248
- export const ScheduledTaskStatus = z.enum(["active", "paused"]);
6101
+ export const ScheduledTaskStatus = /* @__PURE__ */ z.enum(["active", "paused"]);
5249
6102
  export type ScheduledTaskStatus = z.infer<typeof ScheduledTaskStatus>;
5250
6103
 
5251
- export const ScheduledTaskRunStatus = z.enum(["queued", "dispatched", "failed"]);
6104
+ export const ScheduledTaskRunStatus = /* @__PURE__ */ z.enum([
6105
+ "queued",
6106
+ "dispatched",
6107
+ "succeeded",
6108
+ "skipped",
6109
+ "failed",
6110
+ ]);
5252
6111
  export type ScheduledTaskRunStatus = z.infer<typeof ScheduledTaskRunStatus>;
5253
6112
 
5254
- export const ScheduledTaskRunMode = z.enum(["new_session_per_run", "reusable_session"]);
6113
+ export const ScheduledTaskRunMode = /* @__PURE__ */ z.enum([
6114
+ "new_session_per_run",
6115
+ "reusable_session",
6116
+ "existing_session",
6117
+ ]);
5255
6118
  export type ScheduledTaskRunMode = z.infer<typeof ScheduledTaskRunMode>;
5256
6119
 
5257
- export const ScheduledTaskOverlapPolicy = z.enum(["allow_concurrent", "skip", "buffer_one"]);
6120
+ export const ScheduledTaskOverlapPolicy = /* @__PURE__ */ z.enum([
6121
+ "allow_concurrent",
6122
+ "skip",
6123
+ "buffer_one",
6124
+ ]);
5258
6125
  export type ScheduledTaskOverlapPolicy = z.infer<typeof ScheduledTaskOverlapPolicy>;
5259
6126
 
5260
- export const ScheduledTaskTriggerType = z.enum(["scheduled", "manual"]);
6127
+ export const ScheduledTaskTriggerType = /* @__PURE__ */ z.enum([
6128
+ "scheduled",
6129
+ "manual",
6130
+ "initial",
6131
+ "provider_event",
6132
+ "retry",
6133
+ "repair",
6134
+ ]);
5261
6135
  export type ScheduledTaskTriggerType = z.infer<typeof ScheduledTaskTriggerType>;
5262
6136
 
5263
- export const ScheduledTaskScheduleSpec = z.discriminatedUnion("type", [
6137
+ export const ScheduledTaskActionKind = /* @__PURE__ */ z.enum([
6138
+ "agent_turn",
6139
+ "knowledge_source_sync",
6140
+ ]);
6141
+ export type ScheduledTaskActionKind = z.infer<typeof ScheduledTaskActionKind>;
6142
+
6143
+ const KnowledgeSourceSyncPositiveInteger = z.number().int().positive();
6144
+ const KnowledgeSourceSyncNonnegativeInteger = z.number().int().nonnegative();
6145
+ const KnowledgeSourceSyncZeroInteger = KnowledgeSourceSyncNonnegativeInteger.default(0);
6146
+ const KnowledgeSourceSyncUuid = z.string().uuid();
6147
+ const KnowledgeSourceSyncSubject = z.string().min(1).max(1024);
6148
+ const KnowledgeSourceSyncEnabled = z.boolean().default(true);
6149
+ const KnowledgeSourceSyncDisabled = z.boolean().default(false);
6150
+
6151
+ export const KnowledgeSourceSyncLimits = /* @__PURE__ */ z.object({
6152
+ maxItems: KnowledgeSourceSyncPositiveInteger.max(10_000).default(500),
6153
+ maxBytes: KnowledgeSourceSyncPositiveInteger.max(5_000_000_000).default(500_000_000),
6154
+ maxFileBytes: KnowledgeSourceSyncPositiveInteger.max(5_000_000_000).default(100_000_000),
6155
+ maxProviderRequests: KnowledgeSourceSyncPositiveInteger.max(10_000).default(1_000),
6156
+ maxElapsedSeconds: KnowledgeSourceSyncPositiveInteger.max(3_600).default(300),
6157
+ maxConcurrency: KnowledgeSourceSyncPositiveInteger.max(32).default(4),
6158
+ maxFailureDetails: KnowledgeSourceSyncPositiveInteger.max(100).default(25),
6159
+ });
6160
+ export type KnowledgeSourceSyncLimits = z.infer<typeof KnowledgeSourceSyncLimits>;
6161
+
6162
+ export const KnowledgeSourceSyncConnectionAuthority = /* @__PURE__ */ z.object({
6163
+ connectionId: KnowledgeSourceSyncUuid,
6164
+ connectionVersion: KnowledgeSourceSyncPositiveInteger,
6165
+ providerDomain: z.string().min(1).max(2048),
6166
+ kind: z.enum(["oauth2", "api_key", "app_install", "delegated"]),
6167
+ ownerSubjectId: KnowledgeSourceSyncSubject,
6168
+ });
6169
+ export type KnowledgeSourceSyncConnectionAuthority = z.infer<
6170
+ typeof KnowledgeSourceSyncConnectionAuthority
6171
+ >;
6172
+
6173
+ export const KnowledgeSourceSyncAction = /* @__PURE__ */ z
6174
+ .object({
6175
+ kind: z.literal("knowledge_source_sync"),
6176
+ sourceId: KnowledgeSourceSyncUuid,
6177
+ sourceGeneration: KnowledgeSourceSyncNonnegativeInteger,
6178
+ sourceLifecycleGeneration: KnowledgeSourceSyncPositiveInteger,
6179
+ sourceConfigGeneration: KnowledgeSourceSyncPositiveInteger,
6180
+ controlWorkspaceId: KnowledgeSourceSyncUuid,
6181
+ providerCoordinationKey: z.string().trim().min(1).max(1024),
6182
+ connection: KnowledgeSourceSyncConnectionAuthority,
6183
+ destination: ScopedKnowledgeScope,
6184
+ initiatingSubjectId: KnowledgeSourceSyncSubject,
6185
+ allDescendants: KnowledgeSourceSyncEnabled,
6186
+ limits: KnowledgeSourceSyncLimits.prefault({}),
6187
+ })
6188
+ .strict();
6189
+ export type KnowledgeSourceSyncAction = z.infer<typeof KnowledgeSourceSyncAction>;
6190
+
6191
+ export const KnowledgeSourceSyncScheduleControl = /* @__PURE__ */ z
6192
+ .object({
6193
+ sourceEnabled: KnowledgeSourceSyncEnabled,
6194
+ connectionPaused: KnowledgeSourceSyncDisabled,
6195
+ })
6196
+ .strict();
6197
+ export type KnowledgeSourceSyncScheduleControl = z.infer<typeof KnowledgeSourceSyncScheduleControl>;
6198
+
6199
+ export const ScheduledTaskAction = /* @__PURE__ */ z.discriminatedUnion("kind", [
6200
+ z.object({ kind: z.literal("agent_turn") }).strict(),
6201
+ KnowledgeSourceSyncAction,
6202
+ ]);
6203
+ export type ScheduledTaskAction = z.infer<typeof ScheduledTaskAction>;
6204
+
6205
+ export const ScheduledTaskScheduleSpec = /* @__PURE__ */ z.discriminatedUnion("type", [
6206
+ z.object({ type: z.literal("manual") }).strict(),
5264
6207
  z.object({
5265
6208
  type: z.literal("once"),
5266
6209
  runAt: z.string().datetime({ offset: true }),
@@ -5285,7 +6228,7 @@ export const ScheduledTaskScheduleSpec = z.discriminatedUnion("type", [
5285
6228
  ]);
5286
6229
  export type ScheduledTaskScheduleSpec = z.infer<typeof ScheduledTaskScheduleSpec>;
5287
6230
 
5288
- export const ScheduledTaskAgentConfig = z.object({
6231
+ export const ScheduledTaskAgentConfig = /* @__PURE__ */ z.object({
5289
6232
  prompt: z.string().min(1),
5290
6233
  resources: z.array(ResourceRef).default([]),
5291
6234
  tools: z.array(ToolRef).default([]),
@@ -5304,7 +6247,7 @@ export const ScheduledTaskAgentConfig = z.object({
5304
6247
  });
5305
6248
  export type ScheduledTaskAgentConfig = z.infer<typeof ScheduledTaskAgentConfig>;
5306
6249
 
5307
- export const ScheduledTask = z.object({
6250
+ export const ScheduledTask = /* @__PURE__ */ z.object({
5308
6251
  id: z.string().uuid(),
5309
6252
  accountId: z.string().uuid(),
5310
6253
  workspaceId: z.string().uuid(),
@@ -5314,11 +6257,16 @@ export const ScheduledTask = z.object({
5314
6257
  temporalScheduleId: z.string(),
5315
6258
  runMode: ScheduledTaskRunMode,
5316
6259
  overlapPolicy: ScheduledTaskOverlapPolicy,
6260
+ action: ScheduledTaskAction.default({ kind: "agent_turn" }),
5317
6261
  agentConfig: ScheduledTaskAgentConfig,
5318
- createdBy: TurnInitiator.default({ kind: "service", subjectId: "unattributed-legacy" }),
6262
+ createdBy: TurnInitiator.default({
6263
+ kind: "service",
6264
+ subjectId: "unattributed-legacy",
6265
+ }),
5319
6266
  createdByContext: TurnInitiatorContext.default({}),
5320
6267
  personalConnections: z.array(McpPersonalConnectionSummary).default([]),
5321
6268
  reusableSessionId: z.string().uuid().nullable(),
6269
+ targetSessionId: z.string().uuid().nullable().default(null),
5322
6270
  variableSetId: z.string().uuid().nullable().default(null),
5323
6271
  /** @deprecated use variableSetId */
5324
6272
  environmentId: z.string().uuid().nullable().default(null),
@@ -5332,7 +6280,52 @@ export const ScheduledTask = z.object({
5332
6280
  });
5333
6281
  export type ScheduledTask = z.infer<typeof ScheduledTask>;
5334
6282
 
5335
- export const ScheduledTaskRun = z.object({
6283
+ export const KnowledgeSourceSyncFailure = /* @__PURE__ */ z.object({
6284
+ externalObjectId: KnowledgeSourceSyncSubject,
6285
+ code: z.enum([
6286
+ "authority_changed",
6287
+ "connection_reconnect_required",
6288
+ "provider_unavailable",
6289
+ "provider_rejected",
6290
+ "provider_payload_invalid",
6291
+ "content_unsupported",
6292
+ "content_too_large",
6293
+ "resource_limit",
6294
+ "item_processing_failed",
6295
+ "indexing_failed",
6296
+ "internal_failure",
6297
+ ]),
6298
+ retryable: z.boolean(),
6299
+ message: z.string().min(1).max(1000),
6300
+ });
6301
+ export type KnowledgeSourceSyncFailure = z.infer<typeof KnowledgeSourceSyncFailure>;
6302
+
6303
+ export const KnowledgeSourceSyncRunSummary = /* @__PURE__ */ z.object({
6304
+ phase: z
6305
+ .enum(["queued", "inventory", "transfer", "index", "checkpoint", "completed", "failed"])
6306
+ .default("queued"),
6307
+ scanned: KnowledgeSourceSyncZeroInteger,
6308
+ imported: KnowledgeSourceSyncZeroInteger,
6309
+ unchanged: KnowledgeSourceSyncZeroInteger,
6310
+ skipped: KnowledgeSourceSyncZeroInteger,
6311
+ failed: KnowledgeSourceSyncZeroInteger,
6312
+ bytes: KnowledgeSourceSyncZeroInteger,
6313
+ providerRequests: KnowledgeSourceSyncZeroInteger,
6314
+ elapsedMs: KnowledgeSourceSyncZeroInteger,
6315
+ indexed: KnowledgeSourceSyncZeroInteger,
6316
+ aclPending: KnowledgeSourceSyncZeroInteger,
6317
+ retryable: KnowledgeSourceSyncDisabled,
6318
+ limitReached: z
6319
+ .enum(["items", "bytes", "file_bytes", "provider_requests", "elapsed_time"])
6320
+ .nullable()
6321
+ .default(null),
6322
+ checkpointed: KnowledgeSourceSyncDisabled,
6323
+ reconnectRequired: KnowledgeSourceSyncDisabled,
6324
+ failures: z.array(KnowledgeSourceSyncFailure).max(100).default([]),
6325
+ });
6326
+ export type KnowledgeSourceSyncRunSummary = z.infer<typeof KnowledgeSourceSyncRunSummary>;
6327
+
6328
+ export const ScheduledTaskRun = /* @__PURE__ */ z.object({
5336
6329
  id: z.string().uuid(),
5337
6330
  accountId: z.string().uuid(),
5338
6331
  workspaceId: z.string().uuid(),
@@ -5343,17 +6336,26 @@ export const ScheduledTaskRun = z.object({
5343
6336
  firedAt: z.string(),
5344
6337
  sessionId: z.string().uuid().nullable(),
5345
6338
  triggerEventId: z.string().uuid().nullable(),
6339
+ actionKind: ScheduledTaskActionKind.default("agent_turn"),
6340
+ knowledgeSyncRunId: KnowledgeSourceSyncUuid.nullable().default(null),
6341
+ knowledgeSummary: KnowledgeSourceSyncRunSummary.nullable().default(null),
6342
+ completedAt: z.string().nullable().default(null),
5346
6343
  error: z.string().nullable(),
5347
6344
  createdAt: z.string(),
5348
6345
  updatedAt: z.string(),
5349
6346
  });
5350
6347
  export type ScheduledTaskRun = z.infer<typeof ScheduledTaskRun>;
5351
6348
 
5352
- export const CreateScheduledTaskRequest = withVariableSetIdAlias({
6349
+ const CreateAgentScheduledTaskRequest = /* @__PURE__ */ withVariableSetIdAlias({
5353
6350
  name: z.string().min(1),
5354
6351
  schedule: ScheduledTaskScheduleSpec,
6352
+ action: z
6353
+ .object({ kind: z.literal("agent_turn") })
6354
+ .strict()
6355
+ .default({ kind: "agent_turn" }),
5355
6356
  runMode: ScheduledTaskRunMode.default("new_session_per_run"),
5356
6357
  overlapPolicy: ScheduledTaskOverlapPolicy.default("allow_concurrent"),
6358
+ targetSessionId: z.string().uuid().nullable().optional(),
5357
6359
  agentConfig: ScheduledTaskAgentConfig,
5358
6360
  status: ScheduledTaskStatus.default("active"),
5359
6361
  variableSetId: z.string().uuid().nullable().optional(),
@@ -5361,14 +6363,68 @@ export const CreateScheduledTaskRequest = withVariableSetIdAlias({
5361
6363
  // The rig each run binds to (M3); its active version is resolved per fire.
5362
6364
  rigId: z.string().uuid().nullable().optional(),
5363
6365
  metadata: z.record(z.string(), z.unknown()).default({}),
6366
+ }).superRefine((value, context) => {
6367
+ if (value.runMode === "existing_session" && !value.targetSessionId) {
6368
+ context.addIssue({
6369
+ code: "custom",
6370
+ path: ["targetSessionId"],
6371
+ message: "targetSessionId is required when runMode=existing_session",
6372
+ });
6373
+ }
6374
+ if (value.runMode !== "existing_session" && value.targetSessionId) {
6375
+ context.addIssue({
6376
+ code: "custom",
6377
+ path: ["targetSessionId"],
6378
+ message: "targetSessionId requires runMode=existing_session",
6379
+ });
6380
+ }
6381
+ if (value.runMode === "existing_session" && value.agentConfig.goal) {
6382
+ context.addIssue({
6383
+ code: "custom",
6384
+ path: ["agentConfig", "goal"],
6385
+ message: "agentConfig.goal cannot be used with an existing-session target",
6386
+ });
6387
+ }
5364
6388
  });
6389
+
6390
+ const CreateKnowledgeSourceSyncScheduledTaskRequest = /* @__PURE__ */ z
6391
+ .object({
6392
+ name: z.string().min(1),
6393
+ schedule: ScheduledTaskScheduleSpec,
6394
+ action: KnowledgeSourceSyncAction,
6395
+ overlapPolicy: z.enum(["skip", "buffer_one"]).default("buffer_one"),
6396
+ status: ScheduledTaskStatus.default("active"),
6397
+ metadata: z.record(z.string(), z.unknown()).default({}),
6398
+ })
6399
+ .strict()
6400
+ .transform((value) => ({
6401
+ ...value,
6402
+ runMode: "new_session_per_run" as const,
6403
+ targetSessionId: null,
6404
+ agentConfig: {
6405
+ prompt: "Knowledge source synchronization",
6406
+ resources: [],
6407
+ tools: [],
6408
+ metadata: {},
6409
+ },
6410
+ variableSetId: null,
6411
+ environmentId: null,
6412
+ rigId: null,
6413
+ }));
6414
+
6415
+ export const CreateScheduledTaskRequest = /* @__PURE__ */ z.union([
6416
+ CreateKnowledgeSourceSyncScheduledTaskRequest,
6417
+ CreateAgentScheduledTaskRequest,
6418
+ ]);
5365
6419
  export type CreateScheduledTaskRequest = z.infer<typeof CreateScheduledTaskRequest>;
5366
6420
 
5367
- export const UpdateScheduledTaskRequest = withVariableSetIdAlias({
6421
+ export const UpdateScheduledTaskRequest = /* @__PURE__ */ withVariableSetIdAlias({
5368
6422
  name: z.string().min(1).optional(),
5369
6423
  schedule: ScheduledTaskScheduleSpec.optional(),
5370
6424
  runMode: ScheduledTaskRunMode.optional(),
5371
6425
  overlapPolicy: ScheduledTaskOverlapPolicy.optional(),
6426
+ action: ScheduledTaskAction.optional(),
6427
+ targetSessionId: z.string().uuid().nullable().optional(),
5372
6428
  agentConfig: ScheduledTaskAgentConfig.optional(),
5373
6429
  status: ScheduledTaskStatus.optional(),
5374
6430
  variableSetId: z.string().uuid().nullable().optional(),
@@ -5377,6 +6433,31 @@ export const UpdateScheduledTaskRequest = withVariableSetIdAlias({
5377
6433
  // resolved per fire, so an update takes effect on the next dispatch.
5378
6434
  rigId: z.string().uuid().nullable().optional(),
5379
6435
  metadata: z.record(z.string(), z.unknown()).optional(),
6436
+ }).superRefine((value, context) => {
6437
+ if (value.targetSessionId && value.runMode && value.runMode !== "existing_session") {
6438
+ context.addIssue({
6439
+ code: "custom",
6440
+ path: ["targetSessionId"],
6441
+ message: "targetSessionId requires runMode=existing_session",
6442
+ });
6443
+ }
6444
+ if (value.runMode === "existing_session" && value.targetSessionId === null) {
6445
+ context.addIssue({
6446
+ code: "custom",
6447
+ path: ["targetSessionId"],
6448
+ message: "targetSessionId cannot be null when runMode=existing_session",
6449
+ });
6450
+ }
6451
+ if (
6452
+ value.agentConfig?.goal &&
6453
+ (value.runMode === "existing_session" || Boolean(value.targetSessionId))
6454
+ ) {
6455
+ context.addIssue({
6456
+ code: "custom",
6457
+ path: ["agentConfig", "goal"],
6458
+ message: "agentConfig.goal cannot be used with an existing-session target",
6459
+ });
6460
+ }
5380
6461
  });
5381
6462
  export type UpdateScheduledTaskRequest = z.infer<typeof UpdateScheduledTaskRequest>;
5382
6463
 
@@ -5528,11 +6609,86 @@ function isSafePackSkillRelativePath(path: string): boolean {
5528
6609
  .every((segment) => segment.length > 0 && segment !== "." && segment !== "..");
5529
6610
  }
5530
6611
 
5531
- const CapabilityPackVariableSet = z.object({
5532
- description: z.string().min(1),
5533
- requiredVariables: z.array(VariableSetVariableName).default([]),
5534
- required: z.boolean().default(false),
5535
- });
6612
+ const CapabilityPackVariableSet = z
6613
+ .object({
6614
+ description: z.string().min(1).max(2048),
6615
+ requiredVariables: z.array(VariableSetVariableName).max(256).default([]),
6616
+ required: z.boolean().default(false),
6617
+ })
6618
+ .strict();
6619
+
6620
+ const CapabilityPackComponentKey = z
6621
+ .string()
6622
+ .min(1)
6623
+ .max(128)
6624
+ .regex(/^[a-z0-9](?:[a-z0-9._/-]*[a-z0-9])?$/);
6625
+
6626
+ const CapabilityPackInstanceKey = z
6627
+ .string()
6628
+ .min(1)
6629
+ .max(128)
6630
+ .regex(/^[a-z0-9](?:[a-z0-9._/-]*[a-z0-9])?$/);
6631
+
6632
+ /**
6633
+ * Immutable requirements adopted by a Pack installation. The manifest names
6634
+ * portable identities; installation resolves them to exact workspace-local
6635
+ * component rows and records Pack ownership in the shared component ledger.
6636
+ */
6637
+ export const CapabilityPackComponentReference = z.discriminatedUnion("kind", [
6638
+ z
6639
+ .object({
6640
+ key: CapabilityPackComponentKey,
6641
+ kind: z.literal("plugin"),
6642
+ pluginKey: z.string().min(1).max(200),
6643
+ version: z.string().min(1).max(128),
6644
+ manifestDigest: z.string().regex(/^[0-9a-f]{64}$/),
6645
+ required: z.boolean().default(true),
6646
+ })
6647
+ .strict(),
6648
+ z
6649
+ .object({
6650
+ key: CapabilityPackComponentKey,
6651
+ kind: z.literal("skill"),
6652
+ capabilityId: z.string().min(1).max(512),
6653
+ contentSha256: z.string().regex(/^[0-9a-f]{64}$/),
6654
+ required: z.boolean().default(true),
6655
+ })
6656
+ .strict(),
6657
+ z
6658
+ .object({
6659
+ key: CapabilityPackComponentKey,
6660
+ kind: z.literal("integration"),
6661
+ capabilityId: z.string().min(1).max(512),
6662
+ instanceKey: CapabilityPackInstanceKey,
6663
+ revisionId: z.string().min(1).max(512),
6664
+ contentSha256: z.string().regex(/^[0-9a-f]{64}$/),
6665
+ required: z.boolean().default(true),
6666
+ })
6667
+ .strict(),
6668
+ z
6669
+ .object({
6670
+ key: CapabilityPackComponentKey,
6671
+ kind: z.literal("feature"),
6672
+ capabilityId: z.string().min(1).max(512),
6673
+ instanceKey: CapabilityPackInstanceKey,
6674
+ featureKey: z.string().min(1).max(200),
6675
+ bindingKey: CapabilityPackInstanceKey,
6676
+ configDigest: z.string().regex(/^[0-9a-f]{64}$/),
6677
+ required: z.boolean().default(true),
6678
+ })
6679
+ .strict(),
6680
+ ]);
6681
+ export type CapabilityPackComponentReference = z.infer<typeof CapabilityPackComponentReference>;
6682
+
6683
+ export const CapabilityPackRigRequirement = z
6684
+ .object({
6685
+ description: z.string().min(1).max(2048).optional(),
6686
+ required: z.boolean().default(true),
6687
+ rigId: z.string().uuid().optional(),
6688
+ requireVerified: z.boolean().default(false),
6689
+ })
6690
+ .strict();
6691
+ export type CapabilityPackRigRequirement = z.infer<typeof CapabilityPackRigRequirement>;
5536
6692
 
5537
6693
  export const CapabilityPack = z.preprocess(
5538
6694
  (input) => {
@@ -5562,15 +6718,19 @@ export const CapabilityPack = z.preprocess(
5562
6718
  },
5563
6719
  z
5564
6720
  .object({
5565
- id: z.string().min(1),
5566
- name: z.string().min(1),
5567
- description: z.string().min(1),
5568
- role: z.string().min(1),
5569
- category: z.string().min(1),
5570
- version: z.string().min(1),
5571
- // Container image ref (digest-pinned recommended) the pack's sessions run
5572
- // in. At most one enabled pack per workspace may declare one; with none,
5573
- // sessions use the deployment-wide image settings.
6721
+ id: z
6722
+ .string()
6723
+ .min(1)
6724
+ .max(100)
6725
+ .regex(/^[a-z0-9](?:[a-z0-9._/-]*[a-z0-9])?$/),
6726
+ name: z.string().min(1).max(200),
6727
+ description: z.string().min(1).max(4096),
6728
+ role: z.string().min(1).max(128),
6729
+ category: z.string().min(1).max(128),
6730
+ version: z.string().min(1).max(128),
6731
+ // Legacy manifest compatibility. V2 installation resolves this image to
6732
+ // an explicit Rig requirement; the Pack no longer changes workspace
6733
+ // runtime settings directly.
5574
6734
  sandboxImage: z.string().trim().min(1).max(512).optional(),
5575
6735
  // Optional provider-native immutable identities for the exact logical
5576
6736
  // sandboxImage above. These avoid re-importing a private registry image on
@@ -5590,7 +6750,8 @@ export const CapabilityPack = z.preprocess(
5590
6750
  })
5591
6751
  .strict()
5592
6752
  .optional(),
5593
- // Skills delivered into the sandbox skill index when the pack is enabled.
6753
+ // Legacy inline Skills are migrated into immutable Skill components by
6754
+ // the V2 Pack installer. They are not loaded directly by V2 runtime.
5594
6755
  skills: z
5595
6756
  .array(CapabilityPackSkill)
5596
6757
  .max(32)
@@ -5609,6 +6770,8 @@ export const CapabilityPack = z.preprocess(
5609
6770
  });
5610
6771
  })
5611
6772
  .default([]),
6773
+ components: z.array(CapabilityPackComponentReference).max(128).default([]),
6774
+ rig: CapabilityPackRigRequirement.optional(),
5612
6775
  tools: z.array(ToolRef).default([]),
5613
6776
  connectors: z.array(CapabilityPackConnector).default([]),
5614
6777
  knowledge: z.array(CapabilityPackKnowledge).default([]),
@@ -5617,6 +6780,28 @@ export const CapabilityPack = z.preprocess(
5617
6780
  metadata: z.record(z.string(), z.unknown()).default({}),
5618
6781
  })
5619
6782
  .superRefine((pack, ctx) => {
6783
+ const componentKeys = new Set<string>();
6784
+ pack.components.forEach((component, index) => {
6785
+ if (componentKeys.has(component.key)) {
6786
+ ctx.addIssue({
6787
+ code: "custom",
6788
+ message: `duplicate Pack component key: ${component.key}`,
6789
+ path: ["components", index, "key"],
6790
+ });
6791
+ }
6792
+ componentKeys.add(component.key);
6793
+ });
6794
+ pack.skills.forEach((skill, index) => {
6795
+ const key = `inline-skill/${skill.name.toLowerCase()}`;
6796
+ if (componentKeys.has(key)) {
6797
+ ctx.addIssue({
6798
+ code: "custom",
6799
+ message: `Pack component key conflicts with inline Skill ${skill.name}: ${key}`,
6800
+ path: ["skills", index, "name"],
6801
+ });
6802
+ }
6803
+ componentKeys.add(key);
6804
+ });
5620
6805
  if (!pack.sandboxProviderImages?.modal) {
5621
6806
  return;
5622
6807
  }
@@ -5654,7 +6839,12 @@ export const WorkspaceRegisteredPack = z.object({
5654
6839
  });
5655
6840
  export type WorkspaceRegisteredPack = z.infer<typeof WorkspaceRegisteredPack>;
5656
6841
 
5657
- export const PackInstallationStatus = z.enum(["active", "disabled"]);
6842
+ export const PackInstallationStatus = z.enum([
6843
+ "installing",
6844
+ "active",
6845
+ "needs_attention",
6846
+ "disabled",
6847
+ ]);
5658
6848
  export type PackInstallationStatus = z.infer<typeof PackInstallationStatus>;
5659
6849
 
5660
6850
  export const PackInstallation = z.object({
@@ -5663,6 +6853,14 @@ export const PackInstallation = z.object({
5663
6853
  workspaceId: z.string().uuid(),
5664
6854
  packId: z.string().min(1),
5665
6855
  status: PackInstallationStatus,
6856
+ version: z.number().int().positive(),
6857
+ manifestSnapshot: CapabilityPack.nullable(),
6858
+ manifestDigest: z
6859
+ .string()
6860
+ .regex(/^[0-9a-f]{64}$/)
6861
+ .nullable(),
6862
+ selectedRigId: z.string().uuid().nullable(),
6863
+ installedBySubjectId: z.string().min(1).max(1024).nullable(),
5666
6864
  metadata: z.record(z.string(), z.unknown()),
5667
6865
  enabledAt: z.string(),
5668
6866
  updatedAt: z.string(),
@@ -5676,6 +6874,116 @@ export const EnablePackRequest = withVariableSetIdAlias({
5676
6874
  });
5677
6875
  export type EnablePackRequest = z.infer<typeof EnablePackRequest>;
5678
6876
 
6877
+ export const PackComponentResolutionStatus = z.enum(["ready", "missing", "mismatch"]);
6878
+ export type PackComponentResolutionStatus = z.infer<typeof PackComponentResolutionStatus>;
6879
+
6880
+ export const PackComponentResolution = z
6881
+ .object({
6882
+ key: CapabilityPackComponentKey,
6883
+ kind: z.enum(["plugin", "skill", "integration", "feature", "inline_skill"]),
6884
+ capabilityId: z.string().min(1).max(512),
6885
+ required: z.boolean(),
6886
+ status: PackComponentResolutionStatus,
6887
+ expectedDigest: z.string().regex(/^[0-9a-f]{64}$/),
6888
+ actualDigest: z
6889
+ .string()
6890
+ .regex(/^[0-9a-f]{64}$/)
6891
+ .nullable(),
6892
+ resolvedId: z.string().min(1).max(512).nullable(),
6893
+ label: z.string().min(1).max(200),
6894
+ })
6895
+ .strict();
6896
+ export type PackComponentResolution = z.infer<typeof PackComponentResolution>;
6897
+
6898
+ export const PackRigResolution = z
6899
+ .object({
6900
+ required: z.boolean(),
6901
+ status: z.enum(["not_required", "ready", "missing", "mismatch", "unverified"]),
6902
+ requestedRigId: z.string().uuid().nullable(),
6903
+ rigId: z.string().uuid().nullable(),
6904
+ rigVersionId: z.string().uuid().nullable(),
6905
+ name: z.string().min(1).max(200).nullable(),
6906
+ image: z.string().min(1).max(512).nullable(),
6907
+ })
6908
+ .strict();
6909
+ export type PackRigResolution = z.infer<typeof PackRigResolution>;
6910
+
6911
+ export const PreviewPackInstallationRequest = z
6912
+ .object({
6913
+ rigId: z.string().uuid().optional(),
6914
+ variableSetId: z.string().uuid().optional(),
6915
+ })
6916
+ .strict();
6917
+ export type PreviewPackInstallationRequest = z.infer<typeof PreviewPackInstallationRequest>;
6918
+
6919
+ export const PackInstallationPreview = z
6920
+ .object({
6921
+ packId: z.string().min(1),
6922
+ packVersion: z.string().min(1),
6923
+ manifestDigest: z.string().regex(/^[0-9a-f]{64}$/),
6924
+ installationVersion: z.number().int().positive().nullable(),
6925
+ action: z.enum(["install", "update", "repair"]),
6926
+ ready: z.boolean(),
6927
+ blockers: z.array(z.string().min(1).max(500)).max(256),
6928
+ components: z.array(PackComponentResolution).max(160),
6929
+ rig: PackRigResolution,
6930
+ variableSetId: z.string().uuid().nullable(),
6931
+ legacyInlineSkillCount: z.number().int().nonnegative().max(32),
6932
+ legacySandboxImage: z.string().min(1).max(512).nullable(),
6933
+ })
6934
+ .strict();
6935
+ export type PackInstallationPreview = z.infer<typeof PackInstallationPreview>;
6936
+
6937
+ export const InstallPackRequest = z
6938
+ .object({
6939
+ expectedManifestDigest: z.string().regex(/^[0-9a-f]{64}$/),
6940
+ expectedInstallationVersion: z.number().int().positive().optional(),
6941
+ rigId: z.string().uuid().optional(),
6942
+ variableSetId: z.string().uuid().optional(),
6943
+ idempotencyKey: z.string().uuid(),
6944
+ metadata: z.record(z.string(), z.unknown()).default({}),
6945
+ })
6946
+ .strict();
6947
+ export type InstallPackRequest = z.infer<typeof InstallPackRequest>;
6948
+
6949
+ export const PackUninstallPreview = z
6950
+ .object({
6951
+ packId: z.string().min(1),
6952
+ installed: z.boolean(),
6953
+ installationVersion: z.number().int().positive().nullable(),
6954
+ components: z
6955
+ .array(
6956
+ z
6957
+ .object({
6958
+ key: CapabilityPackComponentKey,
6959
+ kind: z.enum(["plugin", "skill", "integration", "feature", "inline_skill"]),
6960
+ capabilityId: z.string().min(1).max(512),
6961
+ retainedByOtherOwners: z.boolean(),
6962
+ })
6963
+ .strict(),
6964
+ )
6965
+ .max(160),
6966
+ })
6967
+ .strict();
6968
+ export type PackUninstallPreview = z.infer<typeof PackUninstallPreview>;
6969
+
6970
+ export const UninstallPackRequest = z
6971
+ .object({
6972
+ expectedInstallationVersion: z.number().int().positive(),
6973
+ idempotencyKey: z.string().uuid(),
6974
+ })
6975
+ .strict();
6976
+ export type UninstallPackRequest = z.infer<typeof UninstallPackRequest>;
6977
+
6978
+ export const UninstallPackResult = z
6979
+ .object({
6980
+ packId: z.string().min(1),
6981
+ status: z.enum(["not_installed", "uninstalled"]),
6982
+ retainedComponents: z.array(z.string().min(1).max(512)).max(160),
6983
+ })
6984
+ .strict();
6985
+ export type UninstallPackResult = z.infer<typeof UninstallPackResult>;
6986
+
5679
6987
  export const SocialProvider = z.enum([
5680
6988
  "x",
5681
6989
  "reddit",
@@ -5909,6 +7217,38 @@ export const OpenGeniSlackBotInstallStart = z.object({
5909
7217
  });
5910
7218
  export type OpenGeniSlackBotInstallStart = z.infer<typeof OpenGeniSlackBotInstallStart>;
5911
7219
 
7220
+ export const SlackInstallationBindingState = z.enum(["active", "quarantined"]);
7221
+ export type SlackInstallationBindingState = z.infer<typeof SlackInstallationBindingState>;
7222
+
7223
+ export const SlackInstallationBinding = z.object({
7224
+ id: z.string().uuid(),
7225
+ accountId: z.string().uuid(),
7226
+ accountName: z.string().min(1),
7227
+ workspaceId: z.string().uuid(),
7228
+ workspaceName: z.string().min(1),
7229
+ connectionId: z.string().uuid(),
7230
+ connectionStatus: ConnectionStatus,
7231
+ connectionVersion: z.number().int().positive(),
7232
+ slackTeamId: z.string().min(1).max(64),
7233
+ slackTeamName: z.string().min(1).max(256),
7234
+ botId: z.string().min(1).max(64),
7235
+ botUserId: z.string().min(1).max(64),
7236
+ botDisplayName: z.literal("OpenGeni"),
7237
+ state: SlackInstallationBindingState,
7238
+ quarantineReason: z.string().min(1).nullable(),
7239
+ version: z.number().int().positive(),
7240
+ createdAt: z.string(),
7241
+ updatedAt: z.string(),
7242
+ });
7243
+ export type SlackInstallationBinding = z.infer<typeof SlackInstallationBinding>;
7244
+
7245
+ export const ListSlackInstallationBindingsResponse = z.object({
7246
+ bindings: z.array(SlackInstallationBinding),
7247
+ });
7248
+ export type ListSlackInstallationBindingsResponse = z.infer<
7249
+ typeof ListSlackInstallationBindingsResponse
7250
+ >;
7251
+
5912
7252
  export const UpdateConnectionRequest = z.object({
5913
7253
  providerDomain: z.string().min(1).optional(),
5914
7254
  subjectId: z.string().min(1).nullable().optional(),
@@ -6009,6 +7349,45 @@ export type CapabilityCatalogAuthKind = z.infer<typeof CapabilityCatalogAuthKind
6009
7349
  export const CapabilityCatalogTier = z.enum(["verified", "community"]);
6010
7350
  export type CapabilityCatalogTier = z.infer<typeof CapabilityCatalogTier>;
6011
7351
 
7352
+ /**
7353
+ * User-facing lifecycle truth for the Capabilities control center. This is a
7354
+ * read-model projection only: each action is still executed by the owning
7355
+ * Plugin, Integration, Connection, Skill, or Pack domain.
7356
+ */
7357
+ export const CapabilityLifecycleStatus = z.enum([
7358
+ "available",
7359
+ "installed",
7360
+ "connected",
7361
+ "ready",
7362
+ "needs_attention",
7363
+ "unavailable",
7364
+ "managed",
7365
+ ]);
7366
+ export type CapabilityLifecycleStatus = z.infer<typeof CapabilityLifecycleStatus>;
7367
+
7368
+ export const CapabilityReadiness = z.enum(["ready", "setup_required", "attention", "unavailable"]);
7369
+ export type CapabilityReadiness = z.infer<typeof CapabilityReadiness>;
7370
+
7371
+ export const CapabilityAction = z.enum([
7372
+ "install",
7373
+ "connect",
7374
+ "configure",
7375
+ "update",
7376
+ "repair",
7377
+ "disconnect",
7378
+ "uninstall",
7379
+ "inspect",
7380
+ ]);
7381
+ export type CapabilityAction = z.infer<typeof CapabilityAction>;
7382
+
7383
+ export const CapabilityLifecycle = z.object({
7384
+ status: CapabilityLifecycleStatus,
7385
+ readiness: CapabilityReadiness,
7386
+ detail: z.string().nullable().default(null),
7387
+ managedBy: z.enum(["deployment", "platform", "workspace"]).nullable().default(null),
7388
+ });
7389
+ export type CapabilityLifecycle = z.infer<typeof CapabilityLifecycle>;
7390
+
6012
7391
  export const CapabilityRuntime = z.object({
6013
7392
  available: z.boolean().default(false),
6014
7393
  mcpServerId: z.string().min(1).optional(),
@@ -6030,146 +7409,845 @@ export const CapabilityRuntime = z.object({
6030
7409
  });
6031
7410
  export type CapabilityRuntime = z.infer<typeof CapabilityRuntime>;
6032
7411
 
6033
- export const CapabilityCatalogItem = z.object({
6034
- id: z.string().min(1),
6035
- accountId: z.string().uuid().optional(),
6036
- workspaceId: z.string().uuid().optional(),
6037
- kind: CapabilityKind,
6038
- source: CapabilitySource,
6039
- name: z.string().min(1),
6040
- description: z.string().nullable().default(null),
6041
- category: z.string().min(1).default("custom"),
6042
- tags: z.array(z.string().min(1)).default([]),
6043
- homepageUrl: z.string().url().nullable().default(null),
6044
- endpointUrl: z.string().url().nullable().default(null),
6045
- installUrl: z.string().url().nullable().default(null),
6046
- authModel: z.string().min(1).nullable().default(null),
6047
- providerDomain: z.string().min(1).nullable().default(null),
6048
- surfaceType: z.string().min(1).nullable().default(null),
6049
- transport: z.string().min(1).nullable().default(null),
6050
- mcpUrl: z.string().url().nullable().default(null),
6051
- authKind: CapabilityCatalogAuthKind.nullable().default(null),
6052
- credentialFacts: z.array(z.record(z.string(), z.unknown())).default([]),
6053
- tier: CapabilityCatalogTier.nullable().default(null),
6054
- provenance: z.string().min(1).nullable().default(null),
6055
- logoAssetPath: z.string().min(1).nullable().default(null),
6056
- importBatchId: z.string().uuid().nullable().default(null),
6057
- stale: z.boolean().default(false),
6058
- staleAt: z.string().nullable().default(null),
6059
- tools: z.array(ToolRef).default([]),
6060
- runtime: CapabilityRuntime.default({ available: false, notes: null }),
6061
- enabled: z.boolean().default(false),
6062
- enabledReason: z.string().nullable().default(null),
6063
- // The non-secret connection binding stored with an enabled installation.
6064
- // Workspace refs retain an exact row id. Subject refs deliberately omit it:
6065
- // each caller resolves their own visible row by provider/kind at runtime.
6066
- connectionRef: z
6067
- .object({
6068
- connectionId: z.string().min(1).optional(),
6069
- providerDomain: z.string().min(1),
6070
- kind: z.string().min(1),
6071
- subjectScope: z.enum(["workspace", "subject"]).optional(),
6072
- })
6073
- .nullable()
6074
- .default(null),
6075
- metadata: z.record(z.string(), z.unknown()).default({}),
6076
- createdAt: z.string().optional(),
6077
- updatedAt: z.string().optional(),
6078
- });
6079
- export type CapabilityCatalogItem = z.infer<typeof CapabilityCatalogItem>;
7412
+ export const CapabilityCatalogItem = z.object({
7413
+ id: z.string().min(1),
7414
+ accountId: z.string().uuid().optional(),
7415
+ workspaceId: z.string().uuid().optional(),
7416
+ kind: CapabilityKind,
7417
+ source: CapabilitySource,
7418
+ name: z.string().min(1),
7419
+ description: z.string().nullable().default(null),
7420
+ category: z.string().min(1).default("custom"),
7421
+ tags: z.array(z.string().min(1)).default([]),
7422
+ homepageUrl: z.string().url().nullable().default(null),
7423
+ endpointUrl: z.string().url().nullable().default(null),
7424
+ installUrl: z.string().url().nullable().default(null),
7425
+ authModel: z.string().min(1).nullable().default(null),
7426
+ providerDomain: z.string().min(1).nullable().default(null),
7427
+ surfaceType: z.string().min(1).nullable().default(null),
7428
+ transport: z.string().min(1).nullable().default(null),
7429
+ mcpUrl: z.string().url().nullable().default(null),
7430
+ authKind: CapabilityCatalogAuthKind.nullable().default(null),
7431
+ credentialFacts: z.array(z.record(z.string(), z.unknown())).default([]),
7432
+ tier: CapabilityCatalogTier.nullable().default(null),
7433
+ provenance: z.string().min(1).nullable().default(null),
7434
+ logoAssetPath: z.string().min(1).nullable().default(null),
7435
+ importBatchId: z.string().uuid().nullable().default(null),
7436
+ stale: z.boolean().default(false),
7437
+ staleAt: z.string().nullable().default(null),
7438
+ tools: z.array(ToolRef).default([]),
7439
+ runtime: CapabilityRuntime.default({ available: false, notes: null }),
7440
+ lifecycle: CapabilityLifecycle.default({
7441
+ status: "available",
7442
+ readiness: "setup_required",
7443
+ detail: null,
7444
+ managedBy: null,
7445
+ }),
7446
+ actions: z.array(CapabilityAction).default([]),
7447
+ /**
7448
+ * @deprecated Compatibility projection for existing clients. New surfaces
7449
+ * must use lifecycle and actions rather than treating every type as an
7450
+ * enable/disable toggle.
7451
+ */
7452
+ enabled: z.boolean().default(false),
7453
+ /** @deprecated Compatibility explanation paired with enabled. */
7454
+ enabledReason: z.string().nullable().default(null),
7455
+ // The non-secret connection binding stored with an enabled installation.
7456
+ // Workspace refs retain an exact row id. Subject refs deliberately omit it:
7457
+ // each caller resolves their own visible row by provider/kind at runtime.
7458
+ connectionRef: z
7459
+ .object({
7460
+ connectionId: z.string().min(1).optional(),
7461
+ providerDomain: z.string().min(1),
7462
+ kind: z.string().min(1),
7463
+ subjectScope: z.enum(["workspace", "subject"]).optional(),
7464
+ })
7465
+ .nullable()
7466
+ .default(null),
7467
+ metadata: z.record(z.string(), z.unknown()).default({}),
7468
+ createdAt: z.string().optional(),
7469
+ updatedAt: z.string().optional(),
7470
+ });
7471
+ export type CapabilityCatalogItem = z.infer<typeof CapabilityCatalogItem>;
7472
+
7473
+ /**
7474
+ * Shared trust gate for catalog visibility and runtime selection. Registry rows
7475
+ * remain durable for provenance and audit, but only a reviewed real-MCP probe
7476
+ * with known authentication is exposable. API-key rows additionally need a
7477
+ * machine-actionable header contract; prose credential instructions are not a
7478
+ * runtime contract and must fail closed.
7479
+ */
7480
+ export function capabilityCatalogItemIsTrustedForExposure(
7481
+ item: Pick<CapabilityCatalogItem, "source" | "stale" | "authKind" | "metadata">,
7482
+ ): boolean {
7483
+ if (item.stale) return false;
7484
+ if (item.source !== "registry") return true;
7485
+ const probe = item.metadata.mcpProbe;
7486
+ if (!probe || typeof probe !== "object" || Array.isArray(probe)) return false;
7487
+ if ((probe as Record<string, unknown>).status !== "real") return false;
7488
+ if (item.authKind === null || item.authKind === "unknown") return false;
7489
+ if (item.authKind !== "api_key") return true;
7490
+ const contract = item.metadata.authContract;
7491
+ if (!contract || typeof contract !== "object" || Array.isArray(contract)) return false;
7492
+ const record = contract as Record<string, unknown>;
7493
+ return (
7494
+ typeof record.headerName === "string" &&
7495
+ /^[A-Za-z0-9!#$%&'*+.^_`|~-]+$/.test(record.headerName) &&
7496
+ typeof record.scheme === "string" &&
7497
+ record.scheme.trim().length > 0
7498
+ );
7499
+ }
7500
+
7501
+ export const CapabilityInstallation = z.object({
7502
+ id: z.string().uuid(),
7503
+ accountId: z.string().uuid(),
7504
+ workspaceId: z.string().uuid(),
7505
+ capabilityId: z.string().min(1),
7506
+ kind: CapabilityKind,
7507
+ status: CapabilityInstallationStatus,
7508
+ config: z.record(z.string(), z.unknown()),
7509
+ metadata: z.record(z.string(), z.unknown()),
7510
+ enabledAt: z.string(),
7511
+ updatedAt: z.string(),
7512
+ });
7513
+ export type CapabilityInstallation = z.infer<typeof CapabilityInstallation>;
7514
+
7515
+ export const CreateCapabilityCatalogItemRequest = z.object({
7516
+ id: z.string().min(1).optional(),
7517
+ kind: CapabilityKind.exclude(["pack"]),
7518
+ source: CapabilitySource.default("manual"),
7519
+ name: z.string().min(1),
7520
+ description: z.string().min(1).optional(),
7521
+ category: z.string().min(1).default("custom"),
7522
+ tags: z.array(z.string().min(1)).default([]),
7523
+ homepageUrl: z.string().url().optional(),
7524
+ endpointUrl: z.string().url().optional(),
7525
+ installUrl: z.string().url().optional(),
7526
+ authModel: z.string().min(1).optional(),
7527
+ metadata: z.record(z.string(), z.unknown()).default({}),
7528
+ });
7529
+ export type CreateCapabilityCatalogItemRequest = z.infer<typeof CreateCapabilityCatalogItemRequest>;
7530
+
7531
+ export const EnableCapabilityRequest = withVariableSetIdAlias({
7532
+ config: z.record(z.string(), z.unknown()).default({}),
7533
+ metadata: z.record(z.string(), z.unknown()).default({}),
7534
+ connectionRef: McpServerConnectionRef.optional(),
7535
+ /**
7536
+ * Credential headers for remote MCP capabilities (for example an
7537
+ * Authorization bearer token). Values are encrypted at rest with the
7538
+ * workspace-variable-sets key, injected only into the runtime MCP client,
7539
+ * and never returned by the API — responses expose header names only.
7540
+ */
7541
+ headers: z.record(z.string(), z.string()).default({}),
7542
+ /**
7543
+ * Initial variableSet attachment for kind=pack capabilities. Mirrors the
7544
+ * dedicated POST /packs/:id/enable body: required to enable an
7545
+ * variableSet.required pack through the unified capability-enable path,
7546
+ * optional otherwise. Ignored by non-pack capabilities.
7547
+ */
7548
+ variableSetId: z.string().uuid().optional(),
7549
+ environmentId: z.string().uuid().optional(),
7550
+ });
7551
+ export type EnableCapabilityRequest = z.infer<typeof EnableCapabilityRequest>;
7552
+
7553
+ export const CapabilityCatalogResponse = z.object({
7554
+ items: z.array(CapabilityCatalogItem),
7555
+ installations: z.array(CapabilityInstallation),
7556
+ });
7557
+ export type CapabilityCatalogResponse = z.infer<typeof CapabilityCatalogResponse>;
7558
+
7559
+ export const DiscoverMcpCapabilitiesResponse = z.object({
7560
+ items: z.array(CapabilityCatalogItem),
7561
+ source: z.literal("official_mcp_registry"),
7562
+ sourceUrl: z.string().url(),
7563
+ });
7564
+ export type DiscoverMcpCapabilitiesResponse = z.infer<typeof DiscoverMcpCapabilitiesResponse>;
7565
+
7566
+ export const SkillImportSource = z.enum(["github", "skills_sh"]);
7567
+ export type SkillImportSource = z.infer<typeof SkillImportSource>;
7568
+
7569
+ export const PreviewSkillImportRequest = z.object({
7570
+ url: z.string().url().max(2048),
7571
+ });
7572
+ export type PreviewSkillImportRequest = z.infer<typeof PreviewSkillImportRequest>;
7573
+
7574
+ export const SkillImportFileSummary = z.object({
7575
+ path: z.string().min(1).max(1024),
7576
+ byteSize: z.number().int().nonnegative().max(262144),
7577
+ contentSha256: z.string().regex(/^[0-9a-f]{64}$/),
7578
+ });
7579
+ export type SkillImportFileSummary = z.infer<typeof SkillImportFileSummary>;
7580
+
7581
+ export const SkillImportPreview = z.object({
7582
+ source: SkillImportSource,
7583
+ sourceUrl: z.string().url(),
7584
+ repositoryUrl: z.string().url(),
7585
+ owner: z.string().min(1).max(100),
7586
+ repository: z.string().min(1).max(100),
7587
+ sourcePath: z.string().min(1).max(1024),
7588
+ sourceCommit: z.string().regex(/^[0-9a-f]{40,64}$/),
7589
+ name: z.string().regex(/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/),
7590
+ description: z.string().min(1).max(2048),
7591
+ contentSha256: z.string().regex(/^[0-9a-f]{64}$/),
7592
+ totalBytes: z.number().int().positive().max(1048576),
7593
+ files: z.array(SkillImportFileSummary).min(1).max(128),
7594
+ warnings: z.array(z.string().min(1).max(500)).max(32).default([]),
7595
+ installed: z.boolean().default(false),
7596
+ installationVersion: z.number().int().positive().nullable().default(null),
7597
+ });
7598
+ export type SkillImportPreview = z.infer<typeof SkillImportPreview>;
7599
+
7600
+ export const InstallSkillRequest = z.object({
7601
+ url: z.string().url().max(2048),
7602
+ expectedSourceCommit: z.string().regex(/^[0-9a-f]{40,64}$/),
7603
+ expectedContentSha256: z.string().regex(/^[0-9a-f]{64}$/),
7604
+ expectedInstallationVersion: z.number().int().positive().optional(),
7605
+ });
7606
+ export type InstallSkillRequest = z.infer<typeof InstallSkillRequest>;
7607
+
7608
+ export const InstalledSkill = z.object({
7609
+ capabilityId: z.string().min(1),
7610
+ pluginId: z.string().uuid(),
7611
+ pluginVersionId: z.string().uuid(),
7612
+ facetId: z.string().uuid(),
7613
+ pluginInstallationId: z.string().uuid(),
7614
+ facetInstallationId: z.string().uuid(),
7615
+ installationVersion: z.number().int().positive(),
7616
+ source: SkillImportSource,
7617
+ sourceUrl: z.string().url(),
7618
+ sourceCommit: z.string().regex(/^[0-9a-f]{40,64}$/),
7619
+ contentSha256: z.string().regex(/^[0-9a-f]{64}$/),
7620
+ name: z.string(),
7621
+ status: z.literal("installed"),
7622
+ });
7623
+ export type InstalledSkill = z.infer<typeof InstalledSkill>;
7624
+
7625
+ export const CapabilityComponentOwner = z.object({
7626
+ kind: z.enum(["direct", "plugin", "pack", "migration"]),
7627
+ id: z.string().min(1).max(512),
7628
+ removable: z.boolean(),
7629
+ });
7630
+ export type CapabilityComponentOwner = z.infer<typeof CapabilityComponentOwner>;
7631
+
7632
+ export const SkillUninstallPreview = z.object({
7633
+ capabilityId: z.string().min(1),
7634
+ installed: z.boolean(),
7635
+ installationVersion: z.number().int().positive().nullable(),
7636
+ directOwner: CapabilityComponentOwner.nullable(),
7637
+ remainingOwners: z.array(CapabilityComponentOwner),
7638
+ removesRuntimeSkill: z.boolean(),
7639
+ });
7640
+ export type SkillUninstallPreview = z.infer<typeof SkillUninstallPreview>;
7641
+
7642
+ export const UninstallSkillRequest = z.object({
7643
+ expectedInstallationVersion: z.number().int().positive(),
7644
+ });
7645
+ export type UninstallSkillRequest = z.infer<typeof UninstallSkillRequest>;
7646
+
7647
+ export const UninstallSkillResult = z.object({
7648
+ capabilityId: z.string().min(1),
7649
+ status: z.enum(["not_installed", "uninstalled", "retained_by_other_owners"]),
7650
+ remainingOwners: z.array(CapabilityComponentOwner),
7651
+ });
7652
+ export type UninstallSkillResult = z.infer<typeof UninstallSkillResult>;
7653
+
7654
+ export const ApiIntegrationProtocol = z.enum(["openapi", "graphql"]);
7655
+ export type ApiIntegrationProtocol = z.infer<typeof ApiIntegrationProtocol>;
7656
+
7657
+ export const IntegrationFeatureKey = z
7658
+ .string()
7659
+ .min(1)
7660
+ .max(200)
7661
+ .regex(/^[a-z0-9](?:[a-z0-9._/-]*[a-z0-9])?$/);
7662
+ export type IntegrationFeatureKey = z.infer<typeof IntegrationFeatureKey>;
7663
+
7664
+ export const IntegrationFeatureKind = z.enum([
7665
+ "tools",
7666
+ "knowledge_source",
7667
+ "inbound_trigger",
7668
+ "delivery_destination",
7669
+ "identity_link",
7670
+ ]);
7671
+ export type IntegrationFeatureKind = z.infer<typeof IntegrationFeatureKind>;
7672
+
7673
+ export const IntegrationFeatureStatus = z.enum(["active", "paused", "needs_attention", "disabled"]);
7674
+ export type IntegrationFeatureStatus = z.infer<typeof IntegrationFeatureStatus>;
7675
+
7676
+ const IntegrationFeatureJsonObject = z.record(z.string(), z.unknown()).superRefine((value, ctx) => {
7677
+ let serialized: string;
7678
+ try {
7679
+ serialized = JSON.stringify(value);
7680
+ } catch {
7681
+ ctx.addIssue({ code: "custom", message: "must be JSON serializable" });
7682
+ return;
7683
+ }
7684
+ if (new TextEncoder().encode(serialized).byteLength > 131_072) {
7685
+ ctx.addIssue({ code: "custom", message: "must not exceed 131072 UTF-8 bytes" });
7686
+ }
7687
+ });
7688
+
7689
+ export const IntegrationFeatureDefinitionSummary = z
7690
+ .object({
7691
+ featureKey: IntegrationFeatureKey,
7692
+ kind: IntegrationFeatureKind.exclude(["tools"]),
7693
+ configSchema: IntegrationFeatureJsonObject,
7694
+ capabilities: IntegrationFeatureJsonObject,
7695
+ })
7696
+ .strict();
7697
+ export type IntegrationFeatureDefinitionSummary = z.infer<
7698
+ typeof IntegrationFeatureDefinitionSummary
7699
+ >;
7700
+
7701
+ export const ApiIntegrationPresetSummary = z
7702
+ .object({
7703
+ id: z.string().min(1).max(128),
7704
+ name: z.string().min(1).max(200),
7705
+ summary: z.string().min(1).max(1000),
7706
+ family: z.enum(["google", "microsoft"]),
7707
+ protocol: z.literal("openapi"),
7708
+ providerDomain: z.string().min(1).max(253),
7709
+ scopes: z.array(z.string().min(1).max(1024)).max(256),
7710
+ features: z.array(IntegrationFeatureDefinitionSummary).max(128),
7711
+ })
7712
+ .strict();
7713
+ export type ApiIntegrationPresetSummary = z.infer<typeof ApiIntegrationPresetSummary>;
7714
+
7715
+ export const ListApiIntegrationPresetsResponse = z
7716
+ .object({ presets: z.array(ApiIntegrationPresetSummary).max(128) })
7717
+ .strict();
7718
+ export type ListApiIntegrationPresetsResponse = z.infer<typeof ListApiIntegrationPresetsResponse>;
7719
+
7720
+ export const IntegrationInstanceKey = z
7721
+ .string()
7722
+ .min(1)
7723
+ .max(128)
7724
+ .regex(/^[a-z0-9](?:[a-z0-9._/-]*[a-z0-9])?$/);
7725
+ export type IntegrationInstanceKey = z.infer<typeof IntegrationInstanceKey>;
7726
+
7727
+ export const IntegrationFeatureBindingSummary = z
7728
+ .object({
7729
+ id: z.string().uuid(),
7730
+ featureKey: IntegrationFeatureKey,
7731
+ kind: IntegrationFeatureKind.exclude(["tools"]),
7732
+ bindingKey: IntegrationInstanceKey,
7733
+ displayName: z.string().min(1).max(200),
7734
+ connectionId: z.string().uuid().nullable(),
7735
+ status: IntegrationFeatureStatus,
7736
+ config: IntegrationFeatureJsonObject,
7737
+ version: z.number().int().positive(),
7738
+ hasCursor: z.boolean(),
7739
+ lastSuccessAt: z.string().datetime({ offset: true }).nullable(),
7740
+ lastErrorCode: z.string().min(1).max(120).nullable(),
7741
+ createdAt: z.string().datetime({ offset: true }),
7742
+ updatedAt: z.string().datetime({ offset: true }),
7743
+ })
7744
+ .strict();
7745
+ export type IntegrationFeatureBindingSummary = z.infer<typeof IntegrationFeatureBindingSummary>;
7746
+
7747
+ export const IntegrationInstanceFeaturesResponse = z
7748
+ .object({
7749
+ capabilityId: z.string().min(1).max(512),
7750
+ instanceKey: IntegrationInstanceKey,
7751
+ providerDomain: z.string().min(1).max(253),
7752
+ connectionId: z.string().uuid().nullable(),
7753
+ features: z
7754
+ .array(
7755
+ z
7756
+ .object({
7757
+ definition: IntegrationFeatureDefinitionSummary,
7758
+ binding: IntegrationFeatureBindingSummary.nullable(),
7759
+ })
7760
+ .strict(),
7761
+ )
7762
+ .max(128),
7763
+ })
7764
+ .strict();
7765
+ export type IntegrationInstanceFeaturesResponse = z.infer<
7766
+ typeof IntegrationInstanceFeaturesResponse
7767
+ >;
7768
+
7769
+ export const UpsertIntegrationFeatureRequest = z
7770
+ .object({
7771
+ displayName: z.string().min(1).max(200),
7772
+ config: IntegrationFeatureJsonObject.default({}),
7773
+ expectedVersion: z.number().int().positive().optional(),
7774
+ idempotencyKey: z.string().uuid(),
7775
+ })
7776
+ .strict();
7777
+ export type UpsertIntegrationFeatureRequest = z.infer<typeof UpsertIntegrationFeatureRequest>;
7778
+
7779
+ export const MutateIntegrationFeatureRequest = z
7780
+ .object({
7781
+ expectedVersion: z.number().int().positive(),
7782
+ idempotencyKey: z.string().uuid(),
7783
+ })
7784
+ .strict();
7785
+ export type MutateIntegrationFeatureRequest = z.infer<typeof MutateIntegrationFeatureRequest>;
7786
+
7787
+ export const IntegrationFeatureMutationResult = z
7788
+ .object({
7789
+ capabilityId: z.string().min(1).max(512),
7790
+ instanceKey: IntegrationInstanceKey,
7791
+ featureKey: IntegrationFeatureKey,
7792
+ status: z.enum(["configured", "paused", "active"]),
7793
+ binding: IntegrationFeatureBindingSummary,
7794
+ })
7795
+ .strict();
7796
+ export type IntegrationFeatureMutationResult = z.infer<typeof IntegrationFeatureMutationResult>;
7797
+
7798
+ export const IntegrationFeatureRemovalResult = z
7799
+ .object({
7800
+ capabilityId: z.string().min(1).max(512),
7801
+ instanceKey: IntegrationInstanceKey,
7802
+ featureKey: IntegrationFeatureKey,
7803
+ status: z.enum(["not_configured", "removed", "retained_by_other_owners"]),
7804
+ binding: IntegrationFeatureBindingSummary.nullable(),
7805
+ remainingOwners: z.array(CapabilityComponentOwner),
7806
+ })
7807
+ .strict();
7808
+ export type IntegrationFeatureRemovalResult = z.infer<typeof IntegrationFeatureRemovalResult>;
7809
+
7810
+ export const ApiIntegrationSource = z.discriminatedUnion("kind", [
7811
+ z.object({ kind: z.literal("preset"), presetId: z.string().min(1).max(128) }).strict(),
7812
+ z
7813
+ .object({
7814
+ kind: z.literal("openapi"),
7815
+ url: z.string().url().max(2048),
7816
+ baseUrl: z.string().url().max(2048).optional(),
7817
+ })
7818
+ .strict(),
7819
+ z
7820
+ .object({
7821
+ kind: z.literal("graphql"),
7822
+ endpoint: z.string().url().max(2048),
7823
+ name: z.string().min(1).max(200).optional(),
7824
+ })
7825
+ .strict(),
7826
+ z
7827
+ .object({
7828
+ kind: z.literal("auto"),
7829
+ url: z.string().url().max(2048),
7830
+ baseUrl: z.string().url().max(2048).optional(),
7831
+ })
7832
+ .strict(),
7833
+ ]);
7834
+ export type ApiIntegrationSource = z.infer<typeof ApiIntegrationSource>;
7835
+
7836
+ export const PreviewApiIntegrationRequest = z
7837
+ .object({
7838
+ source: ApiIntegrationSource,
7839
+ connectionId: z.string().uuid().optional(),
7840
+ ownership: ConnectionOwnership.optional(),
7841
+ })
7842
+ .strict();
7843
+ export type PreviewApiIntegrationRequest = z.infer<typeof PreviewApiIntegrationRequest>;
7844
+
7845
+ export const ApiIntegrationOAuthStartRequest = z
7846
+ .object({
7847
+ presetId: z.string().min(1).max(128),
7848
+ ownership: ConnectionOwnership.optional(),
7849
+ connectionId: z.string().uuid().optional(),
7850
+ returnPath: z.string().min(1).max(2048).optional(),
7851
+ })
7852
+ .strict();
7853
+ export type ApiIntegrationOAuthStartRequest = z.infer<typeof ApiIntegrationOAuthStartRequest>;
7854
+
7855
+ export const API_INTEGRATION_OAUTH_CREDENTIAL_ROLE = "api_integration_oauth" as const;
7856
+
7857
+ export const ApiIntegrationOAuthConnectionMetadata = z
7858
+ .object({
7859
+ credentialRole: z.literal(API_INTEGRATION_OAUTH_CREDENTIAL_ROLE),
7860
+ providerFamily: z.enum(["google", "microsoft"]),
7861
+ providerPrincipalId: z.string().min(1).max(512),
7862
+ providerEmail: z.string().min(1).max(512).nullable(),
7863
+ providerDisplayName: z.string().min(1).max(512).nullable(),
7864
+ authorizedPresetIds: z.array(z.string().min(1).max(128)).min(1).max(32),
7865
+ verifiedAt: z.string().datetime({ offset: true }),
7866
+ })
7867
+ .passthrough();
7868
+ export type ApiIntegrationOAuthConnectionMetadata = z.infer<
7869
+ typeof ApiIntegrationOAuthConnectionMetadata
7870
+ >;
7871
+
7872
+ export const ApiIntegrationAuthPreview = z.discriminatedUnion("kind", [
7873
+ z.object({ kind: z.literal("none") }).strict(),
7874
+ z
7875
+ .object({
7876
+ kind: z.literal("oauth2"),
7877
+ providerDomain: z.string().min(1).max(253),
7878
+ scopes: z.array(z.string().min(1).max(1024)).max(256),
7879
+ })
7880
+ .strict(),
7881
+ z
7882
+ .object({
7883
+ kind: z.literal("api_key"),
7884
+ providerDomain: z.string().min(1).max(253),
7885
+ carrier: z.enum(["header", "query", "cookie"]),
7886
+ name: z.string().min(1).max(256),
7887
+ })
7888
+ .strict(),
7889
+ z
7890
+ .object({
7891
+ kind: z.literal("http"),
7892
+ providerDomain: z.string().min(1).max(253),
7893
+ scheme: z.string().min(1).max(64),
7894
+ })
7895
+ .strict(),
7896
+ ]);
7897
+ export type ApiIntegrationAuthPreview = z.infer<typeof ApiIntegrationAuthPreview>;
7898
+
7899
+ export const ApiIntegrationToolPreview = z
7900
+ .object({
7901
+ id: z.string().min(1).max(200),
7902
+ operationKey: z.string().min(1).max(512),
7903
+ name: z.string().min(1).max(200),
7904
+ description: z.string().max(4000),
7905
+ safety: z.enum(["read", "write", "destructive"]),
7906
+ approvalMode: z.enum(["never", "ask"]),
7907
+ deprecated: z.boolean(),
7908
+ })
7909
+ .strict();
7910
+ export type ApiIntegrationToolPreview = z.infer<typeof ApiIntegrationToolPreview>;
7911
+
7912
+ export const ApiIntegrationPreview = z
7913
+ .object({
7914
+ source: ApiIntegrationSource,
7915
+ presetId: z.string().min(1).max(128).nullable(),
7916
+ protocol: ApiIntegrationProtocol,
7917
+ integrationId: z.string().min(1).max(200),
7918
+ capabilityId: z.string().min(1).max(512),
7919
+ pluginKey: z.string().min(1).max(200),
7920
+ serverId: SessionMcpServerId,
7921
+ name: z.string().min(1).max(200),
7922
+ description: z.string().max(4000).nullable(),
7923
+ provider: z.string().min(1).max(128).nullable(),
7924
+ providerDomain: z.string().min(1).max(253),
7925
+ baseUrl: z.string().url().max(2048),
7926
+ sourceUrl: z.string().url().max(2048).nullable(),
7927
+ revisionId: z.string().min(1).max(96),
7928
+ contentSha256: z.string().regex(/^[0-9a-f]{64}$/),
7929
+ auth: ApiIntegrationAuthPreview,
7930
+ connectionId: z.string().uuid().nullable(),
7931
+ connectionOwnership: ConnectionOwnership.nullable(),
7932
+ tools: z.array(ApiIntegrationToolPreview).min(1).max(2000),
7933
+ warnings: z.array(z.string().min(1).max(500)).max(32).default([]),
7934
+ })
7935
+ .strict();
7936
+ export type ApiIntegrationPreview = z.infer<typeof ApiIntegrationPreview>;
7937
+
7938
+ export const InstallApiIntegrationRequest = z
7939
+ .object({
7940
+ source: ApiIntegrationSource,
7941
+ expectedRevisionId: z.string().min(1).max(96),
7942
+ expectedContentSha256: z.string().regex(/^[0-9a-f]{64}$/),
7943
+ connectionId: z.string().uuid().optional(),
7944
+ ownership: ConnectionOwnership.optional(),
7945
+ instanceKey: IntegrationInstanceKey.optional(),
7946
+ displayName: z.string().min(1).max(200).optional(),
7947
+ expectedInstanceVersion: z.number().int().positive().optional(),
7948
+ allowedTools: z.array(z.string().min(1).max(200)).max(2000).optional(),
7949
+ })
7950
+ .strict();
7951
+ export type InstallApiIntegrationRequest = z.infer<typeof InstallApiIntegrationRequest>;
7952
+
7953
+ export const InstalledApiIntegration = z
7954
+ .object({
7955
+ capabilityId: z.string().min(1),
7956
+ pluginId: z.string().uuid(),
7957
+ pluginVersionId: z.string().uuid(),
7958
+ integrationFacetId: z.string().uuid(),
7959
+ apiFacetId: z.string().uuid(),
7960
+ pluginInstallationId: z.string().uuid(),
7961
+ integrationFacetInstallationId: z.string().uuid(),
7962
+ apiFacetInstallationId: z.string().uuid(),
7963
+ installationVersion: z.number().int().positive(),
7964
+ instanceId: z.string().uuid(),
7965
+ instanceKey: IntegrationInstanceKey,
7966
+ displayName: z.string().min(1).max(200),
7967
+ instanceVersion: z.number().int().positive(),
7968
+ revisionId: z.string().min(1),
7969
+ serverId: SessionMcpServerId,
7970
+ status: z.literal("installed"),
7971
+ })
7972
+ .strict();
7973
+ export type InstalledApiIntegration = z.infer<typeof InstalledApiIntegration>;
7974
+
7975
+ export const ApiIntegrationInstallationSummary = z
7976
+ .object({
7977
+ capabilityId: z.string().min(1),
7978
+ pluginKey: z.string().min(1),
7979
+ installationVersion: z.number().int().positive(),
7980
+ instanceId: z.string().uuid(),
7981
+ instanceKey: IntegrationInstanceKey,
7982
+ displayName: z.string().min(1).max(200),
7983
+ instanceVersion: z.number().int().positive(),
7984
+ serverId: SessionMcpServerId,
7985
+ name: z.string().min(1),
7986
+ description: z.string().nullable(),
7987
+ protocol: ApiIntegrationProtocol,
7988
+ presetId: z.string().min(1).max(128).nullable(),
7989
+ providerDomain: z.string().min(1),
7990
+ baseUrl: z.string().url(),
7991
+ sourceUrl: z.string().url().nullable(),
7992
+ connected: z.boolean(),
7993
+ requiresConnection: z.boolean(),
7994
+ connectionId: z.string().uuid().nullable(),
7995
+ ownership: z.enum(["workspace", "personal", "none"]),
7996
+ allowedTools: z.array(z.string().min(1).max(200)).max(2000),
7997
+ toolCount: z.number().int().nonnegative(),
7998
+ approvalRequiredToolCount: z.number().int().nonnegative(),
7999
+ revisionId: z.string().min(1),
8000
+ contentSha256: z.string().regex(/^[0-9a-f]{64}$/),
8001
+ })
8002
+ .strict();
8003
+ export type ApiIntegrationInstallationSummary = z.infer<typeof ApiIntegrationInstallationSummary>;
8004
+
8005
+ export const ListApiIntegrationsResponse = z
8006
+ .object({ integrations: z.array(ApiIntegrationInstallationSummary) })
8007
+ .strict();
8008
+ export type ListApiIntegrationsResponse = z.infer<typeof ListApiIntegrationsResponse>;
8009
+
8010
+ export const ApiIntegrationUninstallPreview = z
8011
+ .object({
8012
+ capabilityId: z.string().min(1),
8013
+ instanceKey: IntegrationInstanceKey,
8014
+ displayName: z.string().min(1).max(200).nullable(),
8015
+ installed: z.boolean(),
8016
+ installationVersion: z.number().int().positive().nullable(),
8017
+ instanceVersion: z.number().int().positive().nullable(),
8018
+ directOwner: CapabilityComponentOwner.nullable(),
8019
+ remainingOwners: z.array(CapabilityComponentOwner),
8020
+ removesRuntimeIntegration: z.boolean(),
8021
+ removesDefinition: z.boolean(),
8022
+ })
8023
+ .strict();
8024
+ export type ApiIntegrationUninstallPreview = z.infer<typeof ApiIntegrationUninstallPreview>;
8025
+
8026
+ export const UninstallApiIntegrationRequest = z
8027
+ .object({
8028
+ expectedInstallationVersion: z.number().int().positive(),
8029
+ expectedInstanceVersion: z.number().int().positive(),
8030
+ })
8031
+ .strict();
8032
+ export type UninstallApiIntegrationRequest = z.infer<typeof UninstallApiIntegrationRequest>;
8033
+
8034
+ export const UninstallApiIntegrationResult = z
8035
+ .object({
8036
+ capabilityId: z.string().min(1),
8037
+ instanceKey: IntegrationInstanceKey,
8038
+ status: z.enum(["not_installed", "uninstalled", "retained_by_other_owners"]),
8039
+ remainingOwners: z.array(CapabilityComponentOwner),
8040
+ definitionStatus: z.enum(["retained", "disabled"]),
8041
+ })
8042
+ .strict();
8043
+ export type UninstallApiIntegrationResult = z.infer<typeof UninstallApiIntegrationResult>;
8044
+
8045
+ const PluginComponentKey = z
8046
+ .string()
8047
+ .min(1)
8048
+ .max(128)
8049
+ .regex(/^[a-z0-9](?:[a-z0-9._/-]*[a-z0-9])?$/);
8050
+
8051
+ export const PluginManifest = z
8052
+ .object({
8053
+ schemaVersion: z.literal(1),
8054
+ pluginKey: z
8055
+ .string()
8056
+ .min(1)
8057
+ .max(200)
8058
+ .regex(/^[a-z0-9](?:[a-z0-9._/-]*[a-z0-9])?$/),
8059
+ version: z.string().min(1).max(128),
8060
+ name: z.string().min(1).max(200),
8061
+ description: z.string().max(4000).default(""),
8062
+ category: z.string().min(1).max(100).default("plugins"),
8063
+ tags: z.array(z.string().min(1).max(100)).max(64).default([]),
8064
+ components: z
8065
+ .array(
8066
+ z.discriminatedUnion("kind", [
8067
+ z
8068
+ .object({ key: PluginComponentKey, kind: z.literal("skill"), url: z.string().url() })
8069
+ .strict(),
8070
+ z
8071
+ .object({
8072
+ key: PluginComponentKey,
8073
+ kind: z.literal("integration"),
8074
+ source: ApiIntegrationSource,
8075
+ })
8076
+ .strict(),
8077
+ z
8078
+ .object({
8079
+ key: PluginComponentKey,
8080
+ kind: z.literal("mcp"),
8081
+ serverId: SessionMcpServerId,
8082
+ })
8083
+ .strict(),
8084
+ ]),
8085
+ )
8086
+ .min(1)
8087
+ .max(64),
8088
+ })
8089
+ .strict()
8090
+ .superRefine((manifest, context) => {
8091
+ const seen = new Set<string>();
8092
+ for (const [index, component] of manifest.components.entries()) {
8093
+ if (seen.has(component.key)) {
8094
+ context.addIssue({
8095
+ code: "custom",
8096
+ message: "Plugin component keys must be unique",
8097
+ path: ["components", index, "key"],
8098
+ });
8099
+ }
8100
+ seen.add(component.key);
8101
+ }
8102
+ });
8103
+ export type PluginManifest = z.infer<typeof PluginManifest>;
8104
+
8105
+ export const PluginComponentBinding = z
8106
+ .object({
8107
+ connectionId: z.string().uuid().optional(),
8108
+ instanceKey: IntegrationInstanceKey.optional(),
8109
+ displayName: z.string().min(1).max(200).optional(),
8110
+ })
8111
+ .strict();
8112
+ export type PluginComponentBinding = z.infer<typeof PluginComponentBinding>;
6080
8113
 
6081
- /**
6082
- * Shared trust gate for catalog visibility and runtime selection. Registry rows
6083
- * remain durable for provenance and audit, but only a reviewed real-MCP probe
6084
- * with known authentication is exposable. API-key rows additionally need a
6085
- * machine-actionable header contract; prose credential instructions are not a
6086
- * runtime contract and must fail closed.
6087
- */
6088
- export function capabilityCatalogItemIsTrustedForExposure(
6089
- item: Pick<CapabilityCatalogItem, "source" | "stale" | "authKind" | "metadata">,
6090
- ): boolean {
6091
- if (item.stale) return false;
6092
- if (item.source !== "registry") return true;
6093
- const probe = item.metadata.mcpProbe;
6094
- if (!probe || typeof probe !== "object" || Array.isArray(probe)) return false;
6095
- if ((probe as Record<string, unknown>).status !== "real") return false;
6096
- if (item.authKind === null || item.authKind === "unknown") return false;
6097
- if (item.authKind !== "api_key") return true;
6098
- const contract = item.metadata.authContract;
6099
- if (!contract || typeof contract !== "object" || Array.isArray(contract)) return false;
6100
- const record = contract as Record<string, unknown>;
6101
- return (
6102
- typeof record.headerName === "string" &&
6103
- /^[A-Za-z0-9!#$%&'*+.^_`|~-]+$/.test(record.headerName) &&
6104
- typeof record.scheme === "string" &&
6105
- record.scheme.trim().length > 0
6106
- );
6107
- }
8114
+ export const PreviewPluginRequest = z
8115
+ .object({
8116
+ url: z.string().url().max(2048),
8117
+ bindings: z.record(PluginComponentKey, PluginComponentBinding).default({}),
8118
+ })
8119
+ .strict();
8120
+ export type PreviewPluginRequest = z.infer<typeof PreviewPluginRequest>;
6108
8121
 
6109
- export const CapabilityInstallation = z.object({
6110
- id: z.string().uuid(),
6111
- accountId: z.string().uuid(),
6112
- workspaceId: z.string().uuid(),
6113
- capabilityId: z.string().min(1),
6114
- kind: CapabilityKind,
6115
- status: CapabilityInstallationStatus,
6116
- config: z.record(z.string(), z.unknown()),
6117
- metadata: z.record(z.string(), z.unknown()),
6118
- enabledAt: z.string(),
6119
- updatedAt: z.string(),
6120
- });
6121
- export type CapabilityInstallation = z.infer<typeof CapabilityInstallation>;
8122
+ export const PluginComponentPreview = z
8123
+ .object({
8124
+ key: PluginComponentKey,
8125
+ kind: z.enum(["skill", "integration", "mcp"]),
8126
+ name: z.string().min(1).max(200),
8127
+ capabilityId: z.string().min(1).max(512),
8128
+ digest: z.string().regex(/^[0-9a-f]{64}$/),
8129
+ connectionRequired: z.boolean(),
8130
+ connectionId: z.string().uuid().nullable(),
8131
+ instanceKey: IntegrationInstanceKey.nullable(),
8132
+ displayName: z.string().min(1).max(200).nullable(),
8133
+ facts: z.record(z.string(), z.unknown()),
8134
+ })
8135
+ .strict();
8136
+ export type PluginComponentPreview = z.infer<typeof PluginComponentPreview>;
6122
8137
 
6123
- export const CreateCapabilityCatalogItemRequest = z.object({
6124
- id: z.string().min(1).optional(),
6125
- kind: CapabilityKind.exclude(["pack"]),
6126
- source: CapabilitySource.default("manual"),
6127
- name: z.string().min(1),
6128
- description: z.string().min(1).optional(),
6129
- category: z.string().min(1).default("custom"),
6130
- tags: z.array(z.string().min(1)).default([]),
6131
- homepageUrl: z.string().url().optional(),
6132
- endpointUrl: z.string().url().optional(),
6133
- installUrl: z.string().url().optional(),
6134
- authModel: z.string().min(1).optional(),
6135
- metadata: z.record(z.string(), z.unknown()).default({}),
6136
- });
6137
- export type CreateCapabilityCatalogItemRequest = z.infer<typeof CreateCapabilityCatalogItemRequest>;
8138
+ export const PluginUpdateDiff = z
8139
+ .object({
8140
+ fromVersion: z.string().nullable(),
8141
+ toVersion: z.string().min(1),
8142
+ added: z.array(PluginComponentKey),
8143
+ removed: z.array(PluginComponentKey),
8144
+ changed: z.array(PluginComponentKey),
8145
+ unchanged: z.array(PluginComponentKey),
8146
+ })
8147
+ .strict();
8148
+ export type PluginUpdateDiff = z.infer<typeof PluginUpdateDiff>;
6138
8149
 
6139
- export const EnableCapabilityRequest = withVariableSetIdAlias({
6140
- config: z.record(z.string(), z.unknown()).default({}),
6141
- metadata: z.record(z.string(), z.unknown()).default({}),
6142
- connectionRef: McpServerConnectionRef.optional(),
6143
- /**
6144
- * Credential headers for remote MCP capabilities (for example an
6145
- * Authorization bearer token). Values are encrypted at rest with the
6146
- * workspace-variable-sets key, injected only into the runtime MCP client,
6147
- * and never returned by the API — responses expose header names only.
6148
- */
6149
- headers: z.record(z.string(), z.string()).default({}),
6150
- /**
6151
- * Initial variableSet attachment for kind=pack capabilities. Mirrors the
6152
- * dedicated POST /packs/:id/enable body: required to enable an
6153
- * variableSet.required pack through the unified capability-enable path,
6154
- * optional otherwise. Ignored by non-pack capabilities.
6155
- */
6156
- variableSetId: z.string().uuid().optional(),
6157
- environmentId: z.string().uuid().optional(),
6158
- });
6159
- export type EnableCapabilityRequest = z.infer<typeof EnableCapabilityRequest>;
8150
+ export const PluginPreview = z
8151
+ .object({
8152
+ sourceUrl: z.string().url(),
8153
+ manifest: PluginManifest,
8154
+ manifestDigest: z.string().regex(/^[0-9a-f]{64}$/),
8155
+ installed: z.boolean(),
8156
+ installationVersion: z.number().int().positive().nullable(),
8157
+ components: z.array(PluginComponentPreview).min(1).max(64),
8158
+ diff: PluginUpdateDiff,
8159
+ })
8160
+ .strict();
8161
+ export type PluginPreview = z.infer<typeof PluginPreview>;
6160
8162
 
6161
- export const CapabilityCatalogResponse = z.object({
6162
- items: z.array(CapabilityCatalogItem),
6163
- installations: z.array(CapabilityInstallation),
6164
- });
6165
- export type CapabilityCatalogResponse = z.infer<typeof CapabilityCatalogResponse>;
8163
+ export const InstallPluginRequest = z
8164
+ .object({
8165
+ url: z.string().url().max(2048),
8166
+ expectedManifestDigest: z.string().regex(/^[0-9a-f]{64}$/),
8167
+ expectedComponents: z
8168
+ .array(
8169
+ z.object({ key: PluginComponentKey, digest: z.string().regex(/^[0-9a-f]{64}$/) }).strict(),
8170
+ )
8171
+ .min(1)
8172
+ .max(64),
8173
+ bindings: z.record(PluginComponentKey, PluginComponentBinding).default({}),
8174
+ idempotencyKey: z.string().uuid(),
8175
+ expectedInstallationVersion: z.number().int().positive().optional(),
8176
+ })
8177
+ .strict();
8178
+ export type InstallPluginRequest = z.infer<typeof InstallPluginRequest>;
6166
8179
 
6167
- export const DiscoverMcpCapabilitiesResponse = z.object({
6168
- items: z.array(CapabilityCatalogItem),
6169
- source: z.literal("official_mcp_registry"),
6170
- sourceUrl: z.string().url(),
6171
- });
6172
- export type DiscoverMcpCapabilitiesResponse = z.infer<typeof DiscoverMcpCapabilitiesResponse>;
8180
+ export const InstalledPlugin = z
8181
+ .object({
8182
+ pluginKey: z.string().min(1),
8183
+ version: z.string().min(1),
8184
+ pluginId: z.string().uuid(),
8185
+ pluginVersionId: z.string().uuid(),
8186
+ pluginInstallationId: z.string().uuid(),
8187
+ installationVersion: z.number().int().positive(),
8188
+ componentCount: z.number().int().positive(),
8189
+ status: z.literal("installed"),
8190
+ })
8191
+ .strict();
8192
+ export type InstalledPlugin = z.infer<typeof InstalledPlugin>;
8193
+
8194
+ export const PluginInstallationSummary = z
8195
+ .object({
8196
+ pluginKey: z.string().min(1).max(200),
8197
+ version: z.string().min(1).max(128),
8198
+ name: z.string().min(1).max(200),
8199
+ description: z.string().max(4000),
8200
+ category: z.string().min(1).max(100),
8201
+ tags: z.array(z.string().min(1).max(100)).max(64),
8202
+ sourceUrl: z.string().url().max(2048).nullable(),
8203
+ manifestDigest: z.string().regex(/^[0-9a-f]{64}$/),
8204
+ installationVersion: z.number().int().positive(),
8205
+ componentCount: z.number().int().nonnegative().max(64),
8206
+ status: z.enum(["active", "needs_attention"]),
8207
+ installedAt: z.string().datetime({ offset: true }),
8208
+ updatedAt: z.string().datetime({ offset: true }),
8209
+ })
8210
+ .strict();
8211
+ export type PluginInstallationSummary = z.infer<typeof PluginInstallationSummary>;
8212
+
8213
+ export const ListInstalledPluginsResponse = z
8214
+ .object({ plugins: z.array(PluginInstallationSummary).max(1000) })
8215
+ .strict();
8216
+ export type ListInstalledPluginsResponse = z.infer<typeof ListInstalledPluginsResponse>;
8217
+
8218
+ export const PluginUninstallPreview = z
8219
+ .object({
8220
+ pluginKey: z.string().min(1),
8221
+ installed: z.boolean(),
8222
+ version: z.string().nullable(),
8223
+ installationVersion: z.number().int().positive().nullable(),
8224
+ components: z.array(
8225
+ z.object({
8226
+ capabilityId: z.string().min(1),
8227
+ kind: z.enum(["skill", "integration", "mcp"]),
8228
+ retainedByOtherOwners: z.boolean(),
8229
+ }),
8230
+ ),
8231
+ })
8232
+ .strict();
8233
+ export type PluginUninstallPreview = z.infer<typeof PluginUninstallPreview>;
8234
+
8235
+ export const UninstallPluginRequest = z
8236
+ .object({
8237
+ expectedInstallationVersion: z.number().int().positive(),
8238
+ idempotencyKey: z.string().uuid(),
8239
+ })
8240
+ .strict();
8241
+ export type UninstallPluginRequest = z.infer<typeof UninstallPluginRequest>;
8242
+
8243
+ export const UninstallPluginResult = z
8244
+ .object({
8245
+ pluginKey: z.string().min(1),
8246
+ status: z.enum(["not_installed", "uninstalled"]),
8247
+ retainedComponents: z.array(z.string().min(1)),
8248
+ })
8249
+ .strict();
8250
+ export type UninstallPluginResult = z.infer<typeof UninstallPluginResult>;
6173
8251
 
6174
8252
  export const Session = z.object({
6175
8253
  id: z.string().uuid(),
@@ -6334,6 +8412,57 @@ export const SessionListResponse = z.object({
6334
8412
  });
6335
8413
  export type SessionListResponse = z.infer<typeof SessionListResponse>;
6336
8414
 
8415
+ /** Compact, bounded session projection for workspace agent-topology browsers. */
8416
+ export const AgentTopologySession = z.object({
8417
+ id: z.string().uuid(),
8418
+ title: z.string().nullable(),
8419
+ titleTruncated: z.boolean(),
8420
+ parentSessionId: z.string().uuid().nullable(),
8421
+ rootSessionId: z.string().uuid(),
8422
+ nestedAgentDepth: NestedAgentDepthValue,
8423
+ ancestorPath: z.array(
8424
+ z.object({
8425
+ id: z.string().uuid(),
8426
+ title: z.string().nullable(),
8427
+ titleTruncated: z.boolean(),
8428
+ }),
8429
+ ),
8430
+ status: SessionStatus,
8431
+ pause: z.object({
8432
+ state: z.enum(["active", "paused"]),
8433
+ additionalBlockerCount: z.number().int().nonnegative(),
8434
+ source: z
8435
+ .object({
8436
+ kind: z.enum(["session", "workspace"]),
8437
+ sessionId: z.string().uuid().optional(),
8438
+ displayName: z.string(),
8439
+ displayNameTruncated: z.boolean(),
8440
+ })
8441
+ .nullable(),
8442
+ }),
8443
+ children: z.object({
8444
+ directChildren: z.number().int().nonnegative(),
8445
+ totalDescendants: z.number().int().nonnegative(),
8446
+ runningDescendants: z.number().int().nonnegative(),
8447
+ queuedDescendants: z.number().int().nonnegative(),
8448
+ attentionDescendants: z.number().int().nonnegative(),
8449
+ pausedDescendants: z.number().int().nonnegative(),
8450
+ failedDescendants: z.number().int().nonnegative(),
8451
+ truncated: z.boolean(),
8452
+ }),
8453
+ createdAt: z.string(),
8454
+ updatedAt: z.string(),
8455
+ });
8456
+ export type AgentTopologySession = z.infer<typeof AgentTopologySession>;
8457
+
8458
+ export const AgentTopologyPageResponse = z.object({
8459
+ sessions: z.array(AgentTopologySession),
8460
+ total: z.number().int().nonnegative(),
8461
+ hasMore: z.boolean(),
8462
+ nextCursor: z.string().nullable(),
8463
+ });
8464
+ export type AgentTopologyPageResponse = z.infer<typeof AgentTopologyPageResponse>;
8465
+
6337
8466
  // Recursive: the TS type is declared first so the schema annotation can carry
6338
8467
  // the FULL recursive shape (a shallow annotation loses type information for
6339
8468
  // contracts consumers after one level of nesting).
@@ -6752,6 +8881,21 @@ export const ToolAuthNeededPayload = z.object({
6752
8881
  selectedResources: McpConnectionResourceScopes.optional(),
6753
8882
  authorizationUrl: z.string().url().optional(),
6754
8883
  subjectId: z.string().min(1).nullable().optional(),
8884
+ // A catalog recommendation is still a tool-level authorization condition:
8885
+ // the agent may describe and request it, but only the authenticated host UI
8886
+ // can start setup. Keeping this nested and optional preserves the established
8887
+ // auth-needed event for ordinary failed MCP calls.
8888
+ capability: z
8889
+ .object({
8890
+ id: z.string().min(1).max(512),
8891
+ name: z.string().min(1).max(256),
8892
+ kind: CapabilityKind,
8893
+ source: CapabilitySource,
8894
+ action: z.enum(["connect", "add_credentials", "enable"]),
8895
+ rationale: z.string().min(1).max(2000),
8896
+ requiredVariables: z.array(VariableSetVariableName).max(64).default([]),
8897
+ })
8898
+ .optional(),
6755
8899
  });
6756
8900
  export type ToolAuthNeededPayload = z.infer<typeof ToolAuthNeededPayload>;
6757
8901
 
@@ -6863,8 +9007,8 @@ export const RecordingFailedPayload = z.object({
6863
9007
  recordingId: z.string().uuid(),
6864
9008
  turnId: z.string().uuid().nullable(),
6865
9009
  reason: RecordingFailedReason,
6866
- // ffmpeg-stderr tail / error detail agent/ffmpeg-controlled, so the producer
6867
- // caps + scrubs it before emit (it rides redact() like every payload).
9010
+ // Exact ffmpeg stderr/error detail. Event transport limits must reject or
9011
+ // paginate rather than rewriting this canonical diagnostic.
6868
9012
  detail: z.string().nullable().optional(),
6869
9013
  });
6870
9014
  export type RecordingFailedPayload = z.infer<typeof RecordingFailedPayload>;
@@ -6992,6 +9136,18 @@ export const FsListResponse = z.object({
6992
9136
  });
6993
9137
  export type FsListResponse = z.infer<typeof FsListResponse>;
6994
9138
 
9139
+ /** Several independent directory listings served behind one Channel-A lease.
9140
+ * The response order exactly matches `requests`; callers can paint a root and
9141
+ * hydrate a bounded lazy-tree frontier without repeating provider attach work. */
9142
+ export const FsListBatchRequest = z.object({
9143
+ requests: z.array(FsListRequest).min(1).max(16),
9144
+ });
9145
+ export type FsListBatchRequest = z.infer<typeof FsListBatchRequest>;
9146
+ export const FsListBatchResponse = z.object({
9147
+ results: z.array(FsListResponse),
9148
+ });
9149
+ export type FsListBatchResponse = z.infer<typeof FsListBatchResponse>;
9150
+
6995
9151
  export const FsEncoding = z.enum(["utf8", "base64"]);
6996
9152
  export type FsEncoding = z.infer<typeof FsEncoding>;
6997
9153
  export const FsReadRequest = z.object({
@@ -7094,6 +9250,9 @@ export type GitStatusRequest = z.infer<typeof GitStatusRequest>;
7094
9250
  export const GitStatusResponse = z.object({
7095
9251
  isRepo: z.boolean(),
7096
9252
  head: z.string().nullable(), // branch name
9253
+ // Exact commit object identity. null for unborn/non-repositories; optional
9254
+ // only so older adapters and serialized captures remain readable.
9255
+ headOid: z.string().nullable().optional(),
7097
9256
  detached: z.boolean().default(false),
7098
9257
  upstream: z.string().nullable(),
7099
9258
  ahead: z.number().int().nonnegative().default(0),
@@ -7160,6 +9319,27 @@ export const GitDiffResponse = z.object({
7160
9319
  });
7161
9320
  export type GitDiffResponse = z.infer<typeof GitDiffResponse>;
7162
9321
 
9322
+ /** One repository read unit: status metadata plus an optional comparison.
9323
+ * Multiple units execute behind one Channel-A lease and preserve input order. */
9324
+ export const GitReadBatchItemRequest = z.object({
9325
+ status: GitStatusRequest,
9326
+ diff: GitDiffRequest.optional(),
9327
+ });
9328
+ export type GitReadBatchItemRequest = z.infer<typeof GitReadBatchItemRequest>;
9329
+ export const GitReadBatchRequest = z.object({
9330
+ requests: z.array(GitReadBatchItemRequest).min(1).max(32),
9331
+ });
9332
+ export type GitReadBatchRequest = z.infer<typeof GitReadBatchRequest>;
9333
+ export const GitReadBatchItemResponse = z.object({
9334
+ status: GitStatusResponse,
9335
+ diff: GitDiffResponse.optional(),
9336
+ });
9337
+ export type GitReadBatchItemResponse = z.infer<typeof GitReadBatchItemResponse>;
9338
+ export const GitReadBatchResponse = z.object({
9339
+ results: z.array(GitReadBatchItemResponse),
9340
+ });
9341
+ export type GitReadBatchResponse = z.infer<typeof GitReadBatchResponse>;
9342
+
7163
9343
  // ─── Workbench v2 turn-end workspace capture ────────────
7164
9344
  // A capture is a point-in-time snapshot of the session workspace's CHANGES,
7165
9345
  // probed live off the box at turn end (detectRepos → gitStatus/gitDiff → fsRead
@@ -7191,19 +9371,23 @@ export const WorkspaceCaptureFile = z.object({
7191
9371
  });
7192
9372
  export type WorkspaceCaptureFile = z.infer<typeof WorkspaceCaptureFile>;
7193
9373
 
7194
- // One repo discovered in the workspace. `diff` is `git diff HEAD` (combined
7195
- // staged+unstaged tracked changes vs HEAD the review diff); `status` is the
7196
- // full porcelain file list (drives the rail glyphs incl. untracked, which the
7197
- // HEAD diff omits). root "" = the workspace root repo.
9374
+ // One repo discovered in the workspace. `diff` is the working/index surface vs
9375
+ // HEAD; `branchDiff`, when available, is the complete current branch vs the
9376
+ // remote default branch and therefore retains committed agent work. `status`
9377
+ // is the full porcelain file list. root "" = the workspace root repo.
7198
9378
  export const WorkspaceCaptureRepo = z.object({
7199
9379
  root: z.string(),
7200
9380
  head: z.string().nullable(),
9381
+ // Exact HEAD commit object identity. null for unborn repositories; optional
9382
+ // for workspace captures written before commit identity was retained.
9383
+ headOid: z.string().nullable().optional(),
7201
9384
  detached: z.boolean().default(false),
7202
9385
  upstream: z.string().nullable(),
7203
9386
  ahead: z.number().int().nonnegative().default(0),
7204
9387
  behind: z.number().int().nonnegative().default(0),
7205
9388
  status: z.array(GitFileStatus),
7206
9389
  diff: z.array(GitFileDiff),
9390
+ branchDiff: z.array(GitFileDiff).optional(),
7207
9391
  });
7208
9392
  export type WorkspaceCaptureRepo = z.infer<typeof WorkspaceCaptureRepo>;
7209
9393
 
@@ -8768,27 +10952,45 @@ export function approvalIdentifier(value: unknown): string | null {
8768
10952
  return String(candidate);
8769
10953
  }
8770
10954
 
10955
+ function requireMessageTextOrAnnotations(
10956
+ value: { text: string; annotations: readonly unknown[] },
10957
+ ctx: z.RefinementCtx,
10958
+ ): void {
10959
+ if (value.text.length === 0 && value.annotations.length === 0) {
10960
+ ctx.addIssue({
10961
+ code: z.ZodIssueCode.custom,
10962
+ path: ["text"],
10963
+ message: "message text or annotations are required",
10964
+ });
10965
+ }
10966
+ }
10967
+
10968
+ export const SessionUserMessagePayload = z
10969
+ .object({
10970
+ text: z.string().default(""),
10971
+ annotations: SubmittedTimelineAnnotations.default([]),
10972
+ // System-level host context for this exact turn only. Persisted on the
10973
+ // turn for retry/recovery, never copied into the visible user message.
10974
+ turnInstructions: z.string().trim().min(1).max(32768).optional(),
10975
+ resources: z.array(ResourceRef).default([]),
10976
+ model: z.string().min(1).optional(),
10977
+ reasoningEffort: ReasoningEffort.optional(),
10978
+ latencyMode: LatencyMode.optional(),
10979
+ controlEtag: z.string().min(1).optional(),
10980
+ expectedDraftRevision: z.number().int().nonnegative().optional(),
10981
+ // Header-value rotation only. URL/name/tool settings are immutable after
10982
+ // session create; persisted events expose metadata, never header values.
10983
+ mcpCredentialUpdates: z.array(SessionMcpCredentialUpdateInput).optional(),
10984
+ })
10985
+ .strict()
10986
+ .superRefine(requireMessageTextOrAnnotations);
10987
+ export type SessionUserMessagePayload = z.infer<typeof SessionUserMessagePayload>;
10988
+
8771
10989
  export const ClientSessionEvent = z.discriminatedUnion("type", [
8772
10990
  z.object({
8773
10991
  type: z.literal("user.message"),
8774
10992
  clientEventId: SessionOperationKey.optional(),
8775
- payload: z
8776
- .object({
8777
- text: z.string().min(1),
8778
- // System-level host context for this exact turn only. Persisted on the
8779
- // turn for retry/recovery, never copied into the visible user message.
8780
- turnInstructions: z.string().trim().min(1).max(32768).optional(),
8781
- resources: z.array(ResourceRef).default([]),
8782
- model: z.string().min(1).optional(),
8783
- reasoningEffort: ReasoningEffort.optional(),
8784
- latencyMode: LatencyMode.optional(),
8785
- controlEtag: z.string().min(1).optional(),
8786
- expectedDraftRevision: z.number().int().nonnegative().optional(),
8787
- // Header-value rotation only. URL/name/tool settings are immutable after
8788
- // session create; persisted events expose metadata, never header values.
8789
- mcpCredentialUpdates: z.array(SessionMcpCredentialUpdateInput).optional(),
8790
- })
8791
- .strict(),
10993
+ payload: SessionUserMessagePayload,
8792
10994
  }),
8793
10995
  z.object({
8794
10996
  type: z.literal("user.approvalDecision"),
@@ -8812,7 +11014,8 @@ export type ClientSessionEvent = z.infer<typeof ClientSessionEvent>;
8812
11014
 
8813
11015
  export const SteerSessionMessageRequest = z
8814
11016
  .object({
8815
- text: z.string().min(1),
11017
+ text: z.string().default(""),
11018
+ annotations: SubmittedTimelineAnnotations.default([]),
8816
11019
  // Same per-turn system-level context as a queued user.message.
8817
11020
  turnInstructions: z.string().trim().min(1).max(32768).optional(),
8818
11021
  resources: z.array(ResourceRef).default([]),
@@ -8824,7 +11027,8 @@ export const SteerSessionMessageRequest = z
8824
11027
  expectedDraftRevision: z.number().int().nonnegative().optional(),
8825
11028
  mcpCredentialUpdates: z.array(SessionMcpCredentialUpdateInput).optional(),
8826
11029
  })
8827
- .strict();
11030
+ .strict()
11031
+ .superRefine(requireMessageTextOrAnnotations);
8828
11032
  export type SteerSessionMessageRequest = z.infer<typeof SteerSessionMessageRequest>;
8829
11033
 
8830
11034
  export const SteerSessionMessageResponse = z.object({
@@ -9043,19 +11247,21 @@ export type SessionCapabilities = z.infer<typeof SessionCapabilities>;
9043
11247
  // POST .../viewers — acquire a viewer holder. An omitted viewerId mints a fresh
9044
11248
  // one (returned in the response, to carry through heartbeats + detach).
9045
11249
  //
9046
- // `desktop` declares intent to attach the UN-REDACTED pixel plane (noVNC). ONLY
9047
- // that plane carries the consent gate (the un-redacted/shared acknowledgment). A
9048
- // terminal-only warm attach (`desktop:false`, the default) needs NO consent — a
9049
- // shell is interactive by nature and the gate is the scoped tunnel URL + stream
9050
- // token so it warms the box and mints the pty-ws terminal cell WITHOUT a 409.
9051
- // Omitted defaults to `false` so a terminal-only client never trips the gate.
9052
- export const AttachViewerRequest = z.object({
11250
+ // Each optional plane flag declares exactly which live capability is being
11251
+ // acquired. The holder itself is shared liveness; credentials are minted only
11252
+ // for explicitly requested planes. `desktop` alone carries the un-redacted pixel
11253
+ // consent gate, `terminal` carries terminal:attach, and `files` carries
11254
+ // files:write. For compatibility, an entirely omitted plane set retains the old
11255
+ // terminal-only meaning; new clients always send all three flags explicitly.
11256
+ export const AttachViewerRequest = /* @__PURE__ */ z.object({
9053
11257
  viewerId: z.string().uuid().optional(),
9054
11258
  desktop: z.boolean().optional(),
11259
+ terminal: z.boolean().optional(),
11260
+ files: z.boolean().optional(),
9055
11261
  });
9056
11262
  export type AttachViewerRequest = z.infer<typeof AttachViewerRequest>;
9057
11263
 
9058
- export const ViewerHolder = z.object({
11264
+ export const ViewerHolder = /* @__PURE__ */ z.object({
9059
11265
  viewerId: z.string().uuid(),
9060
11266
  sandboxGroupId: z.string().uuid(),
9061
11267
  liveness: z.enum(["cold", "warming", "warm", "draining"]),
@@ -9071,6 +11277,21 @@ export const ViewerHolder = z.object({
9071
11277
  });
9072
11278
  export type ViewerHolder = z.infer<typeof ViewerHolder>;
9073
11279
 
11280
+ /** Exact POST /viewers response. Keep the credential cells in the contracts
11281
+ * package so API and zero-runtime SDK mirrors cannot silently drift. */
11282
+ export const AttachViewerResponse = /* @__PURE__ */ ViewerHolder.extend({
11283
+ streamToken: z.string().nullable(),
11284
+ streamExpiresAt: z.string().nullable(),
11285
+ resolution: z.tuple([z.number().int().positive(), z.number().int().positive()]).nullable(),
11286
+ transport: z.enum(["vnc-ws", "relay-frames"]).nullable(),
11287
+ client: z.enum(["novnc", "frames"]).nullable(),
11288
+ terminalUrl: z.string().nullable(),
11289
+ terminalToken: z.string().nullable(),
11290
+ terminalExpiresAt: z.string().nullable(),
11291
+ terminalTransport: z.literal("pty-ws").nullable(),
11292
+ });
11293
+ export type AttachViewerResponse = z.infer<typeof AttachViewerResponse>;
11294
+
9074
11295
  // POST .../stream-capabilities/acknowledge — record the calling principal's
9075
11296
  // acknowledgment of the un-redacted pixel plane. Reuses the acknowledgment
9076
11297
  // machinery — no new endpoint
@@ -9080,7 +11301,7 @@ export type ViewerHolder = z.infer<typeof ViewerHolder>;
9080
11301
  // session): the un-redacted desktop path returns 409 shared_acknowledgment_required
9081
11302
  // until a shared box is acknowledged WITH the shared-exposure consent. For a
9082
11303
  // solo box `acknowledgeShared` is irrelevant (the un-redacted ack alone gates).
9083
- export const AcknowledgeStreamRequest = z.object({
11304
+ export const AcknowledgeStreamRequest = /* @__PURE__ */ z.object({
9084
11305
  // The principal accepts that the desktop pixel plane is un-redacted (can show
9085
11306
  // cloud creds the agent cat's into a terminal). Always true to record consent;
9086
11307
  // present for self-documentation + a future explicit withdraw.
@@ -9091,7 +11312,7 @@ export const AcknowledgeStreamRequest = z.object({
9091
11312
  });
9092
11313
  export type AcknowledgeStreamRequest = z.infer<typeof AcknowledgeStreamRequest>;
9093
11314
 
9094
- export const AcknowledgeStreamResponse = z.object({
11315
+ export const AcknowledgeStreamResponse = /* @__PURE__ */ z.object({
9095
11316
  acknowledged: z.boolean(),
9096
11317
  acknowledgedShared: z.boolean(),
9097
11318
  });
@@ -9099,12 +11320,12 @@ export type AcknowledgeStreamResponse = z.infer<typeof AcknowledgeStreamResponse
9099
11320
 
9100
11321
  // POST .../viewers/:viewerId/heartbeat — refresh the holder TTL. Epoch-fenced:
9101
11322
  // a stale-epoch beat (a box re-established under a newer epoch) is rejected.
9102
- export const ViewerHeartbeatRequest = z.object({
11323
+ export const ViewerHeartbeatRequest = /* @__PURE__ */ z.object({
9103
11324
  leaseEpoch: z.number().int().nonnegative(),
9104
11325
  });
9105
11326
  export type ViewerHeartbeatRequest = z.infer<typeof ViewerHeartbeatRequest>;
9106
11327
 
9107
- export const ViewerHeartbeatResponse = z.object({
11328
+ export const ViewerHeartbeatResponse = /* @__PURE__ */ z.object({
9108
11329
  // false ⇒ the holder was reaped or the epoch is stale; the client re-attaches.
9109
11330
  alive: z.boolean(),
9110
11331
  });
@@ -9267,9 +11488,39 @@ export type ListEnrollmentsResponse = z.infer<typeof ListEnrollmentsResponse>;
9267
11488
 
9268
11489
  export const RevokeEnrollmentResponse = z.object({
9269
11490
  revoked: z.boolean(),
11491
+ outcome: z.enum(["removed", "already_removed", "blocked"]),
11492
+ enrollmentId: z.string().uuid(),
11493
+ machineName: z.string().nullable(),
11494
+ lastSeenAt: z.string().datetime({ offset: true }).nullable(),
11495
+ revokedAt: z.string().datetime({ offset: true }).nullable(),
11496
+ code: z
11497
+ .enum([
11498
+ "active_route",
11499
+ "active_commands",
11500
+ "machine_home",
11501
+ "active_lease",
11502
+ "recovery_pending",
11503
+ "not_selfhosted",
11504
+ ])
11505
+ .nullable(),
11506
+ message: z.string(),
11507
+ action: z.string(),
11508
+ dependentSessions: z.array(
11509
+ z.object({
11510
+ id: z.string().uuid(),
11511
+ title: z.string().nullable(),
11512
+ }),
11513
+ ),
9270
11514
  });
9271
11515
  export type RevokeEnrollmentResponse = z.infer<typeof RevokeEnrollmentResponse>;
9272
11516
 
11517
+ /** POST /v1/workspaces/:workspaceId/enrollments/:id/revoke body. */
11518
+ export const RemoveEnrollmentRequest = z.object({
11519
+ expectedUpdatedAt: z.string().datetime({ offset: true }).optional(),
11520
+ idempotencyKey: z.string().trim().min(1).max(200).optional(),
11521
+ });
11522
+ export type RemoveEnrollmentRequest = z.infer<typeof RemoveEnrollmentRequest>;
11523
+
9273
11524
  // =============================================================================
9274
11525
  // Enrollment UX (self-hosted enrollment UX, design 11): the click-Grant approve
9275
11526
  // page lookup/deny + the headless enroll-token mint/exchange. These sit beside the
@@ -9615,9 +11866,10 @@ export const TurnExecutionReasoningSourceV1 =
9615
11866
  );
9616
11867
  export type TurnExecutionReasoningSourceV1 = z.infer<typeof TurnExecutionReasoningSourceV1>;
9617
11868
 
9618
- export const TurnExecutionLatencyModeSourceV1 = /* @__PURE__ */ defineModelContractSchema(() =>
9619
- z.enum(["explicit", "session", "deployment", "continuation"]),
9620
- );
11869
+ export const TurnExecutionLatencyModeSourceV1 =
11870
+ /* @__PURE__ */ defineModelContractSchema(() =>
11871
+ z.enum(["explicit", "session", "deployment", "continuation"]),
11872
+ );
9621
11873
  export type TurnExecutionLatencyModeSourceV1 = z.infer<typeof TurnExecutionLatencyModeSourceV1>;
9622
11874
 
9623
11875
  /**
@@ -9920,7 +12172,7 @@ export type WorkspaceModelCatalogResponse = z.infer<typeof WorkspaceModelCatalog
9920
12172
  * that rollout boundary. Mutating clients send this value in
9921
12173
  * `x-opengeni-api-contract`; the API rejects any other value before routing.
9922
12174
  */
9923
- export const OPENGENI_API_CONTRACT_REVISION = "2026-07-workspace-artifacts-v1" as const;
12175
+ export const OPENGENI_API_CONTRACT_REVISION = "2026-08-social-provider-tools-v1" as const;
9924
12176
  export const OPENGENI_API_CONTRACT_HEADER = "x-opengeni-api-contract" as const;
9925
12177
  /** Bounded request/response identifier shared by browser, ingress, and API diagnostics. */
9926
12178
  export const OPENGENI_CORRELATION_HEADER = "x-opengeni-correlation-id" as const;
@@ -10082,8 +12334,9 @@ export function evaluateWorkspaceModelPolicy(
10082
12334
  }
10083
12335
 
10084
12336
  export * from "./codex-fleet-policy";
10085
- export * from "./secret-redaction";
10086
12337
  export * from "./workspace-instruction-policies";
12338
+ export * from "./company-profile";
12339
+ export * from "./workspace-learning-policy";
10087
12340
  export * from "./workspace-state";
10088
12341
  export * from "./preference-registry";
10089
12342
  export * from "./scoped-knowledge";