@opengeni/core 2.5.3 → 2.6.3-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/access/index.d.ts +24 -0
  2. package/dist/canonical-human-identities.js +2 -2
  3. package/dist/{chunk-ZVZJTMSV.js → chunk-OF65T3PM.js} +2 -2
  4. package/dist/{chunk-YGOMUGYS.js → chunk-QO5GVFFO.js} +17 -8
  5. package/dist/{chunk-YGOMUGYS.js.map → chunk-QO5GVFFO.js.map} +1 -1
  6. package/dist/domain/company-brain-governed-writes.d.ts +15 -6
  7. package/dist/domain/company-profile-agent-admin.d.ts +3 -2
  8. package/dist/domain/environments.d.ts +1 -1
  9. package/dist/domain/memory-slack-delivery.d.ts +4 -1
  10. package/dist/domain/personal-connection-delegations.d.ts +1 -0
  11. package/dist/domain/pr-review.d.ts +1 -1
  12. package/dist/domain/scheduled-tasks.d.ts +12 -0
  13. package/dist/domain/sessions.d.ts +14 -1
  14. package/dist/domain/workspace-members.d.ts +8 -1
  15. package/dist/index.js +686 -380
  16. package/dist/index.js.map +1 -1
  17. package/dist/managed-auth-session-sets.d.ts +18 -0
  18. package/dist/managed-auth-session-sets.js +3 -1
  19. package/dist/sandbox/fleet.d.ts +6 -4
  20. package/dist/sandbox/routing.d.ts +7 -2
  21. package/dist/sandbox/runtime-settings.d.ts +17 -1
  22. package/package.json +10 -10
  23. package/src/access/index.ts +140 -5
  24. package/src/application/user-resource-grants.ts +31 -2
  25. package/src/billing/limits.ts +5 -2
  26. package/src/domain/company-brain-governed-writes.ts +29 -13
  27. package/src/domain/company-profile-agent-admin.ts +3 -2
  28. package/src/domain/environments.ts +6 -34
  29. package/src/domain/memory-slack-delivery.ts +30 -0
  30. package/src/domain/personal-connection-delegations.ts +40 -7
  31. package/src/domain/remember.ts +5 -6
  32. package/src/domain/scheduled-tasks.ts +94 -0
  33. package/src/domain/sessions.ts +117 -9
  34. package/src/domain/workspace-members.ts +34 -2
  35. package/src/managed-auth-session-sets.ts +38 -11
  36. package/src/sandbox/fleet.ts +20 -17
  37. package/src/sandbox/routing.ts +18 -4
  38. package/src/sandbox/runtime-settings.ts +32 -0
  39. /package/dist/{chunk-ZVZJTMSV.js.map → chunk-OF65T3PM.js.map} +0 -0
@@ -4,6 +4,16 @@ import { type Database } from "@opengeni/db";
4
4
  import type { Context } from "hono";
5
5
  import type { ManagedAuth } from "../managed-auth-type.js";
6
6
  import type { ManagedAuthSessionAdapter } from "../managed-auth-session-sets.js";
7
+ export type AccountScopedApiKeyWorkspaceAuthority = Readonly<{
8
+ accountId: string;
9
+ permissions: Permission[];
10
+ }>;
11
+ /**
12
+ * Return account-scoped API-key workspace authority only for the exact
13
+ * AccessContext object stamped by successful API-key authentication. Subject
14
+ * shape alone is deliberately insufficient.
15
+ */
16
+ export declare function accountScopedApiKeyWorkspaceAuthority(context: AccessContext): AccountScopedApiKeyWorkspaceAuthority | null;
7
17
  /**
8
18
  * Opaque, request-local proof that the canonical access resolver authorized the
9
19
  * exact account administrator named by the stamp. The random id is audit and
@@ -44,6 +54,8 @@ export type AccessGrantAuthorization = {
44
54
  * principal, and for any future path that does not verify a cookie.
45
55
  */
46
56
  canonicalManagedHumanSession: boolean;
57
+ /** Exact in-process single-user local bootstrap, never a delegated bearer. */
58
+ canonicalLocalHumanSession: boolean;
47
59
  };
48
60
  export declare function accessGrantAuthorizationFromContext(context: AccessContext, grant: AccessGrant): AccessGrantAuthorization;
49
61
  /**
@@ -56,6 +68,18 @@ export declare function accessGrantAuthorizationFromContext(context: AccessConte
56
68
  * access resolver are present in `resolvedAccessGrantAuthorizations`.
57
69
  */
58
70
  export declare function requireAccountAdminAuthorizationStamp(authorization: AccessGrantAuthorization): AccountAdminAuthorizationStamp;
71
+ /**
72
+ * Resolve the exact built-in single-user local administrator for an account.
73
+ *
74
+ * This is intentionally narrower than checking `context.mode === "local"` or
75
+ * the `dev` subject name. Only the in-process local bootstrap branch can place
76
+ * the resolved context in `canonicalLocalHumanContexts`, so delegated bearer
77
+ * tokens and caller-constructed contexts cannot borrow this authority.
78
+ */
79
+ export declare function requireCanonicalLocalAccountAdministrator(c: Context, deps: AccessDeps, accountId: string): Promise<{
80
+ subjectId: string;
81
+ authorization: AccessGrantAuthorization;
82
+ }>;
59
83
  export declare function requireAccessGrantAuthorization(c: Context, deps: AccessDeps, workspaceId: string, permission?: Permission): Promise<AccessGrantAuthorization>;
60
84
  export declare function requirePermission(grant: AccessGrant, permission: Permission): void;
