@opengeni/contracts 1.0.2-canary.37191796234001 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/atlassian.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  AtlassianSyncCadence,
18
18
  SaveAtlassianSourcesRequest,
19
19
  atlassianScopesAllowRead
20
- } from "./chunk-SNV3UUWG.js";
20
+ } from "./chunk-X7ETVO4P.js";
21
21
  import "./chunk-5IXYF6XN.js";
22
22
  import "./chunk-NRMCVHAU.js";
23
23
  import "./chunk-WYBDERIY.js";
@@ -28,7 +28,7 @@ import "./chunk-NVJMJWLL.js";
28
28
  import "./chunk-SIOU2K4U.js";
29
29
  import "./chunk-YRKRZ6OF.js";
30
30
  import "./chunk-2VORLN2R.js";
31
- import "./chunk-RB6CPS5K.js";
31
+ import "./chunk-FZ6BXQHL.js";
32
32
  import "./chunk-GRG7PHWQ.js";
33
33
  import "./chunk-YRXAWWCU.js";
34
34
  import "./chunk-2ACYHZFB.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ConnectionKind,
3
3
  SessionTenancyVisibility
4
- } from "./chunk-SNV3UUWG.js";
4
+ } from "./chunk-X7ETVO4P.js";
5
5
 
6
6
  // src/connection-authority.ts
7
7
  import { z } from "zod";
@@ -183,4 +183,4 @@ export {
183
183
  ConnectionUseAuditFact,
184
184
  ConnectionUseAuthorizationResult
185
185
  };
