@opengeni/core 0.16.3 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2356,6 +2356,19 @@ async function requireCatalogItem(db, workspaceId, settings, capabilityId) {
2356
2356
  return item;
2357
2357
  }
2358
2358
  function packCatalogItem(pack, source) {
2359
+ const customMetadata = { ...pack.metadata };
2360
+ for (const key of [
2361
+ "packId",
2362
+ "version",
2363
+ "connectors",
2364
+ "knowledge",
2365
+ "scheduledTaskTemplates",
2366
+ "sandboxImage",
2367
+ "sandboxProviderImages",
2368
+ "skills"
2369
+ ]) {
2370
+ delete customMetadata[key];
2371
+ }
2359
2372
  return CapabilityCatalogItem.parse({
2360
2373
  id: `pack:${pack.id}`,
2361
2374
  kind: "pack",
@@ -2370,6 +2383,7 @@ function packCatalogItem(pack, source) {
2370
2383
  notes: "Enables role-scoped tools, connectors, knowledge, and scheduled-task templates."
2371
2384
  },
2372
2385
  metadata: {
2386
+ ...customMetadata,
2373
2387
  packId: pack.id,
2374
2388
  version: pack.version,
2375
2389
  connectors: pack.connectors,
@@ -2377,8 +2391,8 @@ function packCatalogItem(pack, source) {
2377
2391
  scheduledTaskTemplates: pack.scheduledTaskTemplates,
2378
2392
  // Runtime composition surface only: skill names, never file content.
2379
2393
  ...pack.sandboxImage ? { sandboxImage: pack.sandboxImage } : {},
2380
- ...pack.skills.length > 0 ? { skills: pack.skills.map((skill) => skill.name) } : {},
2381
- ...pack.metadata
2394
+ ...pack.sandboxProviderImages ? { sandboxProviderImages: pack.sandboxProviderImages } : {},
2395
+ ...pack.skills.length > 0 ? { skills: pack.skills.map((skill) => skill.name) } : {}
2382
2396
  }
2383
2397
  });
2384
2398
  }
@@ -3151,6 +3165,158 @@ async function listRigChangesForApi(deps, workspaceId, rigId, limit) {
3151
3165
  return await listRigChanges(deps.db, workspaceId, rigId, limit);
3152
3166
  }
3153
3167
 
3168
+ // src/domain/personal-connection-delegations.ts
3169
+ import {
3170
+ getSessionTurnPersonalConnectionDelegations,
3171
+ getWorkspaceGrant as getWorkspaceGrant2,
3172
+ listConnectionsMetadata as listConnectionsMetadata2
3173
+ } from "@opengeni/db";
3174
+ function directPersonalConnectionSubjectId(turn) {
3175
+ if (turn.source !== "user" && turn.source !== "api" || turn.initiator.kind !== "subject") {
3176
+ return void 0;
3177
+ }
3178
+ return ["via", "viaTruncated", "provenanceError", "backfill"].some(
3179
+ (key) => Object.prototype.hasOwnProperty.call(turn.initiatorContext, key)
3180
+ ) ? void 0 : turn.initiator.subjectId;
3181
+ }
3182
+ function personalConnectionDelegationSourceForGrant(grant) {
3183
+ const callerSessionId = grant.metadata?.["sessionId"];
3184
+ const callerTurnId = grant.metadata?.["turnId"];
3185
+ if (typeof callerSessionId === "string" && typeof callerTurnId === "string") {
3186
+ return { kind: "turn", sessionId: callerSessionId, turnId: callerTurnId };
3187
+ }
3188
+ if (grant.principalKind === "agent_attempt" || grant.principalKind === "service" || grant.serviceInitiator) {
3189
+ return { kind: "none" };
3190
+ }
3191
+ return { kind: "subject", subjectId: grant.subjectId };
3192
+ }
3193
+ function selectedPersonalConnectionServers(settings, tools) {
3194
+ const selected = new Set(tools.map((tool) => tool.id));
3195
+ return settings.mcpServers.filter(
3196
+ (server) => selected.has(server.id) && server.connectionRef?.subjectScope === "subject"
3197
+ );
3198
+ }
3199
+ function canonicalPersonalConnections(connections) {
3200
+ return [...connections].sort((left, right) => {
3201
+ const active = Number(right.status === "active") - Number(left.status === "active");
3202
+ if (active !== 0) return active;
3203
+ const updated = Date.parse(right.updatedAt) - Date.parse(left.updatedAt);
3204
+ if (updated !== 0) return updated;
3205
+ const created = Date.parse(right.createdAt) - Date.parse(left.createdAt);
3206
+ if (created !== 0) return created;
3207
+ return right.id.localeCompare(left.id);
3208
+ });
3209
+ }
3210
+ function sameProviderDomain(left, right) {
3211
+ return left.toLowerCase() === right.toLowerCase();
3212
+ }
3213
+ function personalConnectionDelegationsFromVisibleConnections(input) {
3214
+ const delegations = [];
3215
+ const connections = canonicalPersonalConnections(input.connections);
3216
+ for (const server of input.servers) {
3217
+ const ref = server.connectionRef;
3218
+ if (!ref || ref.subjectScope !== "subject") continue;
3219
+ const connection = connections.find(
3220
+ (candidate) => candidate.subjectId === input.subjectId && candidate.status === "active" && sameProviderDomain(candidate.providerDomain, ref.providerDomain) && (!ref.kind || candidate.kind === ref.kind) && (!ref.connectionId || candidate.id === ref.connectionId)
3221
+ );
3222
+ if (!connection) continue;
3223
+ delegations.push({
3224
+ serverId: server.id,
3225
+ connectionId: connection.id,
3226
+ ownerSubjectId: input.subjectId,
3227
+ providerDomain: connection.providerDomain,
3228
+ kind: connection.kind
3229
+ });
3230
+ }
3231
+ return delegations;
3232
+ }
3233
+ function personalConnectionDelegationsFromParent(input) {
3234
+ return input.servers.flatMap((server) => {
3235
+ const ref = server.connectionRef;
3236
+ if (!ref || ref.subjectScope !== "subject") return [];
3237
+ const delegation = input.parentDelegations.find(
3238
+ (candidate) => candidate.serverId === server.id && sameProviderDomain(candidate.providerDomain, ref.providerDomain) && (!ref.kind || !candidate.kind || candidate.kind === ref.kind)
3239
+ );
3240
+ return delegation ? [{ ...delegation }] : [];
3241
+ });
3242
+ }
3243
+ function personalConnectionDelegationsEqual(left, right) {
3244
+ if (left.length !== right.length) return false;
3245
+ const byServer = new Map(right.map((delegation) => [delegation.serverId, delegation]));
3246
+ return left.every((delegation) => {
3247
+ const other = byServer.get(delegation.serverId);
3248
+ return other?.connectionId === delegation.connectionId && other.ownerSubjectId === delegation.ownerSubjectId && sameProviderDomain(other.providerDomain, delegation.providerDomain) && other.kind === delegation.kind;
3249
+ });
3250
+ }
3251
+ function personalConnectionDelegationForServer(delegations, server) {
3252
+ const ref = server.connectionRef;
3253
+ if (!ref || ref.subjectScope !== "subject") return null;
3254
+ return delegations.find(
3255
+ (delegation) => delegation.serverId === server.id && sameProviderDomain(delegation.providerDomain, ref.providerDomain) && (!ref.kind || !delegation.kind || delegation.kind === ref.kind)
3256
+ ) ?? null;
3257
+ }
3258
+ function personalAuthorityUnavailable(request) {
3259
+ const ref = request.connectionRef;
3260
+ return {
3261
+ status: "auth_needed",
3262
+ reason: "personal_authority_unavailable",
3263
+ providerDomain: ref.providerDomain,
3264
+ ...ref.provider ? { provider: ref.provider } : {},
3265
+ ...ref.scopes ? { scopes: ref.scopes } : {},
3266
+ ...ref.resource ? { resource: ref.resource } : {},
3267
+ ...ref.selectedResources ? { selectedResources: ref.selectedResources } : {}
3268
+ };
3269
+ }
3270
+ function withFrozenPersonalConnectionDelegations(input) {
3271
+ return async (request) => {
3272
+ let effectiveRequest = request;
3273
+ if (request.connectionRef.subjectScope === "subject") {
3274
+ const config = input.settings.mcpServers.find((server) => server.id === request.serverId);
3275
+ const delegation = config ? personalConnectionDelegationForServer(input.personalConnectionDelegations, config) : null;
3276
+ if (!delegation || !await input.ownerHasWorkspaceMembership(delegation.ownerSubjectId)) {
3277
+ return personalAuthorityUnavailable(request);
3278
+ }
3279
+ effectiveRequest = {
3280
+ ...request,
3281
+ subjectId: delegation.ownerSubjectId,
3282
+ connectionRef: {
3283
+ ...request.connectionRef,
3284
+ providerDomain: delegation.providerDomain,
3285
+ connectionId: delegation.connectionId,
3286
+ ...delegation.kind ? { kind: delegation.kind } : {}
3287
+ }
3288
+ };
3289
+ }
3290
+ const result = await input.resolveCredential(effectiveRequest);
3291
+ if (result.status === "ok" || request.connectionRef.subjectScope !== "subject") {
3292
+ return result;
3293
+ }
3294
+ return personalAuthorityUnavailable(request);
3295
+ };
3296
+ }
3297
+ async function freezePersonalConnectionDelegations(input) {
3298
+ const servers = selectedPersonalConnectionServers(input.settings, input.tools);
3299
+ if (servers.length === 0 || input.source.kind === "none") return [];
3300
+ if (input.source.kind === "turn") {
3301
+ return personalConnectionDelegationsFromParent({
3302
+ servers,
3303
+ parentDelegations: await getSessionTurnPersonalConnectionDelegations(
3304
+ input.db,
3305
+ input.workspaceId,
3306
+ input.source.sessionId,
3307
+ input.source.turnId
3308
+ )
3309
+ });
3310
+ }
3311
+ const membership = await getWorkspaceGrant2(input.db, input.source.subjectId, input.workspaceId);
3312
+ if (!membership) return [];
3313
+ return personalConnectionDelegationsFromVisibleConnections({
3314
+ servers,
3315
+ subjectId: input.source.subjectId,
3316
+ connections: await listConnectionsMetadata2(input.db, input.workspaceId, input.source.subjectId)
3317
+ });
3318
+ }
3319
+
3154
3320
  // src/domain/resources.ts
3155
3321
  import {
3156
3322
  gitCredentialBindingIdForRepository,
@@ -3552,6 +3718,7 @@ import {
3552
3718
  getNestedAgentDepthDeploymentPolicy,
3553
3719
  getRig as getRig3,
3554
3720
  getScheduledTask,
3721
+ getScheduledTaskPersonalConnectionDelegations,
3555
3722
  requireWorkspace as requireWorkspace2,
3556
3723
  updateScheduledTask
3557
3724
  } from "@opengeni/db";
@@ -4009,6 +4176,7 @@ async function createAndStartSession(input) {
4009
4176
  sandboxGroupId: input.sandboxGroupId ?? null,
4010
4177
  ...input.sandboxOs ? { sandboxOs: input.sandboxOs } : {},
4011
4178
  mcpServers: input.mcpServers ?? [],
4179
+ personalConnectionDelegations: input.personalConnectionDelegations ?? [],
4012
4180
  maxNestedAgentDepthOverride: input.maxNestedAgentDepthOverride ?? null,
4013
4181
  allowNestedAgentDepthIncrease: input.allowNestedAgentDepthIncrease ?? false,
4014
4182
  subjectId: input.subjectId ?? null
@@ -4053,6 +4221,7 @@ async function createAndStartSession(input) {
4053
4221
  sandboxGroupId: input.sandboxGroupId ?? null,
4054
4222
  ...input.sandboxOs ? { sandboxOs: input.sandboxOs } : {},
4055
4223
  mcpServers: input.mcpServers ?? [],
4224
+ personalConnectionDelegations: input.personalConnectionDelegations ?? [],
4056
4225
  maxNestedAgentDepthOverride: input.maxNestedAgentDepthOverride ?? null,
4057
4226
  allowNestedAgentDepthIncrease: input.allowNestedAgentDepthIncrease ?? false,
4058
4227
  subjectId: input.subjectId ?? null
@@ -4251,6 +4420,7 @@ async function postUserMessageTurn(input) {
4251
4420
  reasoningEffortFallback: input.reasoningEffortFallback ?? settings.openaiReasoningEffort,
4252
4421
  turnExecutionPolicy: input.turnExecutionPolicy,
4253
4422
  source: input.origin === "operator" ? "api" : "user",
4423
+ personalConnectionDelegations: input.personalConnectionDelegations ?? [],
4254
4424
  mcpCredentialUpdates: input.mcpCredentialUpdates ?? []
4255
4425
  })
4256
4426
  )
@@ -4405,6 +4575,13 @@ async function createSessionForRequest(deps, grant, workspaceId, rawPayload) {
4405
4575
  toolPolicy = { mode: "workspace_default", inheritedFromSessionId: null };
4406
4576
  }
4407
4577
  const tools = withFirstPartyTools(selectedTools, runtimeSettings);
4578
+ const personalConnectionDelegations = await freezePersonalConnectionDelegations({
4579
+ db,
4580
+ workspaceId,
4581
+ settings: runtimeSettings,
4582
+ tools,
4583
+ source: personalConnectionDelegationSourceForGrant(grant)
4584
+ });
4408
4585
  await validateGitHubRepositorySelection(db, workspaceId, resources);
4409
4586
  if (resources.some((resource) => resource.kind === "file") && !objectStorage) {
4410
4587
  throw new HTTPException10(503, { message: "object storage is not configured" });
@@ -4640,6 +4817,7 @@ async function createSessionForRequest(deps, grant, workspaceId, rawPayload) {
4640
4817
  firstPartyMcpTools,
4641
4818
  mcpServers: sessionMcpServers.dbServers,
4642
4819
  sessionMcpServers: sessionMcpServers.metadata,
4820
+ personalConnectionDelegations,
4643
4821
  parentSessionId,
4644
4822
  createIdempotencyKey: payload.idempotencyKey ?? null,
4645
4823
  maxNestedAgentDepthOverride: payload.maxNestedAgentDepth ?? null,
@@ -4742,6 +4920,14 @@ async function acceptSessionUserMessage(deps, grant, workspaceId, sessionId, inp
4742
4920
  session: existingSession,
4743
4921
  updates: input.mcpCredentialUpdates ?? []
4744
4922
  });
4923
+ const runtimeSettings = await settingsWithEnabledCapabilityMcpServers(db, workspaceId, settings);
4924
+ const personalConnectionDelegations = await freezePersonalConnectionDelegations({
4925
+ db,
4926
+ workspaceId,
4927
+ settings: runtimeSettings,
4928
+ tools: existingSession.tools,
4929
+ source: personalConnectionDelegationSourceForGrant(grant)
4930
+ });
4745
4931
  const delegatedServiceInitiator = serviceInitiatorForGrant(grant);
4746
4932
  const { accepted, turn } = await postUserMessageTurn({
4747
4933
  db,
@@ -4760,6 +4946,7 @@ async function acceptSessionUserMessage(deps, grant, workspaceId, sessionId, inp
4760
4946
  reasoningEffortFallback: sessionReasoningEffort,
4761
4947
  turnExecutionPolicy,
4762
4948
  mcpCredentialUpdates,
4949
+ personalConnectionDelegations,
4763
4950
  delivery: input.delivery ?? "send",
4764
4951
  origin: delegatedServiceInitiator ? "operator" : input.origin ?? "human",
4765
4952
  actor: grant.subjectId,
@@ -5101,6 +5288,19 @@ async function createValidatedScheduledTask(input) {
5101
5288
  if (input.payload.rigId) {
5102
5289
  await requireScheduledTaskRig(input.db, input.grant.workspaceId, input.payload.rigId);
5103
5290
  }
5291
+ const runtimeSettings = await settingsWithEnabledCapabilityMcpServers(
5292
+ input.db,
5293
+ input.grant.workspaceId,
5294
+ input.settings
5295
+ );
5296
+ const personalConnectionDelegations = await freezePersonalConnectionDelegations({
5297
+ db: input.db,
5298
+ workspaceId: input.grant.workspaceId,
5299
+ settings: runtimeSettings,
5300
+ tools: agentConfig.tools,
5301
+ source: personalConnectionDelegationSourceForGrant(input.grant)
5302
+ });
5303
+ const creationInitiator = creationInitiatorForGrant(input.grant);
5104
5304
  return await createScheduledTask(input.db, {
5105
5305
  id,
5106
5306
  accountId: input.grant.accountId,
@@ -5112,6 +5312,10 @@ async function createValidatedScheduledTask(input) {
5112
5312
  runMode: input.payload.runMode,
5113
5313
  overlapPolicy: input.payload.overlapPolicy,
5114
5314
  agentConfig,
5315
+ ...creationInitiator.initiator ? { createdBy: creationInitiator.initiator } : {},
5316
+ ...creationInitiator.context ? { createdByContext: creationInitiator.context } : {},
5317
+ createdByActor: creationInitiator.actor ?? null,
5318
+ personalConnectionDelegations,
5115
5319
  variableSetId: input.payload.variableSetId ?? null,
5116
5320
  rigId: input.payload.rigId ?? null,
5117
5321
  metadata: input.payload.metadata
@@ -5192,6 +5396,31 @@ async function validatedScheduledTaskUpdate(input) {
5192
5396
  });
5193
5397
  }
5194
5398
  update.agentConfig = nextAgentConfig;
5399
+ const runtimeSettings = await settingsWithEnabledCapabilityMcpServers(
5400
+ input.db,
5401
+ input.existing.workspaceId,
5402
+ input.settings
5403
+ );
5404
+ const personalConnectionDelegations = await freezePersonalConnectionDelegations({
5405
+ db: input.db,
5406
+ workspaceId: input.existing.workspaceId,
5407
+ settings: runtimeSettings,
5408
+ tools: nextAgentConfig.tools,
5409
+ source: personalConnectionDelegationSourceForGrant(input.grant)
5410
+ });
5411
+ if (input.existing.reusableSessionId && input.existing.runMode === "reusable_session") {
5412
+ const existingDelegations = await getScheduledTaskPersonalConnectionDelegations(
5413
+ input.db,
5414
+ input.existing.workspaceId,
5415
+ input.existing.id
5416
+ );
5417
+ if (!personalConnectionDelegationsEqual(existingDelegations, personalConnectionDelegations)) {
5418
+ throw new HTTPException11(409, {
5419
+ message: "cannot change personal MCP connections of a task with a live reusable session; recreate the task"
5420
+ });
5421
+ }
5422
+ }
5423
+ update.personalConnectionDelegations = personalConnectionDelegations;
5195
5424
  }
5196
5425
  return update;
5197
5426
  }
@@ -5202,7 +5431,18 @@ async function requireScheduledTaskForApi(db, workspaceId, taskId) {
5202
5431
  }
5203
5432
  return task;
5204
5433
  }
5205
- async function restoreScheduledTask(db, task) {
5434
+ async function captureScheduledTaskRestoreState(db, task) {
5435
+ return {
5436
+ task,
5437
+ personalConnectionDelegations: await getScheduledTaskPersonalConnectionDelegations(
5438
+ db,
5439
+ task.workspaceId,
5440
+ task.id
5441
+ )
5442
+ };
5443
+ }
5444
+ async function restoreScheduledTask(db, previous) {
5445
+ const { task } = previous;
5206
5446
  return await updateScheduledTask(db, task.workspaceId, task.id, {
5207
5447
  name: task.name,
5208
5448
  status: task.status,
@@ -5210,8 +5450,10 @@ async function restoreScheduledTask(db, task) {
5210
5450
  runMode: task.runMode,
5211
5451
  overlapPolicy: task.overlapPolicy,
5212
5452
  agentConfig: task.agentConfig,
5453
+ personalConnectionDelegations: previous.personalConnectionDelegations,
5213
5454
  reusableSessionId: task.reusableSessionId,
5214
5455
  variableSetId: task.variableSetId,
5456
+ rigId: task.rigId,
5215
5457
  metadata: task.metadata
5216
5458
  });
5217
5459
  }
@@ -5737,6 +5979,236 @@ async function getWorkspaceInsights(db, settings, input) {
5737
5979
  return { snapshot };
5738
5980
  }
5739
5981
 
5982
+ // src/domain/memory-slack-publication.ts
5983
+ import { createHash } from "crypto";
5984
+ import {
5985
+ redactSensitiveText,
5986
+ stableJson as stableJson3
5987
+ } from "@opengeni/contracts";
5988
+ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
5989
+ var SELECTOR_SEGMENT_PATTERN = /^[a-z0-9](?:[a-z0-9._-]{0,62}[a-z0-9])?$/;
5990
+ var encoder = new TextEncoder();
5991
+ var decoder = new TextDecoder();
5992
+ var MEMORY_SLACK_PROJECTION_VERSION = 1;
5993
+ var MEMORY_SLACK_SUMMARY_MAX_UTF8_BYTES = 512;
5994
+ var MEMORY_SLACK_NAMESPACE_MAX_UTF8_BYTES = 128;
5995
+ var MEMORY_SLACK_LABEL_MAX_UTF8_BYTES = 64;
5996
+ var MEMORY_SLACK_LABEL_MAX_COUNT = 8;
5997
+ var MEMORY_SLACK_OWNER_MAX_UTF8_BYTES = 96;
5998
+ var MEMORY_SLACK_PROJECTION_MAX_UTF8_BYTES = 4096;
5999
+ var DEFAULT_MEMORY_SLACK_PUBLICATION_POLICY = {
6000
+ enabled: false,
6001
+ autoImportances: ["major"],
6002
+ reviewImportances: ["normal"]
6003
+ };
6004
+ var IMPORTANCES = /* @__PURE__ */ new Set(["major", "normal", "minor"]);
6005
+ var REQUESTED_MODES = /* @__PURE__ */ new Set(["auto", "review", "never"]);
6006
+ var CHANGE_KINDS = /* @__PURE__ */ new Set(["created", "corrected", "superseded"]);
6007
+ var ORIGINS = /* @__PURE__ */ new Set(["native", "slack_derived"]);
6008
+ var AUDIENCES = /* @__PURE__ */ new Set(["workspace", "restricted"]);
6009
+ var SCOPE_TYPES = /* @__PURE__ */ new Set([
6010
+ "workspace",
6011
+ "user",
6012
+ "role",
6013
+ "session",
6014
+ "ephemeral",
6015
+ "legacy"
6016
+ ]);
6017
+ var MEMORY_STATUSES = /* @__PURE__ */ new Set([
6018
+ "proposed",
6019
+ "approved",
6020
+ "rejected",
6021
+ "active",
6022
+ "superseded",
6023
+ "archived"
6024
+ ]);
6025
+ var MEMORY_KINDS = /* @__PURE__ */ new Set([
6026
+ "semantic",
6027
+ "episodic",
6028
+ "procedural",
6029
+ "decision",
6030
+ "preference"
6031
+ ]);
6032
+ var VISIBLE_STATUSES = /* @__PURE__ */ new Set(["active", "approved"]);
6033
+ function evaluateMemorySlackPublication(input) {
6034
+ const policy = input.policy ?? DEFAULT_MEMORY_SLACK_PUBLICATION_POLICY;
6035
+ if (!validPolicy(policy)) return denied("invalid_input");
6036
+ if (!policy.enabled) return denied("disabled");
6037
+ if (input.memory.sourceType !== "workspace_memory") return denied("unsupported_source");
6038
+ if (!validIdentity(input)) return denied("invalid_input");
6039
+ if (input.memory.accountId !== input.context.accountId || input.memory.workspaceId !== input.context.workspaceId) {
6040
+ return denied("tenant_mismatch");
6041
+ }
6042
+ if (input.memory.kind !== "decision") return denied("not_decision");
6043
+ if (input.memory.scopeType !== "workspace") return denied("restricted_scope");
6044
+ if (input.distribution.audience !== "workspace") return denied("restricted_audience");
6045
+ if (input.change.origin === "slack_derived") return denied("slack_origin_loop");
6046
+ if (input.distribution.slackMode === "never") return denied("mode_never");
6047
+ const timeDecision = evaluateValidity(input);
6048
+ if (timeDecision) return denied(timeDecision);
6049
+ if (!statusEligibleForChange(input)) return denied("status_ineligible");
6050
+ if (!validChangeLineage(input)) return denied("invalid_change_lineage");
6051
+ const deliveryMode = effectiveDeliveryMode(policy, input.distribution);
6052
+ if (!deliveryMode) return denied("below_noise_policy");
6053
+ const collapsedSummary = collapseText(input.distribution.shareSummary);
6054
+ const redactedSummary = redactSensitiveText(collapsedSummary);
6055
+ if (!redactedSummary) return denied("missing_summary");
6056
+ const summary = truncateUtf8(redactedSummary, MEMORY_SLACK_SUMMARY_MAX_UTF8_BYTES);
6057
+ const namespace = normalizeNamespace(input.memory.namespace);
6058
+ const labels = normalizeLabels(input.memory.labels);
6059
+ if (!namespace || !labels) return denied("invalid_input");
6060
+ const owner = boundedOptionalText(input.change.ownerLabel, MEMORY_SLACK_OWNER_MAX_UTF8_BYTES);
6061
+ const projection = {
6062
+ version: MEMORY_SLACK_PROJECTION_VERSION,
6063
+ workspaceId: input.context.workspaceId,
6064
+ memoryId: input.memory.id,
6065
+ memoryVersion: input.memory.version,
6066
+ changeKind: input.change.kind,
6067
+ relatedMemoryId: input.change.relatedMemoryId,
6068
+ occurredAt: new Date(input.change.occurredAt).toISOString(),
6069
+ importance: input.distribution.importance,
6070
+ deliveryMode,
6071
+ summary: summary.value,
6072
+ summaryRedacted: redactedSummary !== collapsedSummary,
6073
+ summaryTruncated: summary.truncated,
6074
+ namespace,
6075
+ labels: labels.values,
6076
+ labelsTruncated: labels.truncated,
6077
+ ownerLabel: owner.value,
6078
+ ownerLabelRedacted: owner.redacted,
6079
+ ownerLabelTruncated: owner.truncated,
6080
+ authoritativeRecord: {
6081
+ workspaceId: input.context.workspaceId,
6082
+ memoryId: input.memory.id
6083
+ }
6084
+ };
6085
+ if (utf8Bytes(stableJson3(projection)) > MEMORY_SLACK_PROJECTION_MAX_UTF8_BYTES) {
6086
+ return denied("invalid_input");
6087
+ }
6088
+ const digest = createHash("sha256").update(stableJson3(projection), "utf8").digest("hex");
6089
+ return {
6090
+ eligible: true,
6091
+ deliveryMode,
6092
+ idempotencyKey: `memory-slack:v${MEMORY_SLACK_PROJECTION_VERSION}:${digest}`,
6093
+ projection
6094
+ };
6095
+ }
6096
+ function validPolicy(policy) {
6097
+ return typeof policy.enabled === "boolean" && Array.isArray(policy.autoImportances) && Array.isArray(policy.reviewImportances) && policy.autoImportances.every((importance) => IMPORTANCES.has(importance)) && policy.reviewImportances.every((importance) => IMPORTANCES.has(importance));
6098
+ }
6099
+ function validIdentity(input) {
6100
+ const uuids = [
6101
+ input.context.accountId,
6102
+ input.context.workspaceId,
6103
+ input.memory.accountId,
6104
+ input.memory.workspaceId,
6105
+ input.memory.id,
6106
+ input.memory.supersedesId,
6107
+ input.memory.supersededById,
6108
+ input.change.relatedMemoryId
6109
+ ].filter((value) => value !== null);
6110
+ return uuids.every((value) => UUID_PATTERN.test(value)) && Number.isSafeInteger(input.memory.version) && input.memory.version > 0 && typeof input.memory.namespace === "string" && Array.isArray(input.memory.labels) && input.memory.labels.every((label) => typeof label === "string") && (input.change.ownerLabel === void 0 || input.change.ownerLabel === null || typeof input.change.ownerLabel === "string") && typeof input.distribution.shareSummary === "string" && IMPORTANCES.has(input.distribution.importance) && REQUESTED_MODES.has(input.distribution.slackMode) && CHANGE_KINDS.has(input.change.kind) && ORIGINS.has(input.change.origin) && AUDIENCES.has(input.distribution.audience) && SCOPE_TYPES.has(input.memory.scopeType) && MEMORY_STATUSES.has(input.memory.status) && MEMORY_KINDS.has(input.memory.kind);
6111
+ }
6112
+ function evaluateValidity(input) {
6113
+ const now = Date.parse(input.context.now);
6114
+ const occurredAt = Date.parse(input.change.occurredAt);
6115
+ const validFrom = Date.parse(input.memory.validFrom);
6116
+ const validUntil = input.memory.validUntil === null ? null : Date.parse(input.memory.validUntil);
6117
+ if (!Number.isFinite(now) || !Number.isFinite(occurredAt) || !Number.isFinite(validFrom) || validUntil !== null && !Number.isFinite(validUntil) || validUntil !== null && validUntil <= validFrom) {
6118
+ return "invalid_input";
6119
+ }
6120
+ if (now < validFrom) return "not_yet_valid";
6121
+ if (validUntil !== null && now >= validUntil) return "expired";
6122
+ return null;
6123
+ }
6124
+ function validChangeLineage(input) {
6125
+ if (input.memory.supersedesId === input.memory.id || input.memory.supersededById === input.memory.id || input.change.relatedMemoryId === input.memory.id) {
6126
+ return false;
6127
+ }
6128
+ switch (input.change.kind) {
6129
+ case "created":
6130
+ return input.change.relatedMemoryId === null && input.memory.supersedesId === null && input.memory.supersededById === null;
6131
+ case "corrected":
6132
+ return input.change.relatedMemoryId !== null && input.change.relatedMemoryId !== input.memory.id && input.memory.supersedesId === input.change.relatedMemoryId && input.memory.supersededById === null;
6133
+ case "superseded":
6134
+ return input.change.relatedMemoryId !== null && input.change.relatedMemoryId !== input.memory.id && input.memory.supersededById === input.change.relatedMemoryId;
6135
+ }
6136
+ }
6137
+ function statusEligibleForChange(input) {
6138
+ return input.change.kind === "superseded" ? input.memory.status === "superseded" : VISIBLE_STATUSES.has(input.memory.status);
6139
+ }
6140
+ function effectiveDeliveryMode(policy, distribution) {
6141
+ const auto = new Set(policy.autoImportances);
6142
+ const review = new Set(policy.reviewImportances);
6143
+ if (distribution.slackMode === "review") {
6144
+ return auto.has(distribution.importance) || review.has(distribution.importance) ? "review" : null;
6145
+ }
6146
+ if (auto.has(distribution.importance)) return "auto";
6147
+ if (review.has(distribution.importance)) return "review";
6148
+ return null;
6149
+ }
6150
+ function normalizeNamespace(value) {
6151
+ const trimmed = value.trim();
6152
+ if (redactSensitiveText(trimmed) !== trimmed) return null;
6153
+ const namespace = trimmed.toLowerCase();
6154
+ if (!namespace || utf8Bytes(namespace) > MEMORY_SLACK_NAMESPACE_MAX_UTF8_BYTES) return null;
6155
+ if (redactSensitiveText(namespace) !== namespace) return null;
6156
+ const segments = namespace.split("/");
6157
+ if (segments.some((segment) => !SELECTOR_SEGMENT_PATTERN.test(segment))) return null;
6158
+ return segments.join("/");
6159
+ }
6160
+ function normalizeLabels(values) {
6161
+ if (!Array.isArray(values)) return null;
6162
+ const labels = /* @__PURE__ */ new Set();
6163
+ for (const value of values) {
6164
+ if (typeof value !== "string") return null;
6165
+ const trimmed = value.trim();
6166
+ if (redactSensitiveText(trimmed) !== trimmed) return null;
6167
+ const label = trimmed.toLowerCase();
6168
+ if (redactSensitiveText(label) !== label || !SELECTOR_SEGMENT_PATTERN.test(label) || utf8Bytes(label) > MEMORY_SLACK_LABEL_MAX_UTF8_BYTES) {
6169
+ return null;
6170
+ }
6171
+ labels.add(label);
6172
+ }
6173
+ const sorted = [...labels].sort();
6174
+ return {
6175
+ values: sorted.slice(0, MEMORY_SLACK_LABEL_MAX_COUNT),
6176
+ truncated: sorted.length > MEMORY_SLACK_LABEL_MAX_COUNT
6177
+ };
6178
+ }
6179
+ function boundedOptionalText(value, maxBytes) {
6180
+ const collapsed = collapseText(value ?? "");
6181
+ if (!collapsed) return { value: null, redacted: false, truncated: false };
6182
+ const redacted = redactSensitiveText(collapsed);
6183
+ const bounded = truncateUtf8(redacted, maxBytes);
6184
+ return {
6185
+ value: bounded.value || null,
6186
+ redacted: redacted !== collapsed,
6187
+ truncated: bounded.truncated
6188
+ };
6189
+ }
6190
+ function collapseText(value) {
6191
+ return value.replace(/[\u0000-\u001F\u007F-\u009F]/g, " ").replace(/\s+/g, " ").trim();
6192
+ }
6193
+ function truncateUtf8(value, maxBytes) {
6194
+ const bytes = encoder.encode(value);
6195
+ if (bytes.byteLength <= maxBytes) return { value, truncated: false };
6196
+ const marker = "\u2026";
6197
+ const markerBytes = encoder.encode(marker);
6198
+ let end = Math.max(0, maxBytes - markerBytes.byteLength);
6199
+ while (end > 0 && (bytes[end] & 192) === 128) end -= 1;
6200
+ return {
6201
+ value: `${decoder.decode(bytes.subarray(0, end)).trimEnd()}${marker}`,
6202
+ truncated: true
6203
+ };
6204
+ }
6205
+ function utf8Bytes(value) {
6206
+ return encoder.encode(value).byteLength;
6207
+ }
6208
+ function denied(reason) {
6209
+ return { eligible: false, reason };
6210
+ }
6211
+
5740
6212
  // src/domain/workspace-members.ts
5741
6213
  import { HTTPException as HTTPException12 } from "hono/http-exception";
5742
6214
  var MEMBER_ADMIN_PERMISSIONS = ["workspace:admin", "members:manage"];
@@ -6450,6 +6922,7 @@ async function saveHumanComposerDraft(deps, context, input) {
6450
6922
  export {
6451
6923
  CODEX_COMPACTION_V2_PROVIDER_LOCKED,
6452
6924
  CodexCompactionV2ProviderLockedError,
6925
+ DEFAULT_MEMORY_SLACK_PUBLICATION_POLICY,
6453
6926
  MARKETING_SOCIAL_PACK_ID,
6454
6927
  MAX_CHECKS_PER_RIG,
6455
6928
  MAX_CREDENTIAL_HOOKS_PER_RIG,
@@ -6457,6 +6930,13 @@ export {
6457
6930
  MAX_ENVIRONMENTS_PER_WORKSPACE,
6458
6931
  MAX_RIGS_PER_WORKSPACE,
6459
6932
  MAX_VARIABLES_PER_ENVIRONMENT,
6933
+ MEMORY_SLACK_LABEL_MAX_COUNT,
6934
+ MEMORY_SLACK_LABEL_MAX_UTF8_BYTES,
6935
+ MEMORY_SLACK_NAMESPACE_MAX_UTF8_BYTES,
6936
+ MEMORY_SLACK_OWNER_MAX_UTF8_BYTES,
6937
+ MEMORY_SLACK_PROJECTION_MAX_UTF8_BYTES,
6938
+ MEMORY_SLACK_PROJECTION_VERSION,
6939
+ MEMORY_SLACK_SUMMARY_MAX_UTF8_BYTES,
6460
6940
  SESSION_AUTHORIZATION_DEFAULT_REAUTHORIZE_MS,
6461
6941
  SESSION_WORKFLOW_WAKE_DISPATCHER_PERIOD_MS,
6462
6942
  SESSION_WORKFLOW_WAKE_DISPATCHER_SCHEDULE_ID,
@@ -6484,6 +6964,7 @@ export {
6484
6964
  buildFleetContextForSession,
6485
6965
  buildMarketingDailyAnalysisAgentConfig,
6486
6966
  canonicalConfiguredModel,
6967
+ captureScheduledTaskRestoreState,
6487
6968
  checkLimit,
6488
6969
  classifyRigVerificationOutcome,
6489
6970
  controlAgentSessionWorkstream,
@@ -6495,16 +6976,20 @@ export {
6495
6976
  createRigVersionForApi,
6496
6977
  createSessionForRequest,
6497
6978
  createValidatedScheduledTask,
6979
+ creationInitiatorForGrant,
6498
6980
  defaultSessionMcpServerIds,
6499
6981
  deleteHumanQueuePrompt,
6500
6982
  deleteRigForApi,
6983
+ directPersonalConnectionSubjectId,
6501
6984
  disableCapability,
6502
6985
  discoverMcpRegistryCapabilities,
6503
6986
  editHumanQueuePrompt,
6504
6987
  enableCapability,
6505
6988
  enabledCapabilityMcpToolRefs,
6989
+ evaluateMemorySlackPublication,
6506
6990
  executeRunOnSelfhostedMachine,
6507
6991
  filenameForMimeType,
6992
+ freezePersonalConnectionDelegations,
6508
6993
  getActorNewSessionDraft,
6509
6994
  getCapabilityPack,
6510
6995
  getHumanComposerDraft,
@@ -6534,6 +7019,11 @@ export {
6534
7019
  normalizeResources,
6535
7020
  officialMcpRegistryUrl,
6536
7021
  openGeniSlackBotMetadata,
7022
+ personalConnectionDelegationForServer,
7023
+ personalConnectionDelegationSourceForGrant,
7024
+ personalConnectionDelegationsEqual,
7025
+ personalConnectionDelegationsFromParent,
7026
+ personalConnectionDelegationsFromVisibleConnections,
6537
7027
  postUserMessageTurn,
6538
7028
  promoteSetupAppendChange,
6539
7029
  promoteVerifiedDefinitionEditChangeForApi,
@@ -6575,6 +7065,7 @@ export {
6575
7065
  scheduledTaskTemporalScheduleId,
6576
7066
  scheduledTaskToolsProvided,
6577
7067
  scheduledTaskTriggerToken,
7068
+ selectedPersonalConnectionServers,
6578
7069
  sendAgentSessionMessage,
6579
7070
  sessionSpawnDenialEnvelope,
6580
7071
  sessionWithEffectiveToolPolicy,
@@ -6604,6 +7095,7 @@ export {
6604
7095
  validateVariableSetAttachment,
6605
7096
  validatedScheduledTaskUpdate,
6606
7097
  withDefaultEnabledCapabilityMcpTools,
7098
+ withFrozenPersonalConnectionDelegations,
6607
7099
  workflowIdForSession,
6608
7100
  workspaceSessionToolPolicyDefaultServerIds,
6609
7101
  workspaceSessionToolPolicyServerIds,