61
85
  /**
@@ -3,8 +3,8 @@ import {
3
3
  getManagedAuthRequestActorLeaseStamp,
4
4
  getManagedSession,
5
5
  markManagedAuthRequestActorTransitionApplied
6
- } from "./chunk-ZVZJTMSV.js";
7
- import "./chunk-YGOMUGYS.js";
6
+ } from "./chunk-OF65T3PM.js";
7
+ import "./chunk-QO5GVFFO.js";
8
8
 
9
9
  // src/canonical-human-identities.ts
10
10
  import { HTTPException } from "hono/http-exception";
@@ -4,7 +4,7 @@ import {
4
4
  ManagedAuthActorChangeError,
5
5
  managedAuthSha256,
6
6
  resolveManagedAuthSelectedSession
7
- } from "./chunk-YGOMUGYS.js";
7
+ } from "./chunk-QO5GVFFO.js";
8
8
 
9
9
  // src/managed-session.ts
10
10
  import {
@@ -366,4 +366,4 @@ export {
366
366
  getManagedAuthRequestActorAdmissionStamp,
367
367
  getManagedAuthRequestActorLeaseStamp
368
368
  };
369
- //# sourceMappingURL=chunk-ZVZJTMSV.js.map
369
+ //# sourceMappingURL=chunk-OF65T3PM.js.map
@@ -142,25 +142,33 @@ async function authenticateAndAdoptManagedAuthSession(input) {
142
142
  credentials: { email: input.email, password: input.password },
143
143
  headers: input.isolatedHeaders
144
144
  });
145
+ return await adoptManagedAuthSession({
146
+ ...input,
147
+ authorityHash: managedAuthSha256(input.authority),
148
+ transactionSecretHash: managedAuthSha256(input.transactionSecret),
149
+ authSessionId: created.authSessionId
150
+ });
151
+ }
152
+ async function adoptManagedAuthSession(input) {
145
153
  let completed;
146
154
  try {
147
155
  completed = await completeManagedAuthLoginTransaction(input.db, {
148
- authorityHash: managedAuthSha256(input.authority),
156
+ authorityHash: input.authorityHash,
149
157
  csrfHash: input.csrfHash,
150
158
  operationId: input.operationId,
151
159
  requestDigest: input.requestDigest,
152
160
  expectedGeneration: input.expectedGeneration,
153
161
  expectedActorEpoch: input.expectedActorEpoch,
154
162
  transactionId: input.transactionId,
155
- transactionSecretHash: managedAuthSha256(input.transactionSecret),
156
- authSessionId: created.authSessionId,
163
+ transactionSecretHash: input.transactionSecretHash,
164
+ authSessionId: input.authSessionId,
157
165
  mode: input.mode
158
166
  });
159
167
  } catch (error) {
160
168
  let receipt;
161
169
  try {
162
170
  receipt = await getManagedAuthSessionSetOperationReceipt(input.db, {
163
- authorityHash: managedAuthSha256(input.authority),
171
+ authorityHash: input.authorityHash,
164
172
  operationId: input.operationId,
165
173
  requestDigest: input.requestDigest
166
174
  });
@@ -168,14 +176,14 @@ async function authenticateAndAdoptManagedAuthSession(input) {
168
176
  throw new ManagedAuthCompletionOutcomeUnknownError({ cause: receiptError });
169
177
  }
170
178
  if (receipt) {
171
- await reconcileCreatedManagedAuthSession(input, created.authSessionId);
179
+ await reconcileCreatedManagedAuthSession(input, input.authSessionId);
172
180
  return receipt;
173
181
  }
174
- await input.adapter.revokeSession(created).catch(() => void 0);
182
+ await input.adapter.revokeSession({ authSessionId: input.authSessionId }).catch(() => void 0);
175
183
  throw error;
176
184
  }
177
185
  try {
178
- await reconcileCreatedManagedAuthSession(input, created.authSessionId);
186
+ await reconcileCreatedManagedAuthSession(input, input.authSessionId);
179
187
  } catch (error) {
180
188
  throw new ManagedAuthCompletionOutcomeUnknownError({ cause: error });
181
189
  }
@@ -221,6 +229,7 @@ export {
221
229
  requireManagedAuthMutationAdmission,
222
230
  resolveManagedAuthSelectedSession,
223
231
  authenticateAndAdoptManagedAuthSession,
232
+ adoptManagedAuthSession,
224
233
  isolatedManagedAuthHeaders
225
234
  };
226
- //# sourceMappingURL=chunk-YGOMUGYS.js.map
235
+ //# sourceMappingURL=chunk-QO5GVFFO.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/managed-auth-session-sets.ts"],"sourcesContent":["import { createHash, createHmac, randomBytes, timingSafeEqual } from \"node:crypto\";\nimport type {\n ManagedAuthSessionSetMode,\n ManagedAuthSessionSetProjection,\n} from \"@opengeni/contracts/managed-auth-session-sets\";\nimport {\n completeManagedAuthLoginTransaction,\n getManagedAuthSessionSetOperationReceipt,\n getManagedAuthSessionSetSnapshot,\n type Database,\n type ManagedAuthDatabaseProjection,\n type ManagedAuthSelectedSession,\n} from \"@opengeni/db\";\n\nexport const MANAGED_AUTH_SESSION_SET_COOKIE = \"opengeni.session_set\" as const;\nexport const MANAGED_AUTH_LOGIN_TRANSACTION_COOKIE = \"opengeni.login_transaction\" as const;\nexport const MANAGED_AUTH_CSRF_HEADER = \"x-opengeni-session-csrf\" as const;\nexport const MANAGED_AUTH_ACTOR_EPOCH_HEADER = \"x-opengeni-actor-epoch\" as const;\nexport const MANAGED_AUTH_LOGIN_TRANSACTION_COOKIE_PATH =\n \"/v1/auth/session-set/transactions\" as const;\n\nexport type ManagedAuthResolvedSession = {\n session: { id: string; userId: string; [key: string]: unknown };\n user: {\n id: string;\n email: string;\n name: string;\n emailVerified: boolean;\n [key: string]: unknown;\n };\n};\n\n/** Provider-neutral boundary; provider credentials and tokens never cross its output. */\nexport interface ManagedAuthSessionAdapter {\n authenticate(input: {\n provider: \"email_password\";\n transactionId: string;\n credentials: { email: string; password: string };\n headers: Headers;\n }): Promise<{ authSessionId: string }>;\n /** Verify an ambient provider cookie without sliding expiry or emitting cookies. */\n resolveAmbientSession(headers: Headers): Promise<ManagedAuthResolvedSession | null>;\n resolveSelectedSession(\n input: ManagedAuthSelectedSession,\n ): Promise<ManagedAuthResolvedSession | null>;\n refreshSelectedSession(\n input: ManagedAuthSelectedSession,\n ): Promise<ManagedAuthResolvedSession | null>;\n revokeSession(input: { authSessionId: string }): Promise<void>;\n /** Dual-mode exact selected-session cookie plus stale provider-cache invalidations. */\n createLegacySelectedSessionCookies(\n input: ManagedAuthSelectedSession | null,\n currentCookieHeader?: string | null,\n ): Promise<string[]>;\n}\n\nexport class ManagedAuthActorChangeError extends Error {\n readonly name = \"ManagedAuthActorChangeError\";\n readonly code = \"actor_change_required\";\n constructor() {\n super(\"The selected browser actor changed\");\n }\n}\n\nexport class ManagedAuthRequestAdmissionError extends Error {\n readonly name = \"ManagedAuthRequestAdmissionError\";\n readonly code = \"origin_rejected\";\n}\n\nexport class ManagedAuthCompletionOutcomeUnknownError extends Error {\n readonly name = \"ManagedAuthCompletionOutcomeUnknownError\";\n readonly code = \"operation_outcome_unknown\";\n constructor(options?: ErrorOptions) {\n super(\"The managed authentication completion outcome is unknown\", options);\n }\n}\n\nexport function requireManagedAuthActorFence(input: {\n mode: ManagedAuthSessionSetMode;\n actorEpoch: string;\n expectedActorEpoch: string | null;\n selectedAuthSessionId: string | null;\n legacyAmbientSessionId?: string | null;\n}): void {\n if (\n (input.expectedActorEpoch !== null && input.expectedActorEpoch !== input.actorEpoch) ||\n (input.expectedActorEpoch === null &&\n (input.mode === \"broker\" ||\n input.actorEpoch !== \"1\" ||\n (input.selectedAuthSessionId !== null &&\n input.legacyAmbientSessionId !== input.selectedAuthSessionId)))\n ) {\n throw new ManagedAuthActorChangeError();\n }\n}\n\nexport function managedAuthRandomAuthority(): string {\n return randomBytes(32).toString(\"base64url\");\n}\n\nexport function managedAuthSha256(value: string): string {\n return createHash(\"sha256\").update(value, \"utf8\").digest(\"hex\");\n}\n\nexport function managedAuthCsrfHash(authority: string): string {\n return managedAuthSha256(`opengeni:managed-auth:csrf-authority:v1\\n${authority}`);\n}\n\nexport function managedAuthCsrfToken(\n signingSecret: string,\n authority: string,\n generation: string,\n): string {\n return createHmac(\"sha256\", signingSecret)\n .update(`opengeni:managed-auth:csrf:v1\\n${authority}\\n${generation}`, \"utf8\")\n .digest(\"base64url\");\n}\n\nexport function managedAuthTransactionSecret(\n signingSecret: string,\n authority: string,\n operationId: string,\n): string {\n return createHmac(\"sha256\", signingSecret)\n .update(`opengeni:managed-auth:transaction:v1\\n${authority}\\n${operationId}`, \"utf8\")\n .digest(\"base64url\");\n}\n\nexport function managedAuthDerivedUuid(namespace: string, value: string): string {\n const bytes = createHash(\"sha256\")\n .update(`${namespace}\\n${value}`, \"utf8\")\n .digest()\n .subarray(0, 16);\n bytes[6] = (bytes[6]! & 0x0f) | 0x50;\n bytes[8] = (bytes[8]! & 0x3f) | 0x80;\n const hex = bytes.toString(\"hex\");\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\nfunction canonicalJson(value: unknown): string {\n if (value === null || typeof value !== \"object\") return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(canonicalJson).join(\",\")}]`;\n return `{${Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, child]) => `${JSON.stringify(key)}:${canonicalJson(child)}`)\n .join(\",\")}}`;\n}\n\nexport function managedAuthRequestDigest(value: unknown): string {\n return managedAuthSha256(canonicalJson(value));\n}\n\nexport function managedAuthSecretRequestDigest(signingSecret: string, value: unknown): string {\n return createHmac(\"sha256\", signingSecret)\n .update(`opengeni:managed-auth:request:v1\\n${canonicalJson(value)}`, \"utf8\")\n .digest(\"hex\");\n}\n\nexport function withManagedAuthCsrfToken(\n projection: ManagedAuthDatabaseProjection,\n signingSecret: string,\n authority: string,\n): ManagedAuthSessionSetProjection {\n return {\n ...projection,\n csrfToken: managedAuthCsrfToken(signingSecret, authority, projection.generation),\n };\n}\n\nfunction equalSecret(left: string, right: string): boolean {\n const leftBytes = Buffer.from(left, \"utf8\");\n const rightBytes = Buffer.from(right, \"utf8\");\n return leftBytes.length === rightBytes.length && timingSafeEqual(leftBytes, rightBytes);\n}\n\nexport function requireManagedAuthMutationAdmission(input: {\n request: Request;\n allowedOrigins: readonly string[];\n authority: string;\n signingSecret: string;\n expectedGeneration: string;\n}): void {\n const origin = input.request.headers.get(\"origin\");\n const fetchSite = input.request.headers.get(\"sec-fetch-site\");\n const contentType = input.request.headers.get(\"content-type\")?.split(\";\", 1)[0]?.trim();\n const csrf = input.request.headers.get(MANAGED_AUTH_CSRF_HEADER);\n const allowed = new Set(input.allowedOrigins.map((candidate) => new URL(candidate).origin));\n const expectedCsrf = managedAuthCsrfToken(\n input.signingSecret,\n input.authority,\n input.expectedGeneration,\n );\n if (\n !origin ||\n !allowed.has(origin) ||\n fetchSite !== \"same-origin\" ||\n contentType !== \"application/json\" ||\n !csrf ||\n !equalSecret(csrf, expectedCsrf)\n ) {\n throw new ManagedAuthRequestAdmissionError(\"Browser session-set mutation admission failed\");\n }\n}\n\nexport async function resolveManagedAuthSelectedSession(input: {\n db: Database;\n adapter: ManagedAuthSessionAdapter;\n authority: string;\n mode: ManagedAuthSessionSetMode;\n expectedActorEpoch: string | null;\n legacyAmbientSessionId?: string | null;\n allowRecovery?: boolean;\n}): Promise<{\n session: ManagedAuthResolvedSession | null;\n projection: ManagedAuthDatabaseProjection;\n} | null> {\n const snapshot = await getManagedAuthSessionSetSnapshot(input.db, {\n authorityHash: managedAuthSha256(input.authority),\n mode: input.mode,\n includeInternal: true,\n allowRecovery: input.allowRecovery ?? false,\n readOnly: true,\n });\n if (!snapshot) return null;\n if (snapshot.projection.state === \"actor_change_required\") {\n throw new ManagedAuthActorChangeError();\n }\n requireManagedAuthActorFence({\n mode: input.mode,\n actorEpoch: snapshot.projection.actorEpoch,\n expectedActorEpoch: input.expectedActorEpoch,\n selectedAuthSessionId: snapshot.selected?.authSessionId ?? null,\n legacyAmbientSessionId: input.legacyAmbientSessionId ?? null,\n });\n if (!snapshot.selected) return { session: null, projection: snapshot.projection };\n const resolved = await input.adapter.resolveSelectedSession(snapshot.selected);\n if (\n !resolved ||\n resolved.session.id !== snapshot.selected.authSessionId ||\n resolved.user.id !== snapshot.selected.authUserId\n ) {\n return { session: null, projection: snapshot.projection };\n }\n return { session: resolved, projection: snapshot.projection };\n}\n\nexport async function authenticateAndAdoptManagedAuthSession(input: {\n db: Database;\n adapter: ManagedAuthSessionAdapter;\n isolatedHeaders: Headers;\n authority: string;\n csrfHash: string;\n operationId: string;\n requestDigest: string;\n expectedGeneration: string;\n expectedActorEpoch: string;\n transactionId: string;\n transactionSecret: string;\n email: string;\n password: string;\n mode: ManagedAuthSessionSetMode;\n}): Promise<{ projection: ManagedAuthDatabaseProjection; returnIntent: string | null }> {\n try {\n const existing = await getManagedAuthSessionSetOperationReceipt(input.db, {\n authorityHash: managedAuthSha256(input.authority),\n operationId: input.operationId,\n requestDigest: input.requestDigest,\n });\n if (existing) return existing;\n } catch (error) {\n // Provider authentication creates a durable session. Do not perform it\n // while exact-replay reconciliation is unavailable.\n throw new ManagedAuthCompletionOutcomeUnknownError({ cause: error });\n }\n const created = await input.adapter.authenticate({\n provider: \"email_password\",\n transactionId: input.transactionId,\n credentials: { email: input.email, password: input.password },\n headers: input.isolatedHeaders,\n });\n let completed: { projection: ManagedAuthDatabaseProjection; returnIntent: string | null };\n try {\n completed = await completeManagedAuthLoginTransaction(input.db, {\n authorityHash: managedAuthSha256(input.authority),\n csrfHash: input.csrfHash,\n operationId: input.operationId,\n requestDigest: input.requestDigest,\n expectedGeneration: input.expectedGeneration,\n expectedActorEpoch: input.expectedActorEpoch,\n transactionId: input.transactionId,\n transactionSecretHash: managedAuthSha256(input.transactionSecret),\n authSessionId: created.authSessionId,\n mode: input.mode,\n });\n } catch (error) {\n let receipt: Awaited<ReturnType<typeof getManagedAuthSessionSetOperationReceipt>>;\n try {\n receipt = await getManagedAuthSessionSetOperationReceipt(input.db, {\n authorityHash: managedAuthSha256(input.authority),\n operationId: input.operationId,\n requestDigest: input.requestDigest,\n });\n } catch (receiptError) {\n throw new ManagedAuthCompletionOutcomeUnknownError({ cause: receiptError });\n }\n if (receipt) {\n await reconcileCreatedManagedAuthSession(input, created.authSessionId);\n return receipt;\n }\n await input.adapter.revokeSession(created).catch(() => undefined);\n throw error;\n }\n try {\n await reconcileCreatedManagedAuthSession(input, created.authSessionId);\n } catch (error) {\n throw new ManagedAuthCompletionOutcomeUnknownError({ cause: error });\n }\n return completed;\n}\n\nasync function reconcileCreatedManagedAuthSession(\n input: Pick<\n Parameters<typeof authenticateAndAdoptManagedAuthSession>[0],\n \"db\" | \"adapter\" | \"authority\" | \"mode\"\n >,\n authSessionId: string,\n): Promise<void> {\n const snapshot = await getManagedAuthSessionSetSnapshot(input.db, {\n authorityHash: managedAuthSha256(input.authority),\n mode: input.mode,\n includeInternal: true,\n readOnly: true,\n });\n if (snapshot?.internalSlots.some((slot) => slot.authSessionId === authSessionId)) return;\n await input.adapter.revokeSession({ authSessionId });\n}\n\nexport function isolatedManagedAuthHeaders(request: Request): Headers {\n const headers = new Headers(request.headers);\n headers.delete(\"cookie\");\n headers.delete(\"authorization\");\n headers.delete(\"x-forwarded-user\");\n return headers;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/managed-auth-session-sets.ts"],"sourcesContent":["import { createHash, createHmac, randomBytes, timingSafeEqual } from \"node:crypto\";\nimport type {\n ManagedAuthSessionSetMode,\n ManagedAuthSessionSetProjection,\n} from \"@opengeni/contracts/managed-auth-session-sets\";\nimport {\n completeManagedAuthLoginTransaction,\n getManagedAuthSessionSetOperationReceipt,\n getManagedAuthSessionSetSnapshot,\n type Database,\n type ManagedAuthDatabaseProjection,\n type ManagedAuthSelectedSession,\n} from \"@opengeni/db\";\n\nexport const MANAGED_AUTH_SESSION_SET_COOKIE = \"opengeni.session_set\" as const;\nexport const MANAGED_AUTH_LOGIN_TRANSACTION_COOKIE = \"opengeni.login_transaction\" as const;\nexport const MANAGED_AUTH_CSRF_HEADER = \"x-opengeni-session-csrf\" as const;\nexport const MANAGED_AUTH_ACTOR_EPOCH_HEADER = \"x-opengeni-actor-epoch\" as const;\nexport const MANAGED_AUTH_LOGIN_TRANSACTION_COOKIE_PATH =\n \"/v1/auth/session-set/transactions\" as const;\n\nexport type ManagedAuthResolvedSession = {\n session: { id: string; userId: string; [key: string]: unknown };\n user: {\n id: string;\n email: string;\n name: string;\n emailVerified: boolean;\n [key: string]: unknown;\n };\n};\n\n/** Provider-neutral boundary; provider credentials and tokens never cross its output. */\nexport interface ManagedAuthSessionAdapter {\n authenticate(input: {\n provider: \"email_password\";\n transactionId: string;\n credentials: { email: string; password: string };\n headers: Headers;\n }): Promise<{ authSessionId: string }>;\n /** Verify an ambient provider cookie without sliding expiry or emitting cookies. */\n resolveAmbientSession(headers: Headers): Promise<ManagedAuthResolvedSession | null>;\n resolveSelectedSession(\n input: ManagedAuthSelectedSession,\n ): Promise<ManagedAuthResolvedSession | null>;\n refreshSelectedSession(\n input: ManagedAuthSelectedSession,\n ): Promise<ManagedAuthResolvedSession | null>;\n revokeSession(input: { authSessionId: string }): Promise<void>;\n /** Dual-mode exact selected-session cookie plus stale provider-cache invalidations. */\n createLegacySelectedSessionCookies(\n input: ManagedAuthSelectedSession | null,\n currentCookieHeader?: string | null,\n ): Promise<string[]>;\n}\n\nexport class ManagedAuthActorChangeError extends Error {\n readonly name = \"ManagedAuthActorChangeError\";\n readonly code = \"actor_change_required\";\n constructor() {\n super(\"The selected browser actor changed\");\n }\n}\n\nexport class ManagedAuthRequestAdmissionError extends Error {\n readonly name = \"ManagedAuthRequestAdmissionError\";\n readonly code = \"origin_rejected\";\n}\n\nexport class ManagedAuthCompletionOutcomeUnknownError extends Error {\n readonly name = \"ManagedAuthCompletionOutcomeUnknownError\";\n readonly code = \"operation_outcome_unknown\";\n constructor(options?: ErrorOptions) {\n super(\"The managed authentication completion outcome is unknown\", options);\n }\n}\n\nexport function requireManagedAuthActorFence(input: {\n mode: ManagedAuthSessionSetMode;\n actorEpoch: string;\n expectedActorEpoch: string | null;\n selectedAuthSessionId: string | null;\n legacyAmbientSessionId?: string | null;\n}): void {\n if (\n (input.expectedActorEpoch !== null && input.expectedActorEpoch !== input.actorEpoch) ||\n (input.expectedActorEpoch === null &&\n (input.mode === \"broker\" ||\n input.actorEpoch !== \"1\" ||\n (input.selectedAuthSessionId !== null &&\n input.legacyAmbientSessionId !== input.selectedAuthSessionId)))\n ) {\n throw new ManagedAuthActorChangeError();\n }\n}\n\nexport function managedAuthRandomAuthority(): string {\n return randomBytes(32).toString(\"base64url\");\n}\n\nexport function managedAuthSha256(value: string): string {\n return createHash(\"sha256\").update(value, \"utf8\").digest(\"hex\");\n}\n\nexport function managedAuthCsrfHash(authority: string): string {\n return managedAuthSha256(`opengeni:managed-auth:csrf-authority:v1\\n${authority}`);\n}\n\nexport function managedAuthCsrfToken(\n signingSecret: string,\n authority: string,\n generation: string,\n): string {\n return createHmac(\"sha256\", signingSecret)\n .update(`opengeni:managed-auth:csrf:v1\\n${authority}\\n${generation}`, \"utf8\")\n .digest(\"base64url\");\n}\n\nexport function managedAuthTransactionSecret(\n signingSecret: string,\n authority: string,\n operationId: string,\n): string {\n return createHmac(\"sha256\", signingSecret)\n .update(`opengeni:managed-auth:transaction:v1\\n${authority}\\n${operationId}`, \"utf8\")\n .digest(\"base64url\");\n}\n\nexport function managedAuthDerivedUuid(namespace: string, value: string): string {\n const bytes = createHash(\"sha256\")\n .update(`${namespace}\\n${value}`, \"utf8\")\n .digest()\n .subarray(0, 16);\n bytes[6] = (bytes[6]! & 0x0f) | 0x50;\n bytes[8] = (bytes[8]! & 0x3f) | 0x80;\n const hex = bytes.toString(\"hex\");\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\nfunction canonicalJson(value: unknown): string {\n if (value === null || typeof value !== \"object\") return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(canonicalJson).join(\",\")}]`;\n return `{${Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, child]) => `${JSON.stringify(key)}:${canonicalJson(child)}`)\n .join(\",\")}}`;\n}\n\nexport function managedAuthRequestDigest(value: unknown): string {\n return managedAuthSha256(canonicalJson(value));\n}\n\nexport function managedAuthSecretRequestDigest(signingSecret: string, value: unknown): string {\n return createHmac(\"sha256\", signingSecret)\n .update(`opengeni:managed-auth:request:v1\\n${canonicalJson(value)}`, \"utf8\")\n .digest(\"hex\");\n}\n\nexport function withManagedAuthCsrfToken(\n projection: ManagedAuthDatabaseProjection,\n signingSecret: string,\n authority: string,\n): ManagedAuthSessionSetProjection {\n return {\n ...projection,\n csrfToken: managedAuthCsrfToken(signingSecret, authority, projection.generation),\n };\n}\n\nfunction equalSecret(left: string, right: string): boolean {\n const leftBytes = Buffer.from(left, \"utf8\");\n const rightBytes = Buffer.from(right, \"utf8\");\n return leftBytes.length === rightBytes.length && timingSafeEqual(leftBytes, rightBytes);\n}\n\nexport function requireManagedAuthMutationAdmission(input: {\n request: Request;\n allowedOrigins: readonly string[];\n authority: string;\n signingSecret: string;\n expectedGeneration: string;\n}): void {\n const origin = input.request.headers.get(\"origin\");\n const fetchSite = input.request.headers.get(\"sec-fetch-site\");\n const contentType = input.request.headers.get(\"content-type\")?.split(\";\", 1)[0]?.trim();\n const csrf = input.request.headers.get(MANAGED_AUTH_CSRF_HEADER);\n const allowed = new Set(input.allowedOrigins.map((candidate) => new URL(candidate).origin));\n const expectedCsrf = managedAuthCsrfToken(\n input.signingSecret,\n input.authority,\n input.expectedGeneration,\n );\n if (\n !origin ||\n !allowed.has(origin) ||\n fetchSite !== \"same-origin\" ||\n contentType !== \"application/json\" ||\n !csrf ||\n !equalSecret(csrf, expectedCsrf)\n ) {\n throw new ManagedAuthRequestAdmissionError(\"Browser session-set mutation admission failed\");\n }\n}\n\nexport async function resolveManagedAuthSelectedSession(input: {\n db: Database;\n adapter: ManagedAuthSessionAdapter;\n authority: string;\n mode: ManagedAuthSessionSetMode;\n expectedActorEpoch: string | null;\n legacyAmbientSessionId?: string | null;\n allowRecovery?: boolean;\n}): Promise<{\n session: ManagedAuthResolvedSession | null;\n projection: ManagedAuthDatabaseProjection;\n} | null> {\n const snapshot = await getManagedAuthSessionSetSnapshot(input.db, {\n authorityHash: managedAuthSha256(input.authority),\n mode: input.mode,\n includeInternal: true,\n allowRecovery: input.allowRecovery ?? false,\n readOnly: true,\n });\n if (!snapshot) return null;\n if (snapshot.projection.state === \"actor_change_required\") {\n throw new ManagedAuthActorChangeError();\n }\n requireManagedAuthActorFence({\n mode: input.mode,\n actorEpoch: snapshot.projection.actorEpoch,\n expectedActorEpoch: input.expectedActorEpoch,\n selectedAuthSessionId: snapshot.selected?.authSessionId ?? null,\n legacyAmbientSessionId: input.legacyAmbientSessionId ?? null,\n });\n if (!snapshot.selected) return { session: null, projection: snapshot.projection };\n const resolved = await input.adapter.resolveSelectedSession(snapshot.selected);\n if (\n !resolved ||\n resolved.session.id !== snapshot.selected.authSessionId ||\n resolved.user.id !== snapshot.selected.authUserId\n ) {\n return { session: null, projection: snapshot.projection };\n }\n return { session: resolved, projection: snapshot.projection };\n}\n\nexport async function authenticateAndAdoptManagedAuthSession(input: {\n db: Database;\n adapter: ManagedAuthSessionAdapter;\n isolatedHeaders: Headers;\n authority: string;\n csrfHash: string;\n operationId: string;\n requestDigest: string;\n expectedGeneration: string;\n expectedActorEpoch: string;\n transactionId: string;\n transactionSecret: string;\n email: string;\n password: string;\n mode: ManagedAuthSessionSetMode;\n}): Promise<{ projection: ManagedAuthDatabaseProjection; returnIntent: string | null }> {\n try {\n const existing = await getManagedAuthSessionSetOperationReceipt(input.db, {\n authorityHash: managedAuthSha256(input.authority),\n operationId: input.operationId,\n requestDigest: input.requestDigest,\n });\n if (existing) return existing;\n } catch (error) {\n // Provider authentication creates a durable session. Do not perform it\n // while exact-replay reconciliation is unavailable.\n throw new ManagedAuthCompletionOutcomeUnknownError({ cause: error });\n }\n const created = await input.adapter.authenticate({\n provider: \"email_password\",\n transactionId: input.transactionId,\n credentials: { email: input.email, password: input.password },\n headers: input.isolatedHeaders,\n });\n return await adoptManagedAuthSession({\n ...input,\n authorityHash: managedAuthSha256(input.authority),\n transactionSecretHash: managedAuthSha256(input.transactionSecret),\n authSessionId: created.authSessionId,\n });\n}\n\nexport async function adoptManagedAuthSession(input: {\n db: Database;\n adapter: ManagedAuthSessionAdapter;\n authority: string;\n authorityHash: string;\n csrfHash: string;\n operationId: string;\n requestDigest: string;\n expectedGeneration: string;\n expectedActorEpoch: string;\n transactionId: string;\n transactionSecretHash: string;\n authSessionId: string;\n mode: ManagedAuthSessionSetMode;\n}): Promise<{ projection: ManagedAuthDatabaseProjection; returnIntent: string | null }> {\n let completed: { projection: ManagedAuthDatabaseProjection; returnIntent: string | null };\n try {\n completed = await completeManagedAuthLoginTransaction(input.db, {\n authorityHash: input.authorityHash,\n csrfHash: input.csrfHash,\n operationId: input.operationId,\n requestDigest: input.requestDigest,\n expectedGeneration: input.expectedGeneration,\n expectedActorEpoch: input.expectedActorEpoch,\n transactionId: input.transactionId,\n transactionSecretHash: input.transactionSecretHash,\n authSessionId: input.authSessionId,\n mode: input.mode,\n });\n } catch (error) {\n let receipt: Awaited<ReturnType<typeof getManagedAuthSessionSetOperationReceipt>>;\n try {\n receipt = await getManagedAuthSessionSetOperationReceipt(input.db, {\n authorityHash: input.authorityHash,\n operationId: input.operationId,\n requestDigest: input.requestDigest,\n });\n } catch (receiptError) {\n throw new ManagedAuthCompletionOutcomeUnknownError({ cause: receiptError });\n }\n if (receipt) {\n await reconcileCreatedManagedAuthSession(input, input.authSessionId);\n return receipt;\n }\n await input.adapter\n .revokeSession({ authSessionId: input.authSessionId })\n .catch(() => undefined);\n throw error;\n }\n try {\n await reconcileCreatedManagedAuthSession(input, input.authSessionId);\n } catch (error) {\n throw new ManagedAuthCompletionOutcomeUnknownError({ cause: error });\n }\n return completed;\n}\n\nasync function reconcileCreatedManagedAuthSession(\n input: {\n db: Database;\n adapter: ManagedAuthSessionAdapter;\n authority: string;\n mode: ManagedAuthSessionSetMode;\n },\n authSessionId: string,\n): Promise<void> {\n const snapshot = await getManagedAuthSessionSetSnapshot(input.db, {\n authorityHash: managedAuthSha256(input.authority),\n mode: input.mode,\n includeInternal: true,\n readOnly: true,\n });\n if (snapshot?.internalSlots.some((slot) => slot.authSessionId === authSessionId)) return;\n await input.adapter.revokeSession({ authSessionId });\n}\n\nexport function isolatedManagedAuthHeaders(request: Request): Headers {\n const headers = new Headers(request.headers);\n headers.delete(\"cookie\");\n headers.delete(\"authorization\");\n headers.delete(\"x-forwarded-user\");\n return headers;\n}\n"],"mappings":"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","names":[]}
@@ -15,9 +15,8 @@ export type CompanyBrainGovernedWriteRouterOptions = {
15
15
  activate?: typeof activateGovernedLearningDecision;
16
16
  /**
17
17
  * Destinations the router may activate automatically from a final eligible
18
- * decision. Defaults to preferences only: mandatory instruction policy keeps
19
- * requiring human-authoritative activation even under `automatic`, so its
20
- * decision receipt is recorded but the inactive draft stays for review.
18
+ * decision. Defaults to Skills and instruction policy. Both still pass
19
+ * through the evaluator and destination-owned activation lifecycle.
21
20
  */
22
21
  automaticDestinations?: ReadonlyArray<GovernedLearningActivationDestination>;
23
22
  /**
@@ -33,6 +32,17 @@ export type CompanyBrainGovernedWriteRouterOptions = {
33
32
  }) => Promise<GovernedLearningSlackPublicationResult>;
34
33
  };
35
34
  export declare const DEFAULT_AUTOMATIC_LEARNING_DESTINATIONS: ReadonlyArray<GovernedLearningActivationDestination>;
35
+ /**
36
+ * Start a non-authoritative post-activation notification without making the
37
+ * durable activation receipt wait for its settlement. The callback is invoked
38
+ * synchronously so immediate enqueue work begins before the router returns;
39
+ * both synchronous throws and later promise rejections are contained.
40
+ *
41
+ * Exact retries intentionally dispatch again: the publication sink owns an
42
+ * activation-receipt idempotency key, while the activation receipt remains the
43
+ * caller-facing source of truth even if notification delivery stalls forever.
44
+ */
45
+ export declare function dispatchBestEffortGovernedLearningNotification(notify: () => Promise<unknown>): void;
36
46
  /**
37
47
  * Transport-neutral facade for explicit governed Company Brain proposals.
38
48
  * It intentionally exposes no generic remember call, selector, activation,
@@ -59,9 +69,8 @@ export declare function derivedGovernedLearningOperationId(operationId: string,
59
69
  * snapshot. `suggest` records the content-free decision receipt only. Under
60
70
  * `automatic`, a final `automaticEligible` receipt is handed to the activation
61
71
  * controller, which revalidates current authority and applies the change only
62
- * through the destination-owned lifecycle. By default only preferences may
63
- * activate automatically; mandatory instruction policy always keeps a human
64
- * activation boundary. Evaluation or activation failure
72
+ * through the destination-owned lifecycle. Eligible Skills and instruction
73
+ * policies may activate automatically. Evaluation or activation failure
65
74
  * never rolls back the durable proposal; it is reported as a bounded
66
75
  * `learningFailure` and the proposal remains for human review.
67
76
  */
@@ -9,8 +9,9 @@ export type CompanyProfileAgentAdminRouterOptions = {
9
9
  /**
10
10
  * Explicit organization administration is intentionally separate from derived
11
11
  * workspace learning. The database capabilities own exact-attempt admission,
12
- * current organization-owner authority, canonical human confirmation,
13
- * tenant isolation, CAS, and immutable receipts.
12
+ * current organization-owner authority, the separate organization policy,
13
+ * canonical review when required, tenant isolation, CAS, and immutable
14
+ * receipts.
14
15
  */
15
16
  export declare function createCompanyProfileAgentAdminRouter(options: CompanyProfileAgentAdminRouterOptions): {
16
17
  propose: (input: {
@@ -1,5 +1,5 @@
1
1
  import { type Settings } from "@opengeni/config";
2
- import type { AccessGrant, VariableSet } from "@opengeni/contracts";
2
+ import { type AccessGrant, type VariableSet } from "@opengeni/contracts";
3
3
  import { type Database } from "@opengeni/db";
4
4
  export declare const MAX_ENVIRONMENTS_PER_WORKSPACE = 25;
5
5
  export declare const MAX_VARIABLES_PER_ENVIRONMENT = 100;
@@ -1,5 +1,5 @@
1
1
  import type { MemorySlackPublicationDistribution } from "@opengeni/contracts";
2
- import { type Database, type EnqueueMemorySlackPublicationResult, type MemoryEmbedder, type MemorySlackPublicationActor, type SaveWorkspaceMemoryInput, type SaveWorkspaceMemoryResult } from "@opengeni/db";
2
+ import { type CorrectWorkspaceMemoryInput, type CorrectWorkspaceMemoryResult, type Database, type EnqueueMemorySlackPublicationResult, type MemoryEmbedder, type MemorySlackPublicationActor, type SaveWorkspaceMemoryInput, type SaveWorkspaceMemoryResult } from "@opengeni/db";
3
3
  import { type MemorySlackOrigin, type MemorySlackPublicationDecision } from "./memory-slack-publication.js";
4
4
  export type MemorySlackPublicationCommitRequest = {
5
5
  distribution: MemorySlackPublicationDistribution;
@@ -14,3 +14,6 @@ export type MemorySlackPublicationCommitResult = {
14
14
  export declare function saveWorkspaceMemoryWithSlackPublication(db: Database, input: SaveWorkspaceMemoryInput, publication: MemorySlackPublicationCommitRequest | null, embedder?: MemoryEmbedder): Promise<SaveWorkspaceMemoryResult & {
15
15
  slackPublication: MemorySlackPublicationCommitResult;
16
16
  }>;
17
+ export declare function correctWorkspaceMemoryWithSlackPublication(db: Database, input: CorrectWorkspaceMemoryInput, publication: MemorySlackPublicationCommitRequest | null, embedder?: MemoryEmbedder): Promise<CorrectWorkspaceMemoryResult & {
18
+ slackPublication: MemorySlackPublicationCommitResult;
19
+ }>;
@@ -47,6 +47,7 @@ export declare function personalConnectionDelegationsFromVisibleConnections(inpu
47
47
  export declare function personalConnectionDelegationsFromParent(input: {
48
48
  servers: McpServerConfig[];
49
49
  parentDelegations: McpPersonalConnectionDelegation[];
50
+ personalGitHubResources?: ResourceRef[];
50
51
  targetSessionId?: string;
51
52
  rejectActivatedConnections?: boolean;
52
53
  }): McpPersonalConnectionDelegation[];
@@ -81,7 +81,7 @@ export declare const prReviewAutomationAdapter: {
81
81
  optional?: boolean | undefined;
82
82
  }[];
83
83
  firstPartyMcpTools: ("artifacts_create" | "artifacts_get_source" | "artifacts_list" | "artifacts_publish" | "artifacts_rollback" | "atlassian_get" | "atlassian_search" | "atlassian_sources_list" | "browser_act" | "browser_auth" | "browser_clipboard" | "browser_debug" | "browser_identity" | "browser_lifecycle" | "browser_observe" | "browser_open" | "browser_publish" | "browser_tabs" | "capability_authorization_request" | "capability_catalog_search" | "company_profile_confirm" | "company_profile_propose" | "computer_act" | "computer_clipboard" | "computer_lifecycle" | "computer_observe" | "computer_open" | "computer_targets" | "connected_machine_remove" | "editable_artifact_apply" | "editable_artifact_create" | "editable_artifact_export" | "editable_artifact_export_status" | "editable_artifact_get" | "editable_artifact_import" | "editable_artifact_inspect" | "editable_artifact_list" | "environment_list" | "environment_set_variable" | "fiken_bank_accounts_list" | "fiken_companies_list" | "fiken_contact_create" | "fiken_contacts_list" | "fiken_invoice_draft_create" | "fiken_invoice_get" | "fiken_invoices_list" | "fiken_products_list" | "fiken_purchases_list" | "fiken_sales_list" | "github_connect_link" | "github_repositories_list" | "goal_complete" | "goal_pause" | "goal_progress" | "goal_set" | "goal_update" | "goal_wait" | "instruction_policy_propose" | "interaction_discover" | "interaction_request_human" | "knowledge_correct" | "knowledge_propose" | "memory_correct" | "memory_save" | "memory_search" | "preference_propose" | "preference_registry_get" | "preference_registry_summary" | "reddit_accounts_list" | "reddit_mentions_live" | "reddit_post_reply" | "reddit_posts_sync" | "reddit_search_live" | "reddit_thread_fetch" | "remember" | "remember_confirm" | "rig_get" | "rig_list" | "rig_promote" | "rig_propose_change" | "rig_verify" | "run_on" | "sandbox_attach" | "sandbox_file_publish" | "sandbox_provision" | "sandbox_swap" | "sandboxes_list" | "scheduled_task_runs_list" | "scheduled_tasks_create" | "scheduled_tasks_delete" | "scheduled_tasks_get" | "scheduled_tasks_list" | "scheduled_tasks_pause" | "scheduled_tasks_resume" | "scheduled_tasks_trigger" | "scheduled_tasks_update" | "session_create" | "session_events" | "session_get" | "session_human_input_respond" | "session_pause" | "session_resume" | "session_send_message" | "session_steer" | "session_wait" | "sessions_list" | "set_other_session_title" | "set_session_title" | "slack_bot_channel_history" | "slack_bot_delete_message" | "slack_bot_file_content" | "slack_bot_file_info" | "slack_bot_list_channels" | "slack_bot_list_files" | "slack_bot_list_users" | "slack_bot_post_message" | "slack_bot_search" | "slack_bot_thread_replies" | "social_connections_list" | "social_daily_analysis_context" | "social_mentions_live" | "social_post_reply" | "social_posts_recent" | "social_posts_sync" | "social_search_live" | "social_thread_fetch" | "task_note_archive" | "task_note_promote_instruction_policy" | "task_note_promote_knowledge" | "task_note_promote_preference" | "task_note_replace" | "task_note_save" | "task_notes_list" | "variable_set_get_variable" | "variable_set_list" | "variable_set_set_variable" | "work_claim_release" | "work_claim_upsert" | "x_accounts_list" | "x_mentions_live" | "x_post_reply" | "x_posts_sync" | "x_search_live" | "x_thread_fetch")[];
84
- firstPartyMcpPermissions: ("account:admin" | "account:read" | "api_keys:manage" | "artifacts:publish" | "artifacts:read" | "billing:manage" | "billing:read" | "codemode:call" | "connections:read" | "connections:write" | "documents:manage" | "documents:search" | "enrollments:manage" | "enrollments:read" | "environments:manage" | "environments:use" | "files:read" | "files:upload" | "files:write" | "github:manage" | "github:use" | "goals:manage" | "mcp_servers:attach" | "members:manage" | "rigs:manage" | "rigs:use" | "scheduled_tasks:manage" | "scheduled_tasks:run" | "secrets:list" | "secrets:read" | "secrets:write" | "sessions:control" | "sessions:create" | "sessions:read" | "stream:acknowledge" | "stream:control" | "stream:view" | "terminal:attach" | "variable-sets:attach" | "variable-sets:list" | "variable-sets:manage" | "variable-sets:read" | "variable-sets:use" | "variable-sets:write" | "workspace:admin" | "workspace:create" | "workspace:read")[];
84
+ firstPartyMcpPermissions: ("account:admin" | "account:read" | "api_keys:manage" | "artifacts:publish" | "artifacts:read" | "billing:manage" | "billing:read" | "capabilities:manage" | "codemode:call" | "connections:read" | "connections:write" | "documents:manage" | "documents:search" | "enrollments:manage" | "enrollments:read" | "environments:manage" | "environments:use" | "files:read" | "files:upload" | "files:write" | "github:manage" | "github:use" | "goals:manage" | "mcp_servers:attach" | "members:manage" | "rigs:manage" | "rigs:use" | "scheduled_tasks:manage" | "scheduled_tasks:run" | "secrets:list" | "secrets:read" | "secrets:write" | "sessions:control" | "sessions:create" | "sessions:read" | "stream:acknowledge" | "stream:control" | "stream:view" | "terminal:attach" | "variable-sets:attach" | "variable-sets:list" | "variable-sets:manage" | "variable-sets:read" | "variable-sets:use" | "variable-sets:write" | "workspace:admin" | "workspace:create" | "workspace:read")[];
85
85
  model: string | null;
86
86
  reasoningEffort: "high" | "low" | "max" | "medium" | "minimal" | "none" | "xhigh" | null;
87
87
  sandboxBackend: "blaxel" | "cloudflare" | "daytona" | "docker" | "e2b" | "local" | "modal" | "none" | "opensandbox" | "runloop" | "selfhosted" | "vercel" | null;
@@ -48,6 +48,18 @@ export declare function validateScheduledTaskTarget(input: {
48
48
  agentConfig: ScheduledTaskAgentConfig;
49
49
  missingTargetStatus?: 404 | 422;
50
50
  }): Promise<Session | null>;
51
+ export declare function validateScheduledTaskMachineTarget(input: {
52
+ settings: Settings;
53
+ db: Database;
54
+ grant: AccessGrant;
55
+ runMode: ScheduledTask["runMode"];
56
+ agentConfig: ScheduledTaskAgentConfig;
57
+ requireOnline?: boolean;
58
+ }): Promise<{
59
+ sandboxId: string;
60
+ enrollmentId: string;
61
+ sandboxOs: Session["sandboxOs"];
62
+ } | null>;
51
63
  export declare function scheduledTaskForGrant(task: ScheduledTask, grant: AccessGrant): ScheduledTask;
52
64
  export declare function scheduledTaskRunForGrant<T extends {
53
65
  sessionId: string | null;
@@ -66,6 +66,15 @@ export type CreateSessionRequestOutcome = CreateSessionOutcome & {
66
66
  /** Billing telemetry is recorded after the committed session start. */
67
67
  usageRecording: "recorded" | "failed";
68
68
  };
69
+ type AgentChildSessionCreatePresentation = {
70
+ /** Model-authored title candidate from the first-party `session_create` tool.
71
+ * This is deliberately separate from the public REST request contract. */
72
+ automaticTitleCandidate?: string | null;
73
+ };
74
+ /** @internal Exported for the keyed-create repair regression. */
75
+ export declare function freezeAgentChildAutomaticTitleInCreatorContext(context: TurnInitiatorContext | undefined, title: string | null | undefined): TurnInitiatorContext | undefined;
76
+ /** @internal Keyed repair must use the committed winner, not the retry payload. */
77
+ export declare function initialAutomaticTitleForSessionStart(session: Pick<Session, "createdByContext">, requestedTitle: string | null | undefined): string | null;
69
78
  export declare function createAndStartSessionWithOutcome(input: {
70
79
  requestedSessionId?: string;
71
80
  db: Database;
@@ -107,6 +116,9 @@ export declare function createAndStartSessionWithOutcome(input: {
107
116
  rigVersionId?: string | null;
108
117
  channelId?: string | null;
109
118
  goal?: GoalSpec | null;
119
+ /** Trusted sensitive-safe automatic title for an agent-created child. The
120
+ * atomic initializer commits the row mutation and `session.title_set`. */
121
+ initialAutomaticTitle?: string | null;
110
122
  instructions?: string | null;
111
123
  policyRole?: string | null;
112
124
  firstPartyMcpPermissions?: Permission[] | null;
@@ -257,7 +269,7 @@ export declare function resolveSessionCreateVisibility(input: {
257
269
  visibilityProvided: boolean;
258
270
  parentVisibility: "user_private" | "workspace_shared" | null;
259
271
  }): "user_private" | "workspace_shared";
260
- export declare function createSessionForRequestWithOutcome(deps: ApiRouteDeps, grant: AccessGrant, workspaceId: string, rawPayload: unknown, authorization?: AccessGrantAuthorization): Promise<CreateSessionRequestOutcome>;
272
+ export declare function createSessionForRequestWithOutcome(deps: ApiRouteDeps, grant: AccessGrant, workspaceId: string, rawPayload: unknown, authorization?: AccessGrantAuthorization, agentChildPresentation?: AgentChildSessionCreatePresentation): Promise<CreateSessionRequestOutcome>;
261
273
  /** @internal Fixed public projection; the committed session outcome remains authoritative. */
262
274
  export declare function reportSessionUsageRecordingFailure(_error: unknown): void;
263
275
  /** Backward-compatible entity-returning request path for REST and core callers. */
@@ -348,3 +360,4 @@ export declare function updateSessionToolPolicy(deps: {
348
360
  sessionAuthorization?: SessionAuthorizationPort | null;
349
361
  }, grant: AccessGrant, sessionId: string, request: UpdateSessionToolPolicyRequest): Promise<Session>;
350
362
  export declare function readSessionLineage(deps: Pick<ApiRouteDeps, "db" | "sessionAuthorization">, grant: AccessGrant, sessionId: string): Promise<import("@opengeni/db").SessionLineage>;
363
+ export {};
@@ -1,4 +1,4 @@
1
- import type { WorkspaceMember } from "@opengeni/contracts";
1
+ import type { Permission, WorkspaceMember } from "@opengeni/contracts";
2
2
  /** A member can manage other members (directly or via the admin wildcard). */
3
3
  export declare function memberCanAdminister(member: Pick<WorkspaceMember, "permissions">): boolean;
4
4
  /** Only `user:` subjects are people; `api_key:` subjects belong to API keys. */
@@ -21,6 +21,13 @@ export declare function assertWorkspaceMemberRemovable(input: {
21
21
  subjectId: string;
22
22
  callerSubjectId: string;
23
23
  }): void;
24
+ /** Keep scoped member edits from orphaning the workspace or changing the caller's own grant. */
25
+ export declare function assertWorkspaceMemberUpdateAllowed(input: {
26
+ members: WorkspaceMember[];
27
+ subjectId: string;
28
+ callerSubjectId: string;
29
+ nextPermissions: Permission[];
30
+ }): void;
24
31
  /**
25
32
  * Guard the workspace-delete path before any external/DB mutation. Refuses
26
33
  * (409) to delete the account's last workspace, and refuses while any session