186
- //# sourceMappingURL=chunk-LNTTRWSJ.js.map
186
+ //# sourceMappingURL=chunk-46KLD2UH.js.map
@@ -87,7 +87,7 @@ function buildOpenGeniSlackBotManifest(publicBaseUrl, options = {}) {
87
87
  const slashCommand = normalizedSlackCommand(options.slashCommand);
88
88
  const shortcutName = normalizedSlackManifestText(
89
89
  options.shortcutName,
90
- "Open in OpenGeni",
90
+ "Open in Opengeni",
91
91
  "shortcut name",
92
92
  35
93
93
  );
@@ -103,7 +103,7 @@ function buildOpenGeniSlackBotManifest(publicBaseUrl, options = {}) {
103
103
  slash_commands: [
104
104
  {
105
105
  command: slashCommand,
106
- description: "Start an OpenGeni task in this channel",
106
+ description: "Start an Opengeni task in this channel",
107
107
  should_escape: false,
108
108
  url: `${baseUrl}/v1/integrations/slack/commands`
109
109
  }
@@ -111,7 +111,7 @@ function buildOpenGeniSlackBotManifest(publicBaseUrl, options = {}) {
111
111
  shortcuts: [
112
112
  {
113
113
  callback_id: "opengeni_message",
114
- description: "Start an OpenGeni task from this Slack message",
114
+ description: "Start an Opengeni task from this Slack message",
115
115
  name: shortcutName,
116
116
  type: "message"
117
117
  }
@@ -195,4 +195,4 @@ export {
195
195
  hasOpenGeniSlackReactionScope,
196
196
  evaluateOpenGeniSlackBotScopes
197
197
  };
198
- //# sourceMappingURL=chunk-RB6CPS5K.js.map
198
+ //# sourceMappingURL=chunk-FZ6BXQHL.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/slack-bot-scopes.ts"],"sourcesContent":["import { OPENGENI_SLACK_REST_USER_SCOPES } from \"./slack-rest-mcp\";\n\nexport const OPENGENI_SLACK_BOT_REQUIRED_SCOPES = [\n \"app_mentions:read\",\n \"canvases:read\",\n \"channels:history\",\n \"channels:read\",\n \"chat:write\",\n \"commands\",\n \"files:read\",\n \"groups:history\",\n \"groups:read\",\n \"im:history\",\n \"im:read\",\n \"im:write\",\n \"mpim:history\",\n \"mpim:read\",\n \"users:read\",\n] as const;\n\n/** Read-only scope needed only for the optional emoji-reaction summon surface. */\nexport const OPENGENI_SLACK_REACTION_REQUIRED_SCOPE = \"reactions:read\" as const;\n\n/** Optional grant for explicit retained-file delivery to a task's Slack thread. */\nexport const OPENGENI_SLACK_FILE_UPLOAD_REQUIRED_SCOPE = \"files:write\" as const;\n\n/**\n * Bot-token search scopes for Slack's Real-time Search API\n * (`assistant.search.context`). Slack accepts these as BOT scopes, so\n * workspace-wide public search runs under the bot identity and never needs a\n * human proxy token. Private-channel, DM, and MPIM search remain user-token\n * only and belong exclusively to the personal hosted-MCP grant.\n */\nexport const OPENGENI_SLACK_BOT_SEARCH_SCOPES = [\n \"search:read.public\",\n \"search:read.files\",\n \"search:read.users\",\n] as const;\n\n/**\n * Scopes requested by the managed and generated self-hosted manifests.\n *\n * `reactions:read`, `files:write`, and the bot search scopes are not part of the\n * base eligibility contract: legacy installations may continue using existing\n * Slack interactions and tools while the reaction setting stays disabled, bot\n * search and file delivery stay unavailable, and the tools ask an admin to reinstall.\n */\nexport const OPENGENI_SLACK_BOT_REQUESTED_SCOPES = [\n ...OPENGENI_SLACK_BOT_REQUIRED_SCOPES,\n OPENGENI_SLACK_REACTION_REQUIRED_SCOPE,\n OPENGENI_SLACK_FILE_UPLOAD_REQUIRED_SCOPE,\n] as const;\n\nexport function openGeniSlackBotRequestedScopes(mode: \"limited\" | \"full\" = \"limited\"): string[] {\n return [\n ...OPENGENI_SLACK_BOT_REQUESTED_SCOPES,\n ...(mode === \"full\" ? OPENGENI_SLACK_BOT_SEARCH_SCOPES : []),\n ];\n}\n\nexport const OPENGENI_SLACK_BOT_EVENTS = [\n \"app_home_opened\",\n \"app_mention\",\n \"message.channels\",\n \"message.groups\",\n \"message.im\",\n \"message.mpim\",\n \"reaction_added\",\n] as const;\n\n/** User grants required by the reviewed Slack API MCP tools. */\nexport const OPENGENI_SLACK_MCP_USER_SCOPES = OPENGENI_SLACK_REST_USER_SCOPES;\n\nexport const OPENGENI_MANAGED_PUBLIC_BASE_URL = \"https://app.opengeni.ai\" as const;\n\nexport type OpenGeniSlackBotManifestOptions = Readonly<{\n appName?: string;\n botDisplayName?: string;\n slashCommand?: string;\n shortcutName?: string;\n accessMode?: \"limited\" | \"full\";\n}>;\n\nfunction normalizedSlackManifestText(\n value: string | undefined,\n fallback: string,\n label: string,\n maxLength: number,\n): string {\n const normalized = value?.trim() || fallback;\n if (normalized.length > maxLength || /[\\r\\n\\0]/u.test(normalized)) {\n throw new Error(`Slack bot manifest ${label} must be at most ${maxLength} plain characters`);\n }\n return normalized;\n}\n\nfunction normalizedSlackCommand(value: string | undefined): string {\n const command = value?.trim() || \"/opengeni\";\n if (!/^\\/[a-z0-9_-]{1,31}$/u.test(command)) {\n throw new Error(\n \"Slack bot manifest slash command must start with / and contain at most 31 lowercase letters, digits, hyphens, or underscores\",\n );\n }\n return command;\n}\n\nfunction normalizedSlackManifestBaseUrl(publicBaseUrl: string): string {\n const parsed = new URL(publicBaseUrl);\n if (parsed.protocol !== \"https:\" || parsed.username || parsed.password) {\n throw new Error(\"Slack bot manifest public base URL must be credential-free HTTPS\");\n }\n parsed.hash = \"\";\n parsed.search = \"\";\n parsed.pathname = parsed.pathname.replace(/\\/+$/, \"\");\n return parsed.toString().replace(/\\/$/, \"\");\n}\n\n/** Canonical managed/self-hosted Slack app manifest. Slack accepts JSON manifests. */\nexport function buildOpenGeniSlackBotManifest(\n publicBaseUrl: string,\n options: OpenGeniSlackBotManifestOptions = {},\n) {\n const baseUrl = normalizedSlackManifestBaseUrl(publicBaseUrl);\n const appName = normalizedSlackManifestText(options.appName, \"OpenGeni\", \"app name\", 35);\n const botDisplayName = normalizedSlackManifestText(\n options.botDisplayName,\n \"OpenGeni\",\n \"bot display name\",\n 80,\n );\n const slashCommand = normalizedSlackCommand(options.slashCommand);\n const shortcutName = normalizedSlackManifestText(\n options.shortcutName,\n \"Open in OpenGeni\",\n \"shortcut name\",\n 35,\n );\n return {\n display_information: { name: appName },\n features: {\n app_home: {\n home_tab_enabled: true,\n messages_tab_enabled: true,\n messages_tab_read_only_enabled: false,\n },\n bot_user: { display_name: botDisplayName, always_online: false },\n slash_commands: [\n {\n command: slashCommand,\n description: \"Start an OpenGeni task in this channel\",\n should_escape: false,\n url: `${baseUrl}/v1/integrations/slack/commands`,\n },\n ],\n shortcuts: [\n {\n callback_id: \"opengeni_message\",\n description: \"Start an OpenGeni task from this Slack message\",\n name: shortcutName,\n type: \"message\",\n },\n ],\n },\n oauth_config: {\n redirect_urls: [\n `${baseUrl}/v1/integrations/oauth/callback`,\n `${baseUrl}/v1/integrations/slack/callback`,\n ],\n scopes: {\n bot: openGeniSlackBotRequestedScopes(options.accessMode),\n user: [...OPENGENI_SLACK_MCP_USER_SCOPES],\n },\n },\n settings: {\n event_subscriptions: {\n bot_events: [...OPENGENI_SLACK_BOT_EVENTS],\n request_url: `${baseUrl}/v1/integrations/slack/events`,\n },\n interactivity: {\n is_enabled: true,\n request_url: `${baseUrl}/v1/integrations/slack/interactions`,\n },\n is_mcp_enabled: true,\n org_deploy_enabled: false,\n socket_mode_enabled: false,\n token_rotation_enabled: false,\n },\n } as const;\n}\n\n/**\n * Optional bot grants used by the shipped read/identity and task-file-delivery\n * surfaces. Every other unrequired scope fails closed, including unknown future\n * Slack scopes, so verification, core routing, and UI eligibility cannot drift.\n */\nexport const OPENGENI_SLACK_BOT_SAFE_OPTIONAL_SCOPES = [\n \"team:read\",\n OPENGENI_SLACK_REACTION_REQUIRED_SCOPE,\n OPENGENI_SLACK_FILE_UPLOAD_REQUIRED_SCOPE,\n ...OPENGENI_SLACK_BOT_SEARCH_SCOPES,\n] as const;\n\nexport function hasOpenGeniSlackFileUploadScope(grantedScopes: readonly string[]): boolean {\n return grantedScopes.includes(OPENGENI_SLACK_FILE_UPLOAD_REQUIRED_SCOPE);\n}\n\nexport function hasOpenGeniSlackBotSearchScopes(grantedScopes: readonly string[]): boolean {\n return OPENGENI_SLACK_BOT_SEARCH_SCOPES.every((scope) => grantedScopes.includes(scope));\n}\n\n/** @deprecated Use evaluateOpenGeniSlackBotScopes; an allowlist is the policy. */\nexport const OPENGENI_SLACK_BOT_FORBIDDEN_SCOPES = [\"channels:join\", \"chat:write.public\"] as const;\n\nexport type OpenGeniSlackBotScopePolicy = {\n accepted: boolean;\n missingRequired: string[];\n unsupported: string[];\n};\n\nfunction isOpenGeniSlackBotScopeAllowed(scope: string): boolean {\n return (\n (OPENGENI_SLACK_BOT_REQUIRED_SCOPES as readonly string[]).includes(scope) ||\n (OPENGENI_SLACK_BOT_SAFE_OPTIONAL_SCOPES as readonly string[]).includes(scope)\n );\n}\n\nexport function areOpenGeniSlackBotScopesAccepted(grantedScopes: readonly string[]): boolean {\n return (\n OPENGENI_SLACK_BOT_REQUIRED_SCOPES.every((scope) => grantedScopes.includes(scope)) &&\n grantedScopes.every(isOpenGeniSlackBotScopeAllowed)\n );\n}\n\nexport function hasOpenGeniSlackReactionScope(grantedScopes: readonly string[]): boolean {\n return grantedScopes.includes(OPENGENI_SLACK_REACTION_REQUIRED_SCOPE);\n}\n\nexport function evaluateOpenGeniSlackBotScopes(\n grantedScopes: readonly string[],\n): OpenGeniSlackBotScopePolicy {\n const granted = new Set(grantedScopes);\n const missingRequired = OPENGENI_SLACK_BOT_REQUIRED_SCOPES.filter((scope) => !granted.has(scope));\n const unsupported = [...granted].filter((scope) => !isOpenGeniSlackBotScopeAllowed(scope)).sort();\n return {\n accepted: areOpenGeniSlackBotScopesAccepted(grantedScopes),\n missingRequired,\n unsupported,\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/slack-bot-scopes.ts"],"sourcesContent":["import { OPENGENI_SLACK_REST_USER_SCOPES } from \"./slack-rest-mcp\";\n\nexport const OPENGENI_SLACK_BOT_REQUIRED_SCOPES = [\n \"app_mentions:read\",\n \"canvases:read\",\n \"channels:history\",\n \"channels:read\",\n \"chat:write\",\n \"commands\",\n \"files:read\",\n \"groups:history\",\n \"groups:read\",\n \"im:history\",\n \"im:read\",\n \"im:write\",\n \"mpim:history\",\n \"mpim:read\",\n \"users:read\",\n] as const;\n\n/** Read-only scope needed only for the optional emoji-reaction summon surface. */\nexport const OPENGENI_SLACK_REACTION_REQUIRED_SCOPE = \"reactions:read\" as const;\n\n/** Optional grant for explicit retained-file delivery to a task's Slack thread. */\nexport const OPENGENI_SLACK_FILE_UPLOAD_REQUIRED_SCOPE = \"files:write\" as const;\n\n/**\n * Bot-token search scopes for Slack's Real-time Search API\n * (`assistant.search.context`). Slack accepts these as BOT scopes, so\n * workspace-wide public search runs under the bot identity and never needs a\n * human proxy token. Private-channel, DM, and MPIM search remain user-token\n * only and belong exclusively to the personal hosted-MCP grant.\n */\nexport const OPENGENI_SLACK_BOT_SEARCH_SCOPES = [\n \"search:read.public\",\n \"search:read.files\",\n \"search:read.users\",\n] as const;\n\n/**\n * Scopes requested by the managed and generated self-hosted manifests.\n *\n * `reactions:read`, `files:write`, and the bot search scopes are not part of the\n * base eligibility contract: legacy installations may continue using existing\n * Slack interactions and tools while the reaction setting stays disabled, bot\n * search and file delivery stay unavailable, and the tools ask an admin to reinstall.\n */\nexport const OPENGENI_SLACK_BOT_REQUESTED_SCOPES = [\n ...OPENGENI_SLACK_BOT_REQUIRED_SCOPES,\n OPENGENI_SLACK_REACTION_REQUIRED_SCOPE,\n OPENGENI_SLACK_FILE_UPLOAD_REQUIRED_SCOPE,\n] as const;\n\nexport function openGeniSlackBotRequestedScopes(mode: \"limited\" | \"full\" = \"limited\"): string[] {\n return [\n ...OPENGENI_SLACK_BOT_REQUESTED_SCOPES,\n ...(mode === \"full\" ? OPENGENI_SLACK_BOT_SEARCH_SCOPES : []),\n ];\n}\n\nexport const OPENGENI_SLACK_BOT_EVENTS = [\n \"app_home_opened\",\n \"app_mention\",\n \"message.channels\",\n \"message.groups\",\n \"message.im\",\n \"message.mpim\",\n \"reaction_added\",\n] as const;\n\n/** User grants required by the reviewed Slack API MCP tools. */\nexport const OPENGENI_SLACK_MCP_USER_SCOPES = OPENGENI_SLACK_REST_USER_SCOPES;\n\nexport const OPENGENI_MANAGED_PUBLIC_BASE_URL = \"https://app.opengeni.ai\" as const;\n\nexport type OpenGeniSlackBotManifestOptions = Readonly<{\n appName?: string;\n botDisplayName?: string;\n slashCommand?: string;\n shortcutName?: string;\n accessMode?: \"limited\" | \"full\";\n}>;\n\nfunction normalizedSlackManifestText(\n value: string | undefined,\n fallback: string,\n label: string,\n maxLength: number,\n): string {\n const normalized = value?.trim() || fallback;\n if (normalized.length > maxLength || /[\\r\\n\\0]/u.test(normalized)) {\n throw new Error(`Slack bot manifest ${label} must be at most ${maxLength} plain characters`);\n }\n return normalized;\n}\n\nfunction normalizedSlackCommand(value: string | undefined): string {\n const command = value?.trim() || \"/opengeni\";\n if (!/^\\/[a-z0-9_-]{1,31}$/u.test(command)) {\n throw new Error(\n \"Slack bot manifest slash command must start with / and contain at most 31 lowercase letters, digits, hyphens, or underscores\",\n );\n }\n return command;\n}\n\nfunction normalizedSlackManifestBaseUrl(publicBaseUrl: string): string {\n const parsed = new URL(publicBaseUrl);\n if (parsed.protocol !== \"https:\" || parsed.username || parsed.password) {\n throw new Error(\"Slack bot manifest public base URL must be credential-free HTTPS\");\n }\n parsed.hash = \"\";\n parsed.search = \"\";\n parsed.pathname = parsed.pathname.replace(/\\/+$/, \"\");\n return parsed.toString().replace(/\\/$/, \"\");\n}\n\n/** Canonical managed/self-hosted Slack app manifest. Slack accepts JSON manifests. */\nexport function buildOpenGeniSlackBotManifest(\n publicBaseUrl: string,\n options: OpenGeniSlackBotManifestOptions = {},\n) {\n const baseUrl = normalizedSlackManifestBaseUrl(publicBaseUrl);\n const appName = normalizedSlackManifestText(options.appName, \"OpenGeni\", \"app name\", 35);\n const botDisplayName = normalizedSlackManifestText(\n options.botDisplayName,\n \"OpenGeni\",\n \"bot display name\",\n 80,\n );\n const slashCommand = normalizedSlackCommand(options.slashCommand);\n const shortcutName = normalizedSlackManifestText(\n options.shortcutName,\n \"Open in Opengeni\",\n \"shortcut name\",\n 35,\n );\n return {\n display_information: { name: appName },\n features: {\n app_home: {\n home_tab_enabled: true,\n messages_tab_enabled: true,\n messages_tab_read_only_enabled: false,\n },\n bot_user: { display_name: botDisplayName, always_online: false },\n slash_commands: [\n {\n command: slashCommand,\n description: \"Start an Opengeni task in this channel\",\n should_escape: false,\n url: `${baseUrl}/v1/integrations/slack/commands`,\n },\n ],\n shortcuts: [\n {\n callback_id: \"opengeni_message\",\n description: \"Start an Opengeni task from this Slack message\",\n name: shortcutName,\n type: \"message\",\n },\n ],\n },\n oauth_config: {\n redirect_urls: [\n `${baseUrl}/v1/integrations/oauth/callback`,\n `${baseUrl}/v1/integrations/slack/callback`,\n ],\n scopes: {\n bot: openGeniSlackBotRequestedScopes(options.accessMode),\n user: [...OPENGENI_SLACK_MCP_USER_SCOPES],\n },\n },\n settings: {\n event_subscriptions: {\n bot_events: [...OPENGENI_SLACK_BOT_EVENTS],\n request_url: `${baseUrl}/v1/integrations/slack/events`,\n },\n interactivity: {\n is_enabled: true,\n request_url: `${baseUrl}/v1/integrations/slack/interactions`,\n },\n is_mcp_enabled: true,\n org_deploy_enabled: false,\n socket_mode_enabled: false,\n token_rotation_enabled: false,\n },\n } as const;\n}\n\n/**\n * Optional bot grants used by the shipped read/identity and task-file-delivery\n * surfaces. Every other unrequired scope fails closed, including unknown future\n * Slack scopes, so verification, core routing, and UI eligibility cannot drift.\n */\nexport const OPENGENI_SLACK_BOT_SAFE_OPTIONAL_SCOPES = [\n \"team:read\",\n OPENGENI_SLACK_REACTION_REQUIRED_SCOPE,\n OPENGENI_SLACK_FILE_UPLOAD_REQUIRED_SCOPE,\n ...OPENGENI_SLACK_BOT_SEARCH_SCOPES,\n] as const;\n\nexport function hasOpenGeniSlackFileUploadScope(grantedScopes: readonly string[]): boolean {\n return grantedScopes.includes(OPENGENI_SLACK_FILE_UPLOAD_REQUIRED_SCOPE);\n}\n\nexport function hasOpenGeniSlackBotSearchScopes(grantedScopes: readonly string[]): boolean {\n return OPENGENI_SLACK_BOT_SEARCH_SCOPES.every((scope) => grantedScopes.includes(scope));\n}\n\n/** @deprecated Use evaluateOpenGeniSlackBotScopes; an allowlist is the policy. */\nexport const OPENGENI_SLACK_BOT_FORBIDDEN_SCOPES = [\"channels:join\", \"chat:write.public\"] as const;\n\nexport type OpenGeniSlackBotScopePolicy = {\n accepted: boolean;\n missingRequired: string[];\n unsupported: string[];\n};\n\nfunction isOpenGeniSlackBotScopeAllowed(scope: string): boolean {\n return (\n (OPENGENI_SLACK_BOT_REQUIRED_SCOPES as readonly string[]).includes(scope) ||\n (OPENGENI_SLACK_BOT_SAFE_OPTIONAL_SCOPES as readonly string[]).includes(scope)\n );\n}\n\nexport function areOpenGeniSlackBotScopesAccepted(grantedScopes: readonly string[]): boolean {\n return (\n OPENGENI_SLACK_BOT_REQUIRED_SCOPES.every((scope) => grantedScopes.includes(scope)) &&\n grantedScopes.every(isOpenGeniSlackBotScopeAllowed)\n );\n}\n\nexport function hasOpenGeniSlackReactionScope(grantedScopes: readonly string[]): boolean {\n return grantedScopes.includes(OPENGENI_SLACK_REACTION_REQUIRED_SCOPE);\n}\n\nexport function evaluateOpenGeniSlackBotScopes(\n grantedScopes: readonly string[],\n): OpenGeniSlackBotScopePolicy {\n const granted = new Set(grantedScopes);\n const missingRequired = OPENGENI_SLACK_BOT_REQUIRED_SCOPES.filter((scope) => !granted.has(scope));\n const unsupported = [...granted].filter((scope) => !isOpenGeniSlackBotScopeAllowed(scope)).sort();\n return {\n accepted: areOpenGeniSlackBotScopesAccepted(grantedScopes),\n missingRequired,\n unsupported,\n };\n}\n"],"mappings":"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","names":[]}
@@ -13567,8 +13567,7 @@ var UpdateWorkspaceSettingsRequest = z57.object({
13567
13567
  slackReactionSummon: WorkspaceSlackReactionSummonSettings.optional(),
13568
13568
  slackOrchestrationNotices: WorkspaceSlackOrchestrationNoticeSettings.optional(),
13569
13569
  defaultSandboxImage: WorkspaceDefaultSandboxImage.nullable().optional(),
13570
- // Agent defaults for new sessions; null clears them. Requires the agent
13571
- // configuration admission switch.
13570
+ // Agent defaults for new sessions; null clears them.
13572
13571
  sessionAgentDefaults: WorkspaceAgentDefaults.nullable().optional()
13573
13572
  }).passthrough();
13574
13573
  var SetWorkspaceDefaultRigRequest = z57.object({
@@ -13669,7 +13668,7 @@ var ServiceTurnInitiatorContext = TurnInitiatorContext.superRefine((value, ctx)
13669
13668
  ctx.addIssue({
13670
13669
  code: z57.ZodIssueCode.custom,
13671
13670
  path: [key],
13672
- message: `${key} is reserved OpenGeni initiator context`
13671
+ message: `${key} is reserved Opengeni initiator context`
13673
13672
  });
13674
13673
  }
13675
13674
  }
@@ -17559,7 +17558,8 @@ function renderSessionSystemUpdateBatch(updates, options = {}) {
17559
17558
  ...update.createdAt ? { createdAt: formatModelContextTimestamp(update.createdAt) } : {},
17560
17559
  summary: update.summary,
17561
17560
  payload: update.payload,
17562
- lineage: update.lineage
17561
+ lineage: update.lineage,
17562
+ ...options.selectionNotes?.[update.id] ? { selectionNote: options.selectionNotes[update.id] } : {}
17563
17563
  }))
17564
17564
  })
17565
17565
  ].join("\n");
@@ -22796,7 +22796,7 @@ var CreateSessionRequest = /* @__PURE__ */ defineSkillContractSchema(
22796
22796
  firstPartyMcpTools: z57.array(FirstPartyMcpToolName).optional(),
22797
22797
  // One agent configuration: capabilities, identity, instructions alias and
22798
22798
  // renderer. Omission keeps today's behavior (or inherits a configured
22799
- // parent). Children may only narrow. Behind the admission switch.
22799
+ // parent). Children may only narrow.
22800
22800
  agent: AgentConfigRequest.optional(),
22801
22801
  // Third-party MCP servers attached only to this session. For an agent-created
22802
22802
  // child, omission snapshots its trusted immediate parent's server definitions,
@@ -26541,4 +26541,4 @@ export {
26541
26541
  AtlassianDisconnectRequest,
26542
26542
  atlassianScopesAllowRead
26543
26543
  };
26544
- //# sourceMappingURL=chunk-SNV3UUWG.js.map
26544
+ //# sourceMappingURL=chunk-X7ETVO4P.js.map