@wayai/cli 0.3.96 → 0.3.98

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
@@ -15,21 +15,58 @@ var __export = (target, all) => {
15
15
  __defProp(target, name, { get: all[name], enumerable: true });
16
16
  };
17
17
 
18
- // src/lib/redact.ts
19
- function redactSecrets(text) {
18
+ // src/lib/mask-secrets.ts
19
+ function valueEnd(text, from, isEnd) {
20
+ for (let i = from; i < text.length; i++) {
21
+ if (text[i] === "\\") {
22
+ i++;
23
+ continue;
24
+ }
25
+ if (isEnd(text[i])) return i;
26
+ }
27
+ return text.length;
28
+ }
29
+ function maskCredentialValues(text, keyRe, isValueEnd) {
30
+ keyRe.lastIndex = 0;
31
+ let out = "";
32
+ let copied = 0;
33
+ let match;
34
+ while ((match = keyRe.exec(text)) !== null) {
35
+ const valueStart = match.index + match[0].length;
36
+ keyRe.lastIndex = valueStart;
37
+ if (!isCredentialKey(match[1])) continue;
38
+ const end = valueEnd(text, valueStart, isValueEnd);
39
+ const value = text.slice(valueStart, end);
40
+ if (value.length === 0 || FULLY_MASKED_VALUE_RE.test(value)) continue;
41
+ out += text.slice(copied, valueStart) + "[REDACTED]";
42
+ copied = end;
43
+ keyRe.lastIndex = end;
44
+ }
45
+ return out + text.slice(copied);
46
+ }
47
+ function maskSecretsInMessage(text) {
20
48
  let out = text;
21
- for (const [pattern, replacement] of PATTERNS) {
22
- out = out.replace(pattern, replacement);
23
- }
24
- return out;
25
- }
26
- var PATTERNS;
27
- var init_redact = __esm({
28
- "src/lib/redact.ts"() {
49
+ for (const [pattern, replacement] of SHAPE_PATTERNS) out = out.replace(pattern, replacement);
50
+ out = maskCredentialValues(out, JSON_KEY_RE, isJsonValueEnd);
51
+ out = maskCredentialValues(out, QUERY_KEY_RE, isQueryValueEnd);
52
+ return out.replace(BASE64_RE, maskBase64);
53
+ }
54
+ var CREDENTIAL_KEY_RE, FULLY_MASKED_VALUE_RE, isCredentialKey, SHAPE_PATTERNS, JSON_KEY_RE, isJsonValueEnd, QUERY_KEY_RE, isQueryValueEnd, BASE64_RE, maskBase64;
55
+ var init_mask_secrets = __esm({
56
+ "src/lib/mask-secrets.ts"() {
29
57
  "use strict";
30
- PATTERNS = [
58
+ CREDENTIAL_KEY_RE = /token|secret|credential|password|passwd|api[_-]?key|authorization|private[_-]?key|session[_-]?id|cookie|jwt/i;
59
+ FULLY_MASKED_VALUE_RE = /^(?:Bearer\s+)?(?:way_|wst_)?\[REDACTED(?:_JWT|_BASE64)?\]$/;
60
+ isCredentialKey = (key) => CREDENTIAL_KEY_RE.test(key);
61
+ SHAPE_PATTERNS = [
31
62
  // JWTs (header.payload.signature) — WorkOS access/refresh tokens, OAuth JWTs.
32
63
  // Run first so a `Bearer <jwt>` collapses to the JWT placeholder.
64
+ //
65
+ // Deliberately NOT anchored with the lookbehind the base64 rule uses. It would
66
+ // make this linear (this rule is quadratic on a pathological `eyJeyJeyJ…` run),
67
+ // but it also NARROWS masking: `refresh-<jwt>` and `way_<jwt>` would stop
68
+ // matching and leak the token whole. Correctness of a redaction rule outranks
69
+ // its worst case on a body that has to be adversarial to hurt.
33
70
  [/eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, "[REDACTED_JWT]"],
34
71
  // way_ scoped API tokens (keyring/CI credentials). Leading \b avoids
35
72
  // over-redacting benign substrings (e.g. `gateway_config`); the charset is
@@ -40,6 +77,42 @@ var init_redact = __esm({
40
77
  // Authorization: Bearer <opaque token> (anything not already masked above).
41
78
  [/(Bearer\s+)[A-Za-z0-9._~+/=-]{8,}/gi, "$1[REDACTED]"]
42
79
  ];
80
+ JSON_KEY_RE = /"([A-Za-z0-9_.-]+)"\s*:\s*"/g;
81
+ isJsonValueEnd = (char) => char === '"';
82
+ QUERY_KEY_RE = /(?:^|[?#&;,\s"'])([A-Za-z0-9_.-]+)=/g;
83
+ isQueryValueEnd = (char) => char === "&" || char === ";" || char === '"' || /\s/.test(char);
84
+ BASE64_RE = // Padded base64 bodies (wrapped DEKs, HMAC secrets, service-account material)
85
+ // appearing outside any credential-named key — the shape the rules above miss.
86
+ //
87
+ // Base64 has no distinguishing charset: a bare `[A-Za-z0-9+/]{20,}` run also
88
+ // matches slash-separated paths (`hubs/production/agents/support`), 64-char DO
89
+ // hex ids, and ordinary long words — all debugging context, not secrets. Three
90
+ // constraints buy the precision instead:
91
+ // 1. Terminal `=` padding, which prose and paths don't carry.
92
+ // 2. Nothing base64-ish after the padding, so `?param=value` (where `=` is a
93
+ // separator, not padding) is excluded.
94
+ // 3. Not sitting immediately after `?` or `&`, where a run followed by `=` is
95
+ // a query parameter NAME. Constraints 2 and 3 are separate cases: `=value`
96
+ // vs. an empty value (`?someLongParamName=&next=1`), which 2 lets through.
97
+ // 4. The quad-length check below, for a run reached by neither 2 nor 3
98
+ // (`bad xxxxxxxxxxxxxxxxxxxxxx= here`).
99
+ // Runs last so `Bearer <base64>` still collapses to the Bearer placeholder.
100
+ //
101
+ // The trade: unpadded base64 (any input whose byte length is a multiple of 3)
102
+ // is NOT matched here — no marker distinguishes it from prose. It stays covered
103
+ // by the credential-key rules above, which is where such a value realistically
104
+ // reaches this module.
105
+ //
106
+ // The leading lookbehind (NOT \b) is what keeps this linear. `/` and `+` are
107
+ // non-word characters, so \b also fires *inside* a base64 run: on a body like
108
+ // `aaaa/aaaa/aaaa/…` every slash would start a fresh greedy scan of the rest of
109
+ // the string, which is quadratic (~5.5s on a 100KB body, vs ~1.3ms now). "No
110
+ // base64 char precedes this" is both the correct notion of a run's start and
111
+ // O(1) starts per run — and, unlike the JWT rule above, it narrows nothing:
112
+ // base64 embedded mid-run isn't decodable base64 anyway.
113
+ // {22,} + 1-2 pad chars => a 24-char floor, i.e. a 16-byte secret.
114
+ /(?<![A-Za-z0-9+/])(?<![?&])[A-Za-z0-9+/]{22,}={1,2}(?![A-Za-z0-9+/=])/g;
115
+ maskBase64 = (match) => match.length % 4 === 0 ? "[REDACTED_BASE64]" : match;
43
116
  }
44
117
  });
45
118
 
@@ -119,17 +192,17 @@ function initSentry(command2, version) {
119
192
  }
120
193
  }
121
194
  }
122
- if (value.value) value.value = redactSecrets(value.value);
195
+ if (value.value) value.value = maskSecretsInMessage(value.value);
123
196
  }
124
197
  }
125
198
  if (event.breadcrumbs) {
126
199
  for (const crumb of event.breadcrumbs) {
127
- if (crumb.message) crumb.message = redactSecrets(crumb.message);
200
+ if (crumb.message) crumb.message = maskSecretsInMessage(crumb.message);
128
201
  }
129
202
  }
130
203
  if (event.extra) {
131
204
  for (const [key, val] of Object.entries(event.extra)) {
132
- if (typeof val === "string") event.extra[key] = redactSecrets(val);
205
+ if (typeof val === "string") event.extra[key] = maskSecretsInMessage(val);
133
206
  }
134
207
  }
135
208
  return event;
@@ -199,7 +272,7 @@ var HARDCODED_DSN, initialized;
199
272
  var init_sentry = __esm({
200
273
  "src/lib/sentry.ts"() {
201
274
  "use strict";
202
- init_redact();
275
+ init_mask_secrets();
203
276
  init_network_error();
204
277
  HARDCODED_DSN = "https://ffe500121277babcabf32e5868f00f9e@o4510669417807872.ingest.us.sentry.io/4510960145465344";
205
278
  initialized = false;
@@ -225,14 +298,14 @@ var init_api_client = __esm({
225
298
  "src/lib/api-client.ts"() {
226
299
  "use strict";
227
300
  init_sentry();
228
- init_redact();
301
+ init_mask_secrets();
229
302
  RETRYABLE_BACKOFF_MS = [500, 1e3, 2e3];
230
303
  delay = (ms) => new Promise((resolve4) => setTimeout(resolve4, ms));
231
304
  ApiError = class extends Error {
232
305
  status;
233
306
  body;
234
307
  constructor(method, path27, status, body) {
235
- const safeBody = redactSecrets(body);
308
+ const safeBody = maskSecretsInMessage(body);
236
309
  super(`API request failed: ${method} ${path27} (${status}): ${safeBody}`);
237
310
  this.name = "ApiError";
238
311
  this.status = status;
@@ -323,6 +396,11 @@ var init_api_client = __esm({
323
396
  async adminHarnessMassDestroy(body) {
324
397
  return this.request("POST", "/api/admin/harness/mass-destroy", body);
325
398
  }
399
+ // Purge dangling hub_team_id references left by a pre-cascade team deletion.
400
+ // Used by `wayai admin hubs repair-team-orphans` (platform-admin gated).
401
+ async adminRepairTeamOrphans(body) {
402
+ return this.request("POST", "/api/admin/hubs/repair-team-orphans", body);
403
+ }
326
404
  // Read the platform config (platform-admin gated). Used by `wayai admin harness status`.
327
405
  async adminGetConfig() {
328
406
  return this.request("GET", "/api/admin/config");
@@ -4995,6 +5073,18 @@ function normalizeAuthType(raw) {
4995
5073
  if (VALID_AUTH_TYPES.has(raw)) return raw;
4996
5074
  return LEGACY_AUTH_TYPE_MAP[raw] ?? raw;
4997
5075
  }
5076
+ function jsonLengthOrNull(value) {
5077
+ try {
5078
+ const json = JSON.stringify(value);
5079
+ return typeof json === "string" ? json.length : null;
5080
+ } catch {
5081
+ return null;
5082
+ }
5083
+ }
5084
+ function withinJsonLength(value, max) {
5085
+ const length = jsonLengthOrNull(value);
5086
+ return length !== null && length <= max;
5087
+ }
4998
5088
  function visibleLength(s) {
4999
5089
  return s.replace(INVISIBLE_NAME_CHARS, "").length;
5000
5090
  }
@@ -5238,6 +5328,45 @@ function refineToolConfig(value, ctx) {
5238
5328
  }
5239
5329
  }
5240
5330
  }
5331
+ function describeRole(role) {
5332
+ if (typeof role === "string") {
5333
+ return JSON.stringify(role.length > ROLE_ECHO_MAX ? `${role.slice(0, ROLE_ECHO_MAX)}\u2026` : role);
5334
+ }
5335
+ if (role === null) return "null";
5336
+ if (Array.isArray(role)) return "an array";
5337
+ if (typeof role === "object") return "an object";
5338
+ return `a ${typeof role}`;
5339
+ }
5340
+ function asEvalInputRecord(input) {
5341
+ const value = typeof input === "string" ? (() => {
5342
+ try {
5343
+ return JSON.parse(input);
5344
+ } catch {
5345
+ return null;
5346
+ }
5347
+ })() : input;
5348
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
5349
+ }
5350
+ function evalInputRoleError(input) {
5351
+ const record = asEvalInputRecord(input);
5352
+ if (record === null) return null;
5353
+ const role = record.role;
5354
+ if (role === void 0 || role === null) return null;
5355
+ if (typeof role === "string" && EVAL_INPUT_ROLES.includes(role)) {
5356
+ return null;
5357
+ }
5358
+ return `role must be ${EVAL_INPUT_ROLE_LIST} (received ${describeRole(role)}) \u2014 an eval trigger is what the responder answers, and an assistant or tool role gives it nothing to answer`;
5359
+ }
5360
+ function refineEvalMessageTextRole(value, ctx) {
5361
+ const error = evalInputRoleError(value.eval.message_text);
5362
+ if (error) {
5363
+ ctx.addIssue({
5364
+ code: external_exports.ZodIssueCode.custom,
5365
+ path: ["eval", "message_text", "role"],
5366
+ message: error
5367
+ });
5368
+ }
5369
+ }
5241
5370
  function refineHubAsCodeCustomTools(config, ctx) {
5242
5371
  const agents = config.agents;
5243
5372
  if (!Array.isArray(agents)) return;
@@ -5329,6 +5458,22 @@ function refineHubAsCodeLanes(config, ctx) {
5329
5458
  }
5330
5459
  }
5331
5460
  }
5461
+ function refineHubAsCodeEvals(config, ctx) {
5462
+ const evals = config.evals;
5463
+ if (!Array.isArray(evals)) return;
5464
+ for (let e = 0; e < evals.length; e++) {
5465
+ const entry = evals[e];
5466
+ const error = evalInputRoleError(entry?.input);
5467
+ if (error) {
5468
+ ctx.addIssue({
5469
+ code: external_exports.ZodIssueCode.custom,
5470
+ path: ["evals", e, "input", "role"],
5471
+ // Named, not just indexed — the YAML author has files, not an array.
5472
+ message: `eval "${entry?.name ?? "<unnamed>"}": ${error}`
5473
+ });
5474
+ }
5475
+ }
5476
+ }
5332
5477
  function isSafeTemplatePath(path27) {
5333
5478
  if (path27.length === 0 || path27.length > 300) return false;
5334
5479
  if (path27.startsWith("/") || path27.includes("\\")) return false;
@@ -5402,7 +5547,7 @@ function findStepBoundaries(transcript) {
5402
5547
  }
5403
5548
  return out;
5404
5549
  }
5405
- var APP_ERROR_BRAND, AppError, LLM_RATE_LIMIT_BRAND, LlmRateLimitError, LLM_PROVIDER_HTTP_BRAND, LlmProviderHttpError, LLM_PROVIDER_TIMEOUT_BRAND, LlmProviderTimeoutError, ExternalServiceError, CHANNEL_PROVIDER_HTTP_BRAND, ChannelProviderHttpError, MEDIA_PROVIDER_HTTP_BRAND, MediaProviderHttpError, AUTH_TYPE, ORG_CREDENTIAL_AUTH_TYPES, AUTH_TYPE_DISPLAY, LEGACY_AUTH_TYPE_MAP, VALID_AUTH_TYPES, AGENT_ROLES, SAFE_USER_ID_REGEX, SUPPORTED_LOCALES, uuidSchema, paginationSchema, timestampSchema, idParamSchema, primaryRegionSchema, placementSourceSchema, orgIdParam, orgAdminIdParam, createOrganizationBody, updateOrganizationBody, addOrgAdminBody, SUMMARIZATION_THRESHOLD_MIN, SUMMARIZATION_THRESHOLD_MAX, summarizationThresholdField, monitorConfigField, agentIdParam, listAgentsQuery, agentConnectionsQuery, createAgentBody, updateAgentBody, AGENT_PARAMETER_TYPES, AGENT_PARAMETER_NAME_REGEX, agentParameterCreateSchema, MAX_AGENT_PARAMETERS_PER_REQUEST, createAgentParametersBody, SLUG_REGEX, slugSchema, INVISIBLE_NAME_CHARS, MAX_KANBAN_STATUSES, MAX_FOLLOWUPS_PER_STATUS, MAX_LANES, MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES, RESERVED_TEMPLATE_DUMP_NAME, kanbanStatusSlugSchema, followupSchema, EXCLUSIVE_FLAG_PAIRS, kanbanStatusSchema, kanbanStatusesArraySchema, laneSchema, lanesArraySchema, hubIdParam, hubAdminIdParam, hubUserIdParam, hubIdentityIdParam, hubTeamIdParam, hubTeamUserDeleteParam, hubSchemaQuery, PREVIEW_LABEL_MAX_LENGTH, previewLabelField, createHubBody, updateHubBody, addHubAdminBody, addHubIdentityAuthorizationBody, contactDecisionBody, approveContactBody, listContactAccessQuery, createHubTeamBody, updateHubTeamBody, addHubTeamUserBody, reassignHubUserBody, replicatePreviewBody, claimCodeChannelParam, claimCodeDeleteParam, connectionIdParam, connectorIdParam, listConnectionsQuery, deleteConnectionQuery, addConnectionBody, editConnectionBody, PRODUCTION_DIRECT_FIELDS, setProductionCredentialBody, registerWhatsappQuery, registerWhatsappBody, retryProvisioningQuery, resendDomainStatusQuery, PLACEHOLDER_TOKENS, ALLOWED_TYPES, SUBSCHEMA_OBJECT_KEYWORDS, SUBSCHEMA_LIST_KEYWORDS, SUBSCHEMA_MAP_KEYWORDS, MAX_SCHEMA_DEPTH, toolIdParam, listToolsQuery, toolAgentQuery, deleteToolQuery, toolConnectionsQuery, nativeToolIdSchema, addNativeToolBody, addMcpToolBody, createCustomToolBody, updateCustomToolBody, updateToolExecutionConfigBody, initialValueCreateSchema, initialValueUpdateSchema, stateIdParam, listStatesQuery, stateNameSchema, createStateBody, updateStateBody, reorderStatesBody, variantAiModeSchema, experimentStatusSchema, overlayUpdateSchema, experimentIdParam, variantIdParam, listExperimentsQuery, listVariantsQuery, listOverridesQuery, deleteOverrideQuery, createExperimentBody, updateExperimentBody, setExperimentStatusBody, createVariantBody, updateVariantBody, upsertOverrideBody, orgTagIdParam, listOrgTagsQuery, createOrgTagBody, updateOrgTagBody, orgCredentialIdParam, listOrgCredentialsQuery, createOrgCredentialBody, updateOrgCredentialBody, orgResourceIdParam, orgResourceFileIdParam, orgResourceFolderIdParam, hubOrgResourceParam, listOrgResourcesQuery, orgIdQuery, createOrgResourceBody, updateOrgResourceBody, createOrgResourceFolderBody, updateOrgResourceFolderBody, uploadOrgResourceFileBody, updateOrgResourceFileBody, uploadOrgSkillZipBody, linkOrgResourceBody, resourceIdParam, listResourcesQuery, createResourceBody, updateResourceBody, syncSkillsBody, resourceFileIdParam, listResourceFilesQuery, createResourceFileBody, updateResourceFileBody, uploadResourceFileBody, uploadSkillZipBody, resourceFolderIdParam, listResourceFoldersQuery, createResourceFolderBody, updateResourceFolderBody, agentResourceQuery, hubResourceQuery, linkAgentResourceBody, updateAgentResourceBody, unlinkAgentResourceQuery, navItemSchema, hubCountResetBody, navItemCountResetBody, typingBody, analyticsHubIdParam, analyticsVariableIdParam, updateVariablePinBody, updateAnalyticsViewBody, NUMERIC_FILTER_OPS, TEXT_FILTER_OPS, CATEGORICAL_FILTER_OPS, VARIABLE_FILTER_OPS, STRUCTURED_QUERY_OPS, STRUCTURED_QUERY_AGGREGATIONS, filterValueSchema, conversationsBody, analyticsConversationIdParam, messagesQuery, conversationDetailDataQuery, analyticsDataBody, structuredQueryBody, analyticsSqlBody, analyticsSqlSchemaQuery, EVAL_PACING_PRESET_NAMES, PACING_INTERVAL_MIN_MS, PACING_INTERVAL_MAX_MS, EVAL_RUN_DEADLINE_MIN_MS, EVAL_RUN_DEADLINE_MAX_MS, paginationSchema2, evalIdParam, sessionIdParam, scenarioSetIdParam, hubIdQuery, createEvalBody, updateEvalBody, getEvalsQuery, toggleEvalBody, bulkToggleEvalsBody, pacingConfigSchema, sessionConfigSchema, createSessionBody, getSessionsQuery, getSessionResultsQuery, getSessionRunsQuery, evalAnalyticsQuery, getSessionCostQuery, compareSessionsQuery, evalsSqlBody, evalsSqlSchemaQuery, exportResultsQuery, validateEvalBody, hubAgentsQuery, createScenarioSetBody, updateScenarioSetBody, scenarioSetsHubQuery, createScenarioFromConversationBody, createJourneyFromConversationBody, journeyIdParam, journeyToolCallSchema, journeyTurnSchema, journeyStepOverrideSchema, fixtureField, createJourneyBody, updateJourneyBody, getConversationsQuery, getMessagesQuery, updateUserBody, updateProfileBody, pathnameRegex, updatePreferencesBody, registerPushTokenBody, deletePushTokenQuery, activityQuery, deletionModeSchema, deletionRequestBody, archiveHubIdParam, archiveConversationParams, archiveListQuery, archiveMessageObservabilityParams, conversationIdParam, claimBody, releaseBody, transferBody, closeBody, additionalContextPayloadSchema, kanbanUpdateBody, annotateConversationBody, observabilityParams, observabilityListParams, deleteUserConversationsBody, sendMessageBody, listConversationsQuery, getConversationDetailParams, getConversationDetailQuery, listWhatsAppTemplatesQuery, sendWhatsAppTemplateBody, billingOrgIdParam, subscriptionItemParams, spendCapBody, growthPacksBody, portalSessionBody, checkoutSessionBody, updateBillingCurrencyBody, invoicesQuery, downloadBody, uploadQuery, signUrlBody, outboundSchemaQuery, templateIdParam, listTemplatesQuery, deleteTemplateQuery, templateStatusQuery, createTemplateBody, updateTemplateBody, submitTemplateBody, testTemplateBody, contactIdParam, listContactsQuery, createContactBody, updateContactBody, listIdParam, listListsQuery, listListContactsQuery, createListBody, updateListBody, addListContactsBody, removeListContactsBody, scheduleIdParam, listSchedulesQuery, listExecutionsQuery, createScheduleBody, updateScheduleBody, uuidPattern, ciUuidSchema, hubAsCodeConfigSchema, ciPullHubIdParam, ciBranchParam, ciPullQuery, ciHubsQuery, ciLookupQuery, ciBranchesQuery, ciSyncBody, ciPushBody, ciDiffBody, ciPublishBody, ciPublishPreviewBody, ciSyncMcpBody, ciOrgResourcesParam, orgResourcesConfigSchema, ciOrgResourcesPushBody, ciOrgResourcesDiffBody, adminOrgIdParam, adminOrgAdminIdParam, adminUserIdParam, adminPlanIdParam, adminHubIdParam, adminOrganizationsQuery, adminUserSearchQuery, kanbanSlugMigrationQuery, adjustQuotaBody, updatePlanBody, addAdminUserBody, updatePlatformConfigBody, updateFreeOrgLimitBody, adminSetOrgHarnessBody, adminSetHubHarnessBody, adminHarnessMassDestroyBody, updatePricingPlanBody, dataExplorerSearchQuery, dataExplorerOrgIdParam, dataExplorerHubIdParam, dataExplorerConvIdParam, dataExplorerDoInstancesQuery, dataExplorerNsIdParam, dataExplorerKvKeysQuery, dataExplorerKvKeyParam, uuidOrHexId, dataExplorerDeleteOrgParam, dataExplorerDeleteHubParam, dataExplorerDeleteConvParam, dataExplorerDeleteUserParam, dataExplorerDeleteQuery, dataExplorerKvDeleteQuery, pitrDoNamespace, pitrBookmarkParam, pitrRestoreBody, healthSamplingTriggerBody, dataExplorerDebugDoType, DEBUG_READ_MAX_LIMIT, DEBUG_READ_DEFAULT_LIMIT, DEBUG_DO_HEX_PREFIX, debugDoEntityId, debugTableName, dataExplorerDebugTablesParam, dataExplorerDebugRowsParam, dataExplorerDebugRowsQuery, dataExplorerDebugAnalyticsTable, debugUuid, dataExplorerDebugAnalyticsRowsParam, dataExplorerDebugAnalyticsRowsQuery, debugHubConvParam, debugMessageIdQuery, sandboxEgressPolicy, SANDBOX_EXEC_MAX_CMD_LENGTH, SANDBOX_EXEC_MAX_ALLOWLIST, SANDBOX_EXEC_MAX_TIMEOUT_MS, adminSandboxExecBody, whatsappCallbackBody, authMeResponse, wsTicketResponse, sessionCheckResponse, logoutResponse, magicCodeSendBody, magicCodeSendResponse, magicCodeVerifyBody, magicCodeVerifyResponse, browserParams, browserFoldersQuery, browserFilesQuery, stateOperationBody, conversationListResourcesQuery, conversationReadResourceQuery, listPendingSchedulesQuery, listHubAggregateSchedulesQuery, reportSourceSchema, intakeReportSourceSchema, reportClassificationSchema, reportStatusSchema, reportLocaleSchema, reportMessageAuthorRoleSchema, sentryRefStatusSchema, createReportBody, editReportBody, contestReportBody, reporterListQuery, listReportsQuery, GITHUB_ISSUE_URL_REGEX, githubIssueUrlSchema, transitionReportBody, groupReportsBody, holdReportBody, clickhouseReadyResponse, bootstrapQuery, requestSnapshotChunkMessage, MAX_NAME_LENGTH, MAX_VALUE_LENGTH, MAX_TAGS, MAX_TAG_LENGTH, MAX_SCOPE_HUBS, MAX_SCOPE_TAGS, vaultSecretScopeSchema, vaultCreateBody, vaultUpdateBody, PERMISSIONS, MAX_NAME_LENGTH2, MAX_HUBS_PER_GRANT, MAX_HUB_TAGS_PER_GRANT, MAX_GRANTS, permissionEnum, grantScopeSchema, grantSchema, createTokenBody, tokenOrgIdParam, tokenGrantScopeSchema, tokenGrantSchema, tokenMetadataSchema, listTokensResponse, createTokenResponse, orgTokenSummarySchema, listOrgTokensResponse, invitePreviewQuery, invitePreviewResponse, discordTier, discordBillingCycle, discordMetadata, discordOAuthStartResponse, discordOAuthFinalizeBody, discordOAuthFinalizeResponse, discordDisconnectResponse, jsonSchemaSchema, hubUserIdentity, stateValueEntry, getHubUserContextResponse, updateHubUserBody, updateHubUserResponse, unlockHubUserNameResponse, stateResetParams, stateResetResponse, hubAlertsParam, hubAlertSeverity, hubAlert, hubAlertsListResponse, noticeSeveritySchema, noticeStatusSchema, NOTICE_SCOPE_REGEX, noticeScopeSchema, noticeLinkSchema, createNoticeBody, updateNoticeBody, listNoticesQuery, noticeIdParamSchema, templateLocaleSchema, TEMPLATE_SLUG_REGEX, templateSlugSchema, templateStatusSchema, templateFileMapSchema, templateTextSchema, templateUsesEntrySchema, templateUsesSchema, templateYamlLocaleEntry, templateYamlWayaiBlock, templateTagsSchema, templateYamlSchema, templateHeroSchema, templatePushLocaleSchema, templatePushBody, templateListQuery, templateSlugParam, templateDetailQuery, ADMIN_SKILL_NAME_REGEX, adminSkillNameParam, WAYAI_WORKSPACE_LAYOUT, MAX_RESOURCE_FILE_SIZE;
5550
+ var APP_ERROR_BRAND, AppError, LLM_RATE_LIMIT_BRAND, LlmRateLimitError, LLM_PROVIDER_HTTP_BRAND, LlmProviderHttpError, LLM_PROVIDER_TIMEOUT_BRAND, LlmProviderTimeoutError, ExternalServiceError, CHANNEL_PROVIDER_HTTP_BRAND, ChannelProviderHttpError, MEDIA_PROVIDER_HTTP_BRAND, MediaProviderHttpError, AUTH_TYPE, ORG_CREDENTIAL_AUTH_TYPES, AUTH_TYPE_DISPLAY, LEGACY_AUTH_TYPE_MAP, VALID_AUTH_TYPES, AGENT_ROLES, SAFE_USER_ID_REGEX, SUPPORTED_LOCALES, uuidSchema, paginationSchema, timestampSchema, idParamSchema, primaryRegionSchema, placementSourceSchema, orgIdParam, orgAdminIdParam, createOrganizationBody, updateOrganizationBody, addOrgAdminBody, SUMMARIZATION_THRESHOLD_MIN, SUMMARIZATION_THRESHOLD_MAX, summarizationThresholdField, monitorConfigField, agentIdParam, listAgentsQuery, agentConnectionsQuery, createAgentBody, updateAgentBody, AGENT_PARAMETER_TYPES, AGENT_PARAMETER_NAME_REGEX, agentParameterCreateSchema, MAX_AGENT_PARAMETERS_PER_REQUEST, createAgentParametersBody, SLUG_REGEX, slugSchema, INVISIBLE_NAME_CHARS, MAX_KANBAN_STATUSES, MAX_FOLLOWUPS_PER_STATUS, MAX_LANES, MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES, RESERVED_TEMPLATE_DUMP_NAME, kanbanStatusSlugSchema, followupSchema, EXCLUSIVE_FLAG_PAIRS, kanbanStatusSchema, kanbanStatusesArraySchema, laneSchema, lanesArraySchema, hubIdParam, hubAdminIdParam, hubUserIdParam, hubIdentityIdParam, hubTeamIdParam, hubTeamUserDeleteParam, hubSchemaQuery, PREVIEW_LABEL_MAX_LENGTH, MAX_ENDED_INDEX_RETENTION_DAYS, previewLabelField, createHubBody, updateHubBody, addHubAdminBody, addHubIdentityAuthorizationBody, contactDecisionBody, approveContactBody, listContactAccessQuery, createHubTeamBody, updateHubTeamBody, addHubTeamUserBody, reassignHubUserBody, replicatePreviewBody, updateChannelTestIdentitiesBody, claimCodeChannelParam, claimCodeDeleteParam, connectionIdParam, connectorIdParam, listConnectionsQuery, deleteConnectionQuery, addConnectionBody, editConnectionBody, PRODUCTION_DIRECT_FIELDS, setProductionCredentialBody, registerWhatsappQuery, registerWhatsappBody, retryProvisioningQuery, resendDomainStatusQuery, PLACEHOLDER_TOKENS, ALLOWED_TYPES, SUBSCHEMA_OBJECT_KEYWORDS, SUBSCHEMA_LIST_KEYWORDS, SUBSCHEMA_MAP_KEYWORDS, MAX_SCHEMA_DEPTH, toolIdParam, listToolsQuery, toolAgentQuery, deleteToolQuery, toolConnectionsQuery, nativeToolIdSchema, addNativeToolBody, addMcpToolBody, createCustomToolBody, updateCustomToolBody, updateToolExecutionConfigBody, initialValueCreateSchema, initialValueUpdateSchema, stateIdParam, listStatesQuery, stateNameSchema, createStateBody, updateStateBody, reorderStatesBody, variantAiModeSchema, experimentStatusSchema, overlayUpdateSchema, experimentIdParam, variantIdParam, listExperimentsQuery, listVariantsQuery, listOverridesQuery, deleteOverrideQuery, createExperimentBody, updateExperimentBody, setExperimentStatusBody, createVariantBody, updateVariantBody, upsertOverrideBody, orgTagIdParam, listOrgTagsQuery, createOrgTagBody, updateOrgTagBody, orgCredentialIdParam, listOrgCredentialsQuery, createOrgCredentialBody, updateOrgCredentialBody, orgResourceIdParam, orgResourceFileIdParam, orgResourceFolderIdParam, hubOrgResourceParam, listOrgResourcesQuery, orgIdQuery, createOrgResourceBody, updateOrgResourceBody, createOrgResourceFolderBody, updateOrgResourceFolderBody, uploadOrgResourceFileBody, updateOrgResourceFileBody, uploadOrgSkillZipBody, linkOrgResourceBody, resourceIdParam, listResourcesQuery, createResourceBody, updateResourceBody, syncSkillsBody, resourceFileIdParam, listResourceFilesQuery, createResourceFileBody, updateResourceFileBody, uploadResourceFileBody, uploadSkillZipBody, resourceFolderIdParam, listResourceFoldersQuery, createResourceFolderBody, updateResourceFolderBody, agentResourceQuery, hubResourceQuery, linkAgentResourceBody, updateAgentResourceBody, unlinkAgentResourceQuery, navItemSchema, hubCountResetBody, navItemCountResetBody, typingBody, analyticsHubIdParam, analyticsVariableIdParam, updateVariablePinBody, updateAnalyticsViewBody, NUMERIC_FILTER_OPS, TEXT_FILTER_OPS, CATEGORICAL_FILTER_OPS, VARIABLE_FILTER_OPS, STRUCTURED_QUERY_OPS, STRUCTURED_QUERY_AGGREGATIONS, filterValueSchema, conversationsBody, analyticsConversationIdParam, messagesQuery, conversationDetailDataQuery, analyticsDataBody, structuredQueryBody, analyticsSqlBody, analyticsSqlSchemaQuery, EVAL_PACING_PRESET_NAMES, PACING_INTERVAL_MIN_MS, PACING_INTERVAL_MAX_MS, EVAL_RUN_DEADLINE_MIN_MS, EVAL_RUN_DEADLINE_MAX_MS, paginationSchema2, evalIdParam, sessionIdParam, scenarioSetIdParam, hubIdQuery, EVAL_INPUT_ROLES, EVAL_INPUT_ROLE_LIST, ROLE_ECHO_MAX, createEvalBody, updateEvalBody, getEvalsQuery, toggleEvalBody, bulkToggleEvalsBody, pacingConfigSchema, sessionConfigSchema, createSessionBody, getSessionsQuery, getSessionResultsQuery, getSessionRunsQuery, evalAnalyticsQuery, getSessionCostQuery, compareSessionsQuery, evalsSqlBody, evalsSqlSchemaQuery, exportResultsQuery, validateEvalBody, hubAgentsQuery, createScenarioSetBody, updateScenarioSetBody, scenarioSetsHubQuery, createScenarioFromConversationBody, createJourneyFromConversationBody, journeyIdParam, journeyToolCallSchema, journeyTurnSchema, journeyStepOverrideSchema, fixtureField, createJourneyBody, updateJourneyBody, getConversationsQuery, getMessagesQuery, clientOptionalString, clientOptionalBoolean, appMessageSenderType, appMessageReceiverType, appMessageAttachment, MAX_ATTACHMENTS_PER_MESSAGE, appMessageBody, updateUserBody, updateProfileBody, pathnameRegex, updatePreferencesBody, registerPushTokenBody, deletePushTokenQuery, activityQuery, deletionModeSchema, deletionRequestBody, archiveHubIdParam, archiveConversationParams, archiveListQuery, archiveMessageObservabilityParams, conversationIdParam, claimBody, releaseBody, transferBody, closeBody, additionalContextPayloadSchema, kanbanUpdateBody, annotateConversationBody, observabilityParams, observabilityListParams, deleteUserConversationsBody, sendMessageBody, listConversationsQuery, getConversationDetailParams, getConversationDetailQuery, listWhatsAppTemplatesQuery, sendWhatsAppTemplateBody, billingOrgIdParam, subscriptionItemParams, spendCapBody, growthPacksBody, portalSessionBody, checkoutSessionBody, updateBillingCurrencyBody, invoicesQuery, downloadBody, uploadQuery, signUrlBody, outboundSchemaQuery, templateIdParam, listTemplatesQuery, deleteTemplateQuery, templateStatusQuery, createTemplateBody, updateTemplateBody, submitTemplateBody, testTemplateBody, contactIdParam, listContactsQuery, createContactBody, updateContactBody, listIdParam, listListsQuery, listListContactsQuery, createListBody, updateListBody, addListContactsBody, removeListContactsBody, scheduleIdParam, listSchedulesQuery, listExecutionsQuery, createScheduleBody, updateScheduleBody, uuidPattern, ciUuidSchema, hubAsCodeConfigSchema, ciPullHubIdParam, ciBranchParam, ciPullQuery, ciHubsQuery, ciLookupQuery, ciBranchesQuery, ciSyncBody, ciPushBody, ciDiffBody, ciPublishBody, ciPublishPreviewBody, ciSyncMcpBody, ciOrgResourcesParam, orgResourcesConfigSchema, ciOrgResourcesPushBody, ciOrgResourcesDiffBody, adminOrgIdParam, adminOrgAdminIdParam, adminUserIdParam, adminPlanIdParam, adminHubIdParam, adminOrganizationsQuery, adminUserSearchQuery, kanbanSlugMigrationQuery, adjustQuotaBody, updatePlanBody, addAdminUserBody, updatePlatformConfigBody, updateFreeOrgLimitBody, adminSetOrgHarnessBody, adminSetHubHarnessBody, adminScopedTargetBody, updatePricingPlanBody, dataExplorerSearchQuery, dataExplorerOrgIdParam, dataExplorerHubIdParam, dataExplorerConvIdParam, dataExplorerDoInstancesQuery, dataExplorerNsIdParam, dataExplorerKvKeysQuery, dataExplorerKvKeyParam, uuidOrHexId, dataExplorerDeleteOrgParam, dataExplorerDeleteHubParam, dataExplorerDeleteConvParam, dataExplorerDeleteUserParam, dataExplorerDeleteQuery, dataExplorerKvDeleteQuery, pitrDoNamespace, pitrBookmarkParam, pitrRestoreBody, healthSamplingTriggerBody, dataExplorerDebugDoType, DEBUG_READ_MAX_LIMIT, DEBUG_READ_DEFAULT_LIMIT, DEBUG_DO_HEX_PREFIX, debugDoEntityId, debugTableName, dataExplorerDebugTablesParam, dataExplorerDebugRowsParam, dataExplorerDebugRowsQuery, dataExplorerDebugAnalyticsTable, debugUuid, dataExplorerDebugAnalyticsRowsParam, dataExplorerDebugAnalyticsRowsQuery, debugHubConvParam, debugMessageIdQuery, sandboxEgressPolicy, SANDBOX_EXEC_MAX_CMD_LENGTH, SANDBOX_EXEC_MAX_ALLOWLIST, SANDBOX_EXEC_MAX_TIMEOUT_MS, adminSandboxExecBody, whatsappCallbackBody, authMeResponse, wsTicketResponse, sessionCheckResponse, logoutResponse, magicCodeSendBody, magicCodeSendResponse, magicCodeVerifyBody, magicCodeVerifyResponse, browserParams, browserFoldersQuery, browserFilesQuery, stateOperationBody, conversationListResourcesQuery, conversationReadResourceQuery, listPendingSchedulesQuery, listHubAggregateSchedulesQuery, reportSourceSchema, intakeReportSourceSchema, reportClassificationSchema, reportStatusSchema, reportLocaleSchema, reportMessageAuthorRoleSchema, sentryRefStatusSchema, createReportBody, editReportBody, contestReportBody, reporterListQuery, listReportsQuery, GITHUB_ISSUE_URL_REGEX, githubIssueUrlSchema, transitionReportBody, groupReportsBody, holdReportBody, clickhouseReadyResponse, bootstrapQuery, requestSnapshotChunkMessage, MAX_NAME_LENGTH, MAX_VALUE_LENGTH, MAX_TAGS, MAX_TAG_LENGTH, MAX_SCOPE_HUBS, MAX_SCOPE_TAGS, vaultSecretScopeSchema, vaultCreateBody, vaultUpdateBody, PERMISSIONS, MAX_NAME_LENGTH2, MAX_HUBS_PER_GRANT, MAX_HUB_TAGS_PER_GRANT, MAX_GRANTS, permissionEnum, grantScopeSchema, grantSchema, createTokenBody, tokenOrgIdParam, tokenGrantScopeSchema, tokenGrantSchema, tokenMetadataSchema, listTokensResponse, createTokenResponse, orgTokenSummarySchema, listOrgTokensResponse, invitePreviewQuery, invitePreviewResponse, discordTier, discordBillingCycle, discordMetadata, discordOAuthStartResponse, discordOAuthFinalizeBody, discordOAuthFinalizeResponse, discordDisconnectResponse, jsonSchemaSchema, hubUserIdentity, stateValueEntry, getHubUserContextResponse, updateHubUserBody, updateHubUserResponse, unlockHubUserNameResponse, stateResetParams, stateResetResponse, hubAlertsParam, hubAlertSeverity, hubAlert, hubAlertsListResponse, noticeSeveritySchema, noticeStatusSchema, NOTICE_SCOPE_REGEX, noticeScopeSchema, noticeLinkSchema, createNoticeBody, updateNoticeBody, listNoticesQuery, noticeIdParamSchema, templateLocaleSchema, TEMPLATE_SLUG_REGEX, templateSlugSchema, templateStatusSchema, templateFileMapSchema, templateTextSchema, templateUsesEntrySchema, templateUsesSchema, templateYamlLocaleEntry, templateYamlWayaiBlock, templateTagsSchema, templateYamlSchema, templateHeroSchema, templatePushLocaleSchema, templatePushBody, templateListQuery, templateSlugParam, templateDetailQuery, ADMIN_SKILL_NAME_REGEX, adminSkillNameParam, WAYAI_WORKSPACE_LAYOUT, MAX_RESOURCE_FILE_SIZE;
5406
5551
  var init_dist = __esm({
5407
5552
  "../../packages/core/dist/index.js"() {
5408
5553
  "use strict";
@@ -5453,6 +5598,7 @@ var init_dist = __esm({
5453
5598
  init_zod();
5454
5599
  init_zod();
5455
5600
  init_zod();
5601
+ init_zod();
5456
5602
  APP_ERROR_BRAND = /* @__PURE__ */ Symbol.for("wayai.AppError");
5457
5603
  AppError = class extends Error {
5458
5604
  constructor(message, code, statusCode = 500, details) {
@@ -5750,7 +5896,7 @@ var init_dist = __esm({
5750
5896
  eventName: external_exports.string().optional(),
5751
5897
  additional_instructions: external_exports.string().optional(),
5752
5898
  additional_context_schema: external_exports.record(external_exports.unknown()).refine(
5753
- (s) => JSON.stringify(s).length <= MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES,
5899
+ (s) => withinJsonLength(s, MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES),
5754
5900
  `additional_context_schema must be at most ${MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES} bytes when JSON-serialized`
5755
5901
  ).optional(),
5756
5902
  followups: external_exports.array(followupSchema).max(MAX_FOLLOWUPS_PER_STATUS, `followups must have at most ${MAX_FOLLOWUPS_PER_STATUS} entries`).optional(),
@@ -5885,6 +6031,7 @@ var init_dist = __esm({
5885
6031
  hubTeamUserDeleteParam = external_exports.object({ id: uuidSchema, teamUserId: uuidSchema });
5886
6032
  hubSchemaQuery = external_exports.object({ hub_id: uuidSchema });
5887
6033
  PREVIEW_LABEL_MAX_LENGTH = 60;
6034
+ MAX_ENDED_INDEX_RETENTION_DAYS = 730;
5888
6035
  previewLabelField = external_exports.string().max(PREVIEW_LABEL_MAX_LENGTH).optional().nullable().transform((v) => {
5889
6036
  if (v == null) return null;
5890
6037
  const trimmed = v.trim();
@@ -5912,8 +6059,14 @@ var init_dist = __esm({
5912
6059
  // persisted via the agent path (.passthrough() agent body → HubDO column), not here.
5913
6060
  auto_close_inactive_days: external_exports.number().int().min(1).max(180).optional(),
5914
6061
  // Per-hub ConversationDO retention window (days) — keeps an ended conversation's DO
5915
- // alive for post-hoc annotation. Default 7, max 30 (= ENDED_INDEX_RETENTION_DAYS).
6062
+ // alive for post-hoc annotation. Default 7, max 30 — the floor of the retention
6063
+ // chain (≤ ended_index_retention_days ≤ effective storage retention).
5916
6064
  conversation_retention_days: external_exports.number().int().min(1).max(30).optional(),
6065
+ // Per-hub ended-conversation index retention window (days) — how long the warm
6066
+ // "Ended" tab + chat-hub continuous history serve a closed conversation before
6067
+ // the cleanup cron reaps its index row. Absent → DEFAULT_ENDED_INDEX_RETENTION_DAYS
6068
+ // (365). Re-clamped to the effective storage retention at reap time.
6069
+ ended_index_retention_days: external_exports.number().int().min(1).max(MAX_ENDED_INDEX_RETENTION_DAYS).optional(),
5917
6070
  // Channel contact access control. Enum-validated explicitly (not via passthrough)
5918
6071
  // so `language`/`access_approval_role` can't reach the DB with an invalid value.
5919
6072
  language: external_exports.enum(["en", "pt", "es"]).optional(),
@@ -5969,6 +6122,9 @@ var init_dist = __esm({
5969
6122
  replicatePreviewBody = external_exports.object({
5970
6123
  preview_label: previewLabelField
5971
6124
  });
6125
+ updateChannelTestIdentitiesBody = external_exports.object({
6126
+ test_identities: external_exports.array(external_exports.string().max(320)).max(1e3)
6127
+ });
5972
6128
  claimCodeChannelParam = external_exports.object({
5973
6129
  id: uuidSchema,
5974
6130
  channelId: uuidSchema
@@ -6619,12 +6775,15 @@ var init_dist = __esm({
6619
6775
  hubIdQuery = external_exports.object({
6620
6776
  hub_id: external_exports.string().uuid()
6621
6777
  });
6778
+ EVAL_INPUT_ROLES = ["user", "system"];
6779
+ EVAL_INPUT_ROLE_LIST = EVAL_INPUT_ROLES.map((r) => `"${r}"`).join(" or ");
6780
+ ROLE_ECHO_MAX = 40;
6622
6781
  createEvalBody = external_exports.object({
6623
6782
  eval: external_exports.record(external_exports.unknown())
6624
- });
6783
+ }).superRefine(refineEvalMessageTextRole);
6625
6784
  updateEvalBody = external_exports.object({
6626
6785
  eval: external_exports.record(external_exports.unknown())
6627
- });
6786
+ }).superRefine(refineEvalMessageTextRole);
6628
6787
  getEvalsQuery = external_exports.object({
6629
6788
  hub_id: external_exports.string().uuid(),
6630
6789
  agent_id: external_exports.string().uuid().optional(),
@@ -6796,18 +6955,21 @@ var init_dist = __esm({
6796
6955
  hub_user_id: external_exports.string().optional(),
6797
6956
  search_filter: external_exports.string().optional(),
6798
6957
  hub_id: external_exports.string().uuid().optional(),
6958
+ // NON-authorizing single-hub narrow. Unlike `hub_id` (which runs the
6959
+ // grant-gated `loadHub('hub:read')` and so throws for grant-less end users /
6960
+ // team members), `scope_hub_id` INTERSECTS the caller's already-resolved hub
6961
+ // roster server-side. Intersecting the caller's own roster IS the
6962
+ // authorization — a hub the caller isn't in narrows to empty and leaks
6963
+ // nothing. Continuous history sends it to take the single-hub ended-index
6964
+ // path (one HubDO read, accurate uncapped total) instead of the all-hub
6965
+ // fan-out it would otherwise discard client-side (gh #3319).
6966
+ scope_hub_id: external_exports.string().uuid().optional(),
6799
6967
  conversation_id: external_exports.string().uuid().optional(),
6800
6968
  // 'ended' = recently-closed, served warm from the HubDO index (≤ retention
6801
6969
  // window). 'archived' = the full closed-conversation history from ClickHouse.
6802
6970
  status: external_exports.enum(["active", "agent", "team", "ended", "archived"]).optional(),
6803
6971
  page: external_exports.string().regex(/^\d+$/).optional(),
6804
- page_size: external_exports.string().regex(/^\d+$/).optional(),
6805
- // Cursor for the continuous-history scroll (chat hubs): with status='archived',
6806
- // return only conversations that ended strictly before this instant. The caller
6807
- // passes the oldest warm-index `ended_at` so the CH superset excludes the
6808
- // already-loaded warm slice. UTC ISO-8601 (Timestamps standard) — datetime()
6809
- // hardens it before it reaches the parameterized CH predicate.
6810
- before_ended_at: external_exports.string().datetime().optional()
6972
+ page_size: external_exports.string().regex(/^\d+$/).optional()
6811
6973
  });
6812
6974
  getMessagesQuery = external_exports.object({
6813
6975
  hub_id: external_exports.string().uuid(),
@@ -6823,8 +6985,7 @@ var init_dist = __esm({
6823
6985
  // Keyset cursor for the newest-first scroll (`page` absent): return only
6824
6986
  // messages strictly older than (before_created_at, before_message_id) — the
6825
6987
  // oldest currently-loaded VISIBLE message. UTC ISO-8601 (Timestamps standard);
6826
- // `datetime()` hardens it before the parameterized DO predicate. Mirrors the
6827
- // `before_ended_at` cursor precedent above.
6988
+ // `datetime()` hardens it before the parameterized DO predicate.
6828
6989
  before_created_at: external_exports.string().datetime().optional(),
6829
6990
  before_message_id: external_exports.string().uuid().optional(),
6830
6991
  /**
@@ -6843,6 +7004,50 @@ var init_dist = __esm({
6843
7004
  });
6844
7005
  }
6845
7006
  });
7007
+ clientOptionalString = external_exports.string().nullish().transform((v) => v ?? void 0);
7008
+ clientOptionalBoolean = external_exports.boolean().nullish().transform((v) => v ?? void 0);
7009
+ appMessageSenderType = external_exports.enum(["user", "team"]);
7010
+ appMessageReceiverType = external_exports.enum(["user", "team", "agent", "assistant"]).transform((v) => v === "assistant" ? "agent" : v);
7011
+ appMessageAttachment = external_exports.object({
7012
+ file_name: external_exports.string(),
7013
+ file_binary: external_exports.string(),
7014
+ file_size: external_exports.number().nullish().transform((v) => v ?? void 0),
7015
+ file_extension: clientOptionalString
7016
+ });
7017
+ MAX_ATTACHMENTS_PER_MESSAGE = 20;
7018
+ appMessageBody = external_exports.object({
7019
+ // Message content — three historical aliases. All optional: an attachment-only
7020
+ // or voice-only message carries no text.
7021
+ content: clientOptionalString,
7022
+ message_text: clientOptionalString,
7023
+ message_body: clientOptionalString,
7024
+ // Conversation context. Ids are plain strings rather than `.uuid()` on purpose:
7025
+ // they are AUTHORIZED downstream, which is the stronger guarantee — a well-formed
7026
+ // uuid belonging to another tenant must fail just as hard as junk. `hub_id` is
7027
+ // gated by `assertHubEndUserAccess` (gh #3286) and `conversation_id` by HubDO's
7028
+ // conversation_index owner check (gh #2781, #3281). The route's own falsy guards
7029
+ // ('hub_id is required') still reject an empty one.
7030
+ hub_id: clientOptionalString,
7031
+ channel_id: clientOptionalString,
7032
+ conversation_id: clientOptionalString,
7033
+ hub_type: external_exports.enum(["chat", "task"]).nullish().transform((v) => v ?? void 0),
7034
+ // Routing.
7035
+ sender_type: appMessageSenderType.nullish().transform((v) => v ?? void 0),
7036
+ receiver_type: appMessageReceiverType.nullish().transform((v) => v ?? void 0),
7037
+ // Only meaningful on a team send, where `validateAppTeamSendContext` proves the
7038
+ // caller may send to this receiver. The end-user branch ignores it — see the
7039
+ // receiver derivation in the route.
7040
+ user_receiver_id: clientOptionalString,
7041
+ is_first_message: clientOptionalBoolean,
7042
+ end_conversation: clientOptionalBoolean,
7043
+ // Pre-generated by the client so the optimistic bubble and the stored row share
7044
+ // a key (transcription live-updates land on the same row instead of duplicating).
7045
+ message_id: clientOptionalString,
7046
+ attachments: external_exports.array(appMessageAttachment).max(MAX_ATTACHMENTS_PER_MESSAGE).nullish().transform((v) => v ?? void 0),
7047
+ // Base64-encoded audio for STT. Size-capped in the route (the cap is a byte
7048
+ // budget tied to the /channels/* bodyLimit, not a shape rule).
7049
+ audio_file: clientOptionalString
7050
+ });
6846
7051
  updateUserBody = external_exports.object({
6847
7052
  user_language: external_exports.string().optional(),
6848
7053
  ui_dark_mode: external_exports.boolean().optional(),
@@ -6965,7 +7170,7 @@ var init_dist = __esm({
6965
7170
  hub_type: external_exports.enum(["chat", "task"]).default("chat"),
6966
7171
  user_id: external_exports.string().optional()
6967
7172
  });
6968
- additionalContextPayloadSchema = external_exports.record(external_exports.unknown()).refine((r) => JSON.stringify(r).length <= 16384, {
7173
+ additionalContextPayloadSchema = external_exports.record(external_exports.unknown()).refine((r) => withinJsonLength(r, 16384), {
6969
7174
  message: "additional_context payload must be at most 16384 bytes when JSON-serialized"
6970
7175
  });
6971
7176
  kanbanUpdateBody = external_exports.object({
@@ -7225,6 +7430,7 @@ var init_dist = __esm({
7225
7430
  refineHubAsCodeCustomTools(config, ctx);
7226
7431
  refineHubAsCodeKanbanStatuses(config, ctx);
7227
7432
  refineHubAsCodeLanes(config, ctx);
7433
+ refineHubAsCodeEvals(config, ctx);
7228
7434
  });
7229
7435
  ciPullHubIdParam = external_exports.object({
7230
7436
  hub_id: ciUuidSchema
@@ -7352,7 +7558,7 @@ var init_dist = __esm({
7352
7558
  adminSetHubHarnessBody = external_exports.object({
7353
7559
  harness_enabled: external_exports.number().int().min(0).max(1)
7354
7560
  }).strict();
7355
- adminHarnessMassDestroyBody = external_exports.object({
7561
+ adminScopedTargetBody = external_exports.object({
7356
7562
  scope: external_exports.enum(["all", "org", "hub"]),
7357
7563
  org_id: external_exports.string().uuid().optional(),
7358
7564
  hub_id: external_exports.string().optional(),
@@ -9311,7 +9517,7 @@ async function exchangeCodeForTokens(authkitDomain, clientId, code, codeVerifier
9311
9517
  });
9312
9518
  if (!response.ok) {
9313
9519
  const body = await response.text();
9314
- throw new Error(`Token exchange failed (${response.status}): ${redactSecrets(body)}`);
9520
+ throw new Error(`Token exchange failed (${response.status}): ${maskSecretsInMessage(body)}`);
9315
9521
  }
9316
9522
  return response.json();
9317
9523
  }
@@ -9337,7 +9543,7 @@ async function refreshAccessToken(authkitDomain, clientId, refreshToken) {
9337
9543
  }
9338
9544
  if (isInvalidGrant) throw new Error("SESSION_EXPIRED");
9339
9545
  }
9340
- throw new Error(`Token refresh failed (${status}): ${redactSecrets(body)}`);
9546
+ throw new Error(`Token refresh failed (${status}): ${maskSecretsInMessage(body)}`);
9341
9547
  }
9342
9548
  return response.json();
9343
9549
  }
@@ -9469,7 +9675,7 @@ var init_auth = __esm({
9469
9675
  init_config();
9470
9676
  init_token_store();
9471
9677
  init_sentry();
9472
- init_redact();
9678
+ init_mask_secrets();
9473
9679
  OAUTH_CALLBACK_PORT = 3829;
9474
9680
  AUTHKIT_DOMAIN = "https://sprightly-comic-51.authkit.app";
9475
9681
  AUTHKIT_CLIENT_ID = "client_01KMZHB50KENM5SV90ZA80VXK4";
@@ -12016,6 +12222,18 @@ var init_diff = __esm({
12016
12222
  });
12017
12223
 
12018
12224
  // ../../packages/core/dist/contracts/index.js
12225
+ function jsonLengthOrNull2(value) {
12226
+ try {
12227
+ const json = JSON.stringify(value);
12228
+ return typeof json === "string" ? json.length : null;
12229
+ } catch {
12230
+ return null;
12231
+ }
12232
+ }
12233
+ function withinJsonLength2(value, max) {
12234
+ const length = jsonLengthOrNull2(value);
12235
+ return length !== null && length <= max;
12236
+ }
12019
12237
  function normalizeAuthType2(raw) {
12020
12238
  if (VALID_AUTH_TYPES3.has(raw)) return raw;
12021
12239
  return LEGACY_AUTH_TYPE_MAP3[raw] ?? raw;
@@ -12263,6 +12481,45 @@ function refineToolConfig2(value, ctx) {
12263
12481
  }
12264
12482
  }
12265
12483
  }
12484
+ function describeRole2(role) {
12485
+ if (typeof role === "string") {
12486
+ return JSON.stringify(role.length > ROLE_ECHO_MAX2 ? `${role.slice(0, ROLE_ECHO_MAX2)}\u2026` : role);
12487
+ }
12488
+ if (role === null) return "null";
12489
+ if (Array.isArray(role)) return "an array";
12490
+ if (typeof role === "object") return "an object";
12491
+ return `a ${typeof role}`;
12492
+ }
12493
+ function asEvalInputRecord2(input) {
12494
+ const value = typeof input === "string" ? (() => {
12495
+ try {
12496
+ return JSON.parse(input);
12497
+ } catch {
12498
+ return null;
12499
+ }
12500
+ })() : input;
12501
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
12502
+ }
12503
+ function evalInputRoleError2(input) {
12504
+ const record = asEvalInputRecord2(input);
12505
+ if (record === null) return null;
12506
+ const role = record.role;
12507
+ if (role === void 0 || role === null) return null;
12508
+ if (typeof role === "string" && EVAL_INPUT_ROLES2.includes(role)) {
12509
+ return null;
12510
+ }
12511
+ return `role must be ${EVAL_INPUT_ROLE_LIST2} (received ${describeRole2(role)}) \u2014 an eval trigger is what the responder answers, and an assistant or tool role gives it nothing to answer`;
12512
+ }
12513
+ function refineEvalMessageTextRole2(value, ctx) {
12514
+ const error = evalInputRoleError2(value.eval.message_text);
12515
+ if (error) {
12516
+ ctx.addIssue({
12517
+ code: external_exports.ZodIssueCode.custom,
12518
+ path: ["eval", "message_text", "role"],
12519
+ message: error
12520
+ });
12521
+ }
12522
+ }
12266
12523
  function refineHubAsCodeCustomTools2(config, ctx) {
12267
12524
  const agents = config.agents;
12268
12525
  if (!Array.isArray(agents)) return;
@@ -12354,6 +12611,22 @@ function refineHubAsCodeLanes2(config, ctx) {
12354
12611
  }
12355
12612
  }
12356
12613
  }
12614
+ function refineHubAsCodeEvals2(config, ctx) {
12615
+ const evals = config.evals;
12616
+ if (!Array.isArray(evals)) return;
12617
+ for (let e = 0; e < evals.length; e++) {
12618
+ const entry = evals[e];
12619
+ const error = evalInputRoleError2(entry?.input);
12620
+ if (error) {
12621
+ ctx.addIssue({
12622
+ code: external_exports.ZodIssueCode.custom,
12623
+ path: ["evals", e, "input", "role"],
12624
+ // Named, not just indexed — the YAML author has files, not an array.
12625
+ message: `eval "${entry?.name ?? "<unnamed>"}": ${error}`
12626
+ });
12627
+ }
12628
+ }
12629
+ }
12357
12630
  function isSafeTemplatePath2(path27) {
12358
12631
  if (path27.length === 0 || path27.length > 300) return false;
12359
12632
  if (path27.startsWith("/") || path27.includes("\\")) return false;
@@ -12392,7 +12665,7 @@ function isSanitizableSliceFile(path27) {
12392
12665
  function distinctUsesBackends(uses) {
12393
12666
  return [...new Set((uses ?? []).map((u) => u.backend))];
12394
12667
  }
12395
- var uuidSchema2, paginationSchema3, timestampSchema2, idParamSchema2, primaryRegionSchema2, placementSourceSchema2, orgIdParam2, orgAdminIdParam2, createOrganizationBody2, updateOrganizationBody2, addOrgAdminBody2, AUTH_TYPE3, ORG_CREDENTIAL_AUTH_TYPES3, AUTH_TYPE_DISPLAY3, LEGACY_AUTH_TYPE_MAP3, VALID_AUTH_TYPES3, AGENT_ROLES2, SAFE_USER_ID_REGEX2, SUPPORTED_LOCALES2, SUMMARIZATION_THRESHOLD_MIN2, SUMMARIZATION_THRESHOLD_MAX2, summarizationThresholdField2, monitorConfigField2, agentIdParam2, listAgentsQuery2, agentConnectionsQuery2, createAgentBody2, updateAgentBody2, AGENT_PARAMETER_TYPES2, AGENT_PARAMETER_NAME_REGEX2, agentParameterCreateSchema2, MAX_AGENT_PARAMETERS_PER_REQUEST2, createAgentParametersBody2, SLUG_REGEX2, slugSchema2, INVISIBLE_NAME_CHARS2, MAX_KANBAN_STATUSES2, MAX_FOLLOWUPS_PER_STATUS2, MAX_LANES2, MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES2, RESERVED_TEMPLATE_DUMP_NAME2, kanbanStatusSlugSchema2, followupSchema2, EXCLUSIVE_FLAG_PAIRS2, kanbanStatusSchema2, kanbanStatusesArraySchema2, laneSchema2, lanesArraySchema2, hubIdParam2, hubAdminIdParam2, hubUserIdParam2, hubIdentityIdParam2, hubTeamIdParam2, hubTeamUserDeleteParam2, hubSchemaQuery2, PREVIEW_LABEL_MAX_LENGTH2, previewLabelField2, createHubBody2, updateHubBody2, addHubAdminBody2, addHubIdentityAuthorizationBody2, contactDecisionBody2, approveContactBody2, listContactAccessQuery2, createHubTeamBody2, updateHubTeamBody2, addHubTeamUserBody2, reassignHubUserBody2, replicatePreviewBody2, claimCodeChannelParam2, claimCodeDeleteParam2, connectionIdParam2, connectorIdParam2, listConnectionsQuery2, deleteConnectionQuery2, addConnectionBody2, editConnectionBody2, PRODUCTION_DIRECT_FIELDS2, setProductionCredentialBody2, registerWhatsappQuery2, registerWhatsappBody2, retryProvisioningQuery2, resendDomainStatusQuery2, PLACEHOLDER_TOKENS2, ALLOWED_TYPES2, SUBSCHEMA_OBJECT_KEYWORDS2, SUBSCHEMA_LIST_KEYWORDS2, SUBSCHEMA_MAP_KEYWORDS2, MAX_SCHEMA_DEPTH2, toolIdParam2, listToolsQuery2, toolAgentQuery2, deleteToolQuery2, toolConnectionsQuery2, nativeToolIdSchema2, addNativeToolBody2, addMcpToolBody2, createCustomToolBody2, updateCustomToolBody2, updateToolExecutionConfigBody2, initialValueCreateSchema2, initialValueUpdateSchema2, stateIdParam2, listStatesQuery2, stateNameSchema2, createStateBody2, updateStateBody2, reorderStatesBody2, variantAiModeSchema2, experimentStatusSchema2, overlayUpdateSchema2, experimentIdParam2, variantIdParam2, listExperimentsQuery2, listVariantsQuery2, listOverridesQuery2, deleteOverrideQuery2, createExperimentBody2, updateExperimentBody2, setExperimentStatusBody2, createVariantBody2, updateVariantBody2, upsertOverrideBody2, orgTagIdParam2, listOrgTagsQuery2, createOrgTagBody2, updateOrgTagBody2, orgCredentialIdParam2, listOrgCredentialsQuery2, createOrgCredentialBody2, updateOrgCredentialBody2, orgResourceIdParam2, orgResourceFileIdParam2, orgResourceFolderIdParam2, hubOrgResourceParam2, listOrgResourcesQuery2, orgIdQuery2, createOrgResourceBody2, updateOrgResourceBody2, createOrgResourceFolderBody2, updateOrgResourceFolderBody2, uploadOrgResourceFileBody2, updateOrgResourceFileBody2, uploadOrgSkillZipBody2, linkOrgResourceBody2, resourceIdParam2, listResourcesQuery2, createResourceBody2, updateResourceBody2, syncSkillsBody2, resourceFileIdParam2, listResourceFilesQuery2, createResourceFileBody2, updateResourceFileBody2, uploadResourceFileBody2, uploadSkillZipBody2, resourceFolderIdParam2, listResourceFoldersQuery2, createResourceFolderBody2, updateResourceFolderBody2, agentResourceQuery2, hubResourceQuery2, linkAgentResourceBody2, updateAgentResourceBody2, unlinkAgentResourceQuery2, navItemSchema2, hubCountResetBody2, navItemCountResetBody2, typingBody2, analyticsHubIdParam2, analyticsVariableIdParam2, updateVariablePinBody2, updateAnalyticsViewBody2, NUMERIC_FILTER_OPS2, TEXT_FILTER_OPS2, CATEGORICAL_FILTER_OPS2, VARIABLE_FILTER_OPS2, STRUCTURED_QUERY_OPS2, STRUCTURED_QUERY_AGGREGATIONS2, filterValueSchema2, conversationsBody2, analyticsConversationIdParam2, messagesQuery2, conversationDetailDataQuery2, analyticsDataBody2, structuredQueryBody2, analyticsSqlBody2, analyticsSqlSchemaQuery2, EVAL_PACING_PRESET_NAMES2, PACING_INTERVAL_MIN_MS2, PACING_INTERVAL_MAX_MS2, EVAL_RUN_DEADLINE_MIN_MS2, EVAL_RUN_DEADLINE_MAX_MS2, paginationSchema22, evalIdParam2, sessionIdParam2, scenarioSetIdParam2, hubIdQuery2, createEvalBody2, updateEvalBody2, getEvalsQuery2, toggleEvalBody2, bulkToggleEvalsBody2, pacingConfigSchema2, sessionConfigSchema2, createSessionBody2, getSessionsQuery2, getSessionResultsQuery2, getSessionRunsQuery2, evalAnalyticsQuery2, getSessionCostQuery2, compareSessionsQuery2, evalsSqlBody2, evalsSqlSchemaQuery2, exportResultsQuery2, validateEvalBody2, hubAgentsQuery2, createScenarioSetBody2, updateScenarioSetBody2, scenarioSetsHubQuery2, createScenarioFromConversationBody2, createJourneyFromConversationBody2, journeyIdParam2, journeyToolCallSchema2, journeyTurnSchema2, journeyStepOverrideSchema2, fixtureField2, createJourneyBody2, updateJourneyBody2, getConversationsQuery2, getMessagesQuery2, updateUserBody2, updateProfileBody2, pathnameRegex2, updatePreferencesBody2, registerPushTokenBody2, deletePushTokenQuery2, activityQuery2, deletionModeSchema2, deletionRequestBody2, archiveHubIdParam2, archiveConversationParams2, archiveListQuery2, archiveMessageObservabilityParams2, conversationIdParam2, claimBody2, releaseBody2, transferBody2, closeBody2, additionalContextPayloadSchema2, kanbanUpdateBody2, annotateConversationBody2, observabilityParams2, observabilityListParams2, deleteUserConversationsBody2, sendMessageBody2, listConversationsQuery2, getConversationDetailParams2, getConversationDetailQuery2, listWhatsAppTemplatesQuery2, sendWhatsAppTemplateBody2, billingOrgIdParam2, subscriptionItemParams2, spendCapBody2, growthPacksBody2, portalSessionBody2, checkoutSessionBody2, updateBillingCurrencyBody2, invoicesQuery2, downloadBody2, uploadQuery2, signUrlBody2, outboundSchemaQuery2, templateIdParam2, listTemplatesQuery2, deleteTemplateQuery2, templateStatusQuery2, createTemplateBody2, updateTemplateBody2, submitTemplateBody2, testTemplateBody2, contactIdParam2, listContactsQuery2, createContactBody2, updateContactBody2, listIdParam2, listListsQuery2, listListContactsQuery2, createListBody2, updateListBody2, addListContactsBody2, removeListContactsBody2, scheduleIdParam2, listSchedulesQuery2, listExecutionsQuery2, createScheduleBody2, updateScheduleBody2, uuidPattern2, ciUuidSchema2, hubAsCodeConfigSchema2, ciPullHubIdParam2, ciBranchParam2, ciPullQuery2, ciHubsQuery2, ciLookupQuery2, ciBranchesQuery2, ciSyncBody2, ciPushBody2, ciDiffBody2, ciPublishBody2, ciPublishPreviewBody2, ciSyncMcpBody2, ciOrgResourcesParam2, orgResourcesConfigSchema2, ciOrgResourcesPushBody2, ciOrgResourcesDiffBody2, adminOrgIdParam2, adminOrgAdminIdParam2, adminUserIdParam2, adminPlanIdParam2, adminHubIdParam2, adminOrganizationsQuery2, adminUserSearchQuery2, kanbanSlugMigrationQuery2, adjustQuotaBody2, updatePlanBody2, addAdminUserBody2, updatePlatformConfigBody2, updateFreeOrgLimitBody2, adminSetOrgHarnessBody2, adminSetHubHarnessBody2, adminHarnessMassDestroyBody2, updatePricingPlanBody2, dataExplorerSearchQuery2, dataExplorerOrgIdParam2, dataExplorerHubIdParam2, dataExplorerConvIdParam2, dataExplorerDoInstancesQuery2, dataExplorerNsIdParam2, dataExplorerKvKeysQuery2, dataExplorerKvKeyParam2, uuidOrHexId2, dataExplorerDeleteOrgParam2, dataExplorerDeleteHubParam2, dataExplorerDeleteConvParam2, dataExplorerDeleteUserParam2, dataExplorerDeleteQuery2, dataExplorerKvDeleteQuery2, pitrDoNamespace2, pitrBookmarkParam2, pitrRestoreBody2, healthSamplingTriggerBody2, dataExplorerDebugDoType2, DEBUG_READ_MAX_LIMIT2, DEBUG_READ_DEFAULT_LIMIT2, DEBUG_DO_HEX_PREFIX2, debugDoEntityId2, debugTableName2, dataExplorerDebugTablesParam2, dataExplorerDebugRowsParam2, dataExplorerDebugRowsQuery2, dataExplorerDebugAnalyticsTable2, debugUuid2, dataExplorerDebugAnalyticsRowsParam2, dataExplorerDebugAnalyticsRowsQuery2, debugHubConvParam2, debugMessageIdQuery2, sandboxEgressPolicy2, SANDBOX_EXEC_MAX_CMD_LENGTH2, SANDBOX_EXEC_MAX_ALLOWLIST2, SANDBOX_EXEC_MAX_TIMEOUT_MS2, adminSandboxExecBody2, whatsappCallbackBody2, authMeResponse2, wsTicketResponse2, sessionCheckResponse2, logoutResponse2, magicCodeSendBody2, magicCodeSendResponse2, magicCodeVerifyBody2, magicCodeVerifyResponse2, browserParams2, browserFoldersQuery2, browserFilesQuery2, stateOperationBody2, conversationListResourcesQuery2, conversationReadResourceQuery2, listPendingSchedulesQuery2, listHubAggregateSchedulesQuery2, reportSourceSchema2, intakeReportSourceSchema2, reportClassificationSchema2, reportStatusSchema2, reportLocaleSchema2, reportMessageAuthorRoleSchema2, sentryRefStatusSchema2, createReportBody2, editReportBody2, contestReportBody2, reporterListQuery2, listReportsQuery2, GITHUB_ISSUE_URL_REGEX2, githubIssueUrlSchema2, transitionReportBody2, groupReportsBody2, holdReportBody2, clickhouseReadyResponse2, bootstrapQuery2, requestSnapshotChunkMessage2, MAX_NAME_LENGTH3, MAX_VALUE_LENGTH2, MAX_TAGS2, MAX_TAG_LENGTH2, MAX_SCOPE_HUBS2, MAX_SCOPE_TAGS2, vaultSecretScopeSchema2, vaultCreateBody2, vaultUpdateBody2, PERMISSIONS2, MAX_NAME_LENGTH22, MAX_HUBS_PER_GRANT2, MAX_HUB_TAGS_PER_GRANT2, MAX_GRANTS2, permissionEnum2, grantScopeSchema2, grantSchema2, createTokenBody2, tokenOrgIdParam2, tokenGrantScopeSchema2, tokenGrantSchema2, tokenMetadataSchema2, listTokensResponse2, createTokenResponse2, orgTokenSummarySchema2, listOrgTokensResponse2, invitePreviewQuery2, invitePreviewResponse2, discordTier2, discordBillingCycle2, discordMetadata2, discordOAuthStartResponse2, discordOAuthFinalizeBody2, discordOAuthFinalizeResponse2, discordDisconnectResponse2, jsonSchemaSchema2, hubUserIdentity2, stateValueEntry2, getHubUserContextResponse2, updateHubUserBody2, updateHubUserResponse2, unlockHubUserNameResponse2, stateResetParams2, stateResetResponse2, hubAlertsParam2, hubAlertSeverity2, hubAlert2, hubAlertsListResponse2, noticeSeveritySchema2, noticeStatusSchema2, NOTICE_SCOPE_REGEX2, noticeScopeSchema2, noticeLinkSchema2, createNoticeBody2, updateNoticeBody2, listNoticesQuery2, noticeIdParamSchema2, templateLocaleSchema2, TEMPLATE_SLUG_REGEX2, templateSlugSchema2, templateStatusSchema2, templateFileMapSchema2, TEMPLATE_INSTANCE_ID_KEYS, TEMPLATE_OPAQUE_BLOB_KEYS, TEMPLATE_AUTHOR_DATA_KEYS, templateTextSchema2, templateUsesEntrySchema2, templateUsesSchema2, templateYamlLocaleEntry2, templateYamlWayaiBlock2, templateTagsSchema2, templateYamlSchema2, templateHeroSchema2, templatePushLocaleSchema2, templatePushBody2, templateListQuery2, templateSlugParam2, templateDetailQuery2, ADMIN_SKILL_NAME_REGEX2, adminSkillNameParam2;
12668
+ var uuidSchema2, paginationSchema3, timestampSchema2, idParamSchema2, primaryRegionSchema2, placementSourceSchema2, orgIdParam2, orgAdminIdParam2, createOrganizationBody2, updateOrganizationBody2, addOrgAdminBody2, AUTH_TYPE3, ORG_CREDENTIAL_AUTH_TYPES3, AUTH_TYPE_DISPLAY3, LEGACY_AUTH_TYPE_MAP3, VALID_AUTH_TYPES3, AGENT_ROLES2, SAFE_USER_ID_REGEX2, SUPPORTED_LOCALES2, SUMMARIZATION_THRESHOLD_MIN2, SUMMARIZATION_THRESHOLD_MAX2, summarizationThresholdField2, monitorConfigField2, agentIdParam2, listAgentsQuery2, agentConnectionsQuery2, createAgentBody2, updateAgentBody2, AGENT_PARAMETER_TYPES2, AGENT_PARAMETER_NAME_REGEX2, agentParameterCreateSchema2, MAX_AGENT_PARAMETERS_PER_REQUEST2, createAgentParametersBody2, SLUG_REGEX2, slugSchema2, INVISIBLE_NAME_CHARS2, MAX_KANBAN_STATUSES2, MAX_FOLLOWUPS_PER_STATUS2, MAX_LANES2, MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES2, RESERVED_TEMPLATE_DUMP_NAME2, kanbanStatusSlugSchema2, followupSchema2, EXCLUSIVE_FLAG_PAIRS2, kanbanStatusSchema2, kanbanStatusesArraySchema2, laneSchema2, lanesArraySchema2, hubIdParam2, hubAdminIdParam2, hubUserIdParam2, hubIdentityIdParam2, hubTeamIdParam2, hubTeamUserDeleteParam2, hubSchemaQuery2, PREVIEW_LABEL_MAX_LENGTH2, MAX_ENDED_INDEX_RETENTION_DAYS2, previewLabelField2, createHubBody2, updateHubBody2, addHubAdminBody2, addHubIdentityAuthorizationBody2, contactDecisionBody2, approveContactBody2, listContactAccessQuery2, createHubTeamBody2, updateHubTeamBody2, addHubTeamUserBody2, reassignHubUserBody2, replicatePreviewBody2, updateChannelTestIdentitiesBody2, claimCodeChannelParam2, claimCodeDeleteParam2, connectionIdParam2, connectorIdParam2, listConnectionsQuery2, deleteConnectionQuery2, addConnectionBody2, editConnectionBody2, PRODUCTION_DIRECT_FIELDS2, setProductionCredentialBody2, registerWhatsappQuery2, registerWhatsappBody2, retryProvisioningQuery2, resendDomainStatusQuery2, PLACEHOLDER_TOKENS2, ALLOWED_TYPES2, SUBSCHEMA_OBJECT_KEYWORDS2, SUBSCHEMA_LIST_KEYWORDS2, SUBSCHEMA_MAP_KEYWORDS2, MAX_SCHEMA_DEPTH2, toolIdParam2, listToolsQuery2, toolAgentQuery2, deleteToolQuery2, toolConnectionsQuery2, nativeToolIdSchema2, addNativeToolBody2, addMcpToolBody2, createCustomToolBody2, updateCustomToolBody2, updateToolExecutionConfigBody2, initialValueCreateSchema2, initialValueUpdateSchema2, stateIdParam2, listStatesQuery2, stateNameSchema2, createStateBody2, updateStateBody2, reorderStatesBody2, variantAiModeSchema2, experimentStatusSchema2, overlayUpdateSchema2, experimentIdParam2, variantIdParam2, listExperimentsQuery2, listVariantsQuery2, listOverridesQuery2, deleteOverrideQuery2, createExperimentBody2, updateExperimentBody2, setExperimentStatusBody2, createVariantBody2, updateVariantBody2, upsertOverrideBody2, orgTagIdParam2, listOrgTagsQuery2, createOrgTagBody2, updateOrgTagBody2, orgCredentialIdParam2, listOrgCredentialsQuery2, createOrgCredentialBody2, updateOrgCredentialBody2, orgResourceIdParam2, orgResourceFileIdParam2, orgResourceFolderIdParam2, hubOrgResourceParam2, listOrgResourcesQuery2, orgIdQuery2, createOrgResourceBody2, updateOrgResourceBody2, createOrgResourceFolderBody2, updateOrgResourceFolderBody2, uploadOrgResourceFileBody2, updateOrgResourceFileBody2, uploadOrgSkillZipBody2, linkOrgResourceBody2, resourceIdParam2, listResourcesQuery2, createResourceBody2, updateResourceBody2, syncSkillsBody2, resourceFileIdParam2, listResourceFilesQuery2, createResourceFileBody2, updateResourceFileBody2, uploadResourceFileBody2, uploadSkillZipBody2, resourceFolderIdParam2, listResourceFoldersQuery2, createResourceFolderBody2, updateResourceFolderBody2, agentResourceQuery2, hubResourceQuery2, linkAgentResourceBody2, updateAgentResourceBody2, unlinkAgentResourceQuery2, navItemSchema2, hubCountResetBody2, navItemCountResetBody2, typingBody2, analyticsHubIdParam2, analyticsVariableIdParam2, updateVariablePinBody2, updateAnalyticsViewBody2, NUMERIC_FILTER_OPS2, TEXT_FILTER_OPS2, CATEGORICAL_FILTER_OPS2, VARIABLE_FILTER_OPS2, STRUCTURED_QUERY_OPS2, STRUCTURED_QUERY_AGGREGATIONS2, filterValueSchema2, conversationsBody2, analyticsConversationIdParam2, messagesQuery2, conversationDetailDataQuery2, analyticsDataBody2, structuredQueryBody2, analyticsSqlBody2, analyticsSqlSchemaQuery2, EVAL_PACING_PRESET_NAMES2, PACING_INTERVAL_MIN_MS2, PACING_INTERVAL_MAX_MS2, EVAL_RUN_DEADLINE_MIN_MS2, EVAL_RUN_DEADLINE_MAX_MS2, paginationSchema22, evalIdParam2, sessionIdParam2, scenarioSetIdParam2, hubIdQuery2, EVAL_INPUT_ROLES2, EVAL_INPUT_ROLE_LIST2, ROLE_ECHO_MAX2, createEvalBody2, updateEvalBody2, getEvalsQuery2, toggleEvalBody2, bulkToggleEvalsBody2, pacingConfigSchema2, sessionConfigSchema2, createSessionBody2, getSessionsQuery2, getSessionResultsQuery2, getSessionRunsQuery2, evalAnalyticsQuery2, getSessionCostQuery2, compareSessionsQuery2, evalsSqlBody2, evalsSqlSchemaQuery2, exportResultsQuery2, validateEvalBody2, hubAgentsQuery2, createScenarioSetBody2, updateScenarioSetBody2, scenarioSetsHubQuery2, createScenarioFromConversationBody2, createJourneyFromConversationBody2, journeyIdParam2, journeyToolCallSchema2, journeyTurnSchema2, journeyStepOverrideSchema2, fixtureField2, createJourneyBody2, updateJourneyBody2, getConversationsQuery2, getMessagesQuery2, clientOptionalString2, clientOptionalBoolean2, appMessageSenderType2, appMessageReceiverType2, appMessageAttachment2, MAX_ATTACHMENTS_PER_MESSAGE2, appMessageBody2, updateUserBody2, updateProfileBody2, pathnameRegex2, updatePreferencesBody2, registerPushTokenBody2, deletePushTokenQuery2, activityQuery2, deletionModeSchema2, deletionRequestBody2, archiveHubIdParam2, archiveConversationParams2, archiveListQuery2, archiveMessageObservabilityParams2, conversationIdParam2, claimBody2, releaseBody2, transferBody2, closeBody2, additionalContextPayloadSchema2, kanbanUpdateBody2, annotateConversationBody2, observabilityParams2, observabilityListParams2, deleteUserConversationsBody2, sendMessageBody2, listConversationsQuery2, getConversationDetailParams2, getConversationDetailQuery2, listWhatsAppTemplatesQuery2, sendWhatsAppTemplateBody2, billingOrgIdParam2, subscriptionItemParams2, spendCapBody2, growthPacksBody2, portalSessionBody2, checkoutSessionBody2, updateBillingCurrencyBody2, invoicesQuery2, downloadBody2, uploadQuery2, signUrlBody2, outboundSchemaQuery2, templateIdParam2, listTemplatesQuery2, deleteTemplateQuery2, templateStatusQuery2, createTemplateBody2, updateTemplateBody2, submitTemplateBody2, testTemplateBody2, contactIdParam2, listContactsQuery2, createContactBody2, updateContactBody2, listIdParam2, listListsQuery2, listListContactsQuery2, createListBody2, updateListBody2, addListContactsBody2, removeListContactsBody2, scheduleIdParam2, listSchedulesQuery2, listExecutionsQuery2, createScheduleBody2, updateScheduleBody2, uuidPattern2, ciUuidSchema2, hubAsCodeConfigSchema2, ciPullHubIdParam2, ciBranchParam2, ciPullQuery2, ciHubsQuery2, ciLookupQuery2, ciBranchesQuery2, ciSyncBody2, ciPushBody2, ciDiffBody2, ciPublishBody2, ciPublishPreviewBody2, ciSyncMcpBody2, ciOrgResourcesParam2, orgResourcesConfigSchema2, ciOrgResourcesPushBody2, ciOrgResourcesDiffBody2, adminOrgIdParam2, adminOrgAdminIdParam2, adminUserIdParam2, adminPlanIdParam2, adminHubIdParam2, adminOrganizationsQuery2, adminUserSearchQuery2, kanbanSlugMigrationQuery2, adjustQuotaBody2, updatePlanBody2, addAdminUserBody2, updatePlatformConfigBody2, updateFreeOrgLimitBody2, adminSetOrgHarnessBody2, adminSetHubHarnessBody2, adminScopedTargetBody2, updatePricingPlanBody2, dataExplorerSearchQuery2, dataExplorerOrgIdParam2, dataExplorerHubIdParam2, dataExplorerConvIdParam2, dataExplorerDoInstancesQuery2, dataExplorerNsIdParam2, dataExplorerKvKeysQuery2, dataExplorerKvKeyParam2, uuidOrHexId2, dataExplorerDeleteOrgParam2, dataExplorerDeleteHubParam2, dataExplorerDeleteConvParam2, dataExplorerDeleteUserParam2, dataExplorerDeleteQuery2, dataExplorerKvDeleteQuery2, pitrDoNamespace2, pitrBookmarkParam2, pitrRestoreBody2, healthSamplingTriggerBody2, dataExplorerDebugDoType2, DEBUG_READ_MAX_LIMIT2, DEBUG_READ_DEFAULT_LIMIT2, DEBUG_DO_HEX_PREFIX2, debugDoEntityId2, debugTableName2, dataExplorerDebugTablesParam2, dataExplorerDebugRowsParam2, dataExplorerDebugRowsQuery2, dataExplorerDebugAnalyticsTable2, debugUuid2, dataExplorerDebugAnalyticsRowsParam2, dataExplorerDebugAnalyticsRowsQuery2, debugHubConvParam2, debugMessageIdQuery2, sandboxEgressPolicy2, SANDBOX_EXEC_MAX_CMD_LENGTH2, SANDBOX_EXEC_MAX_ALLOWLIST2, SANDBOX_EXEC_MAX_TIMEOUT_MS2, adminSandboxExecBody2, whatsappCallbackBody2, authMeResponse2, wsTicketResponse2, sessionCheckResponse2, logoutResponse2, magicCodeSendBody2, magicCodeSendResponse2, magicCodeVerifyBody2, magicCodeVerifyResponse2, browserParams2, browserFoldersQuery2, browserFilesQuery2, stateOperationBody2, conversationListResourcesQuery2, conversationReadResourceQuery2, listPendingSchedulesQuery2, listHubAggregateSchedulesQuery2, reportSourceSchema2, intakeReportSourceSchema2, reportClassificationSchema2, reportStatusSchema2, reportLocaleSchema2, reportMessageAuthorRoleSchema2, sentryRefStatusSchema2, createReportBody2, editReportBody2, contestReportBody2, reporterListQuery2, listReportsQuery2, GITHUB_ISSUE_URL_REGEX2, githubIssueUrlSchema2, transitionReportBody2, groupReportsBody2, holdReportBody2, clickhouseReadyResponse2, bootstrapQuery2, requestSnapshotChunkMessage2, MAX_NAME_LENGTH3, MAX_VALUE_LENGTH2, MAX_TAGS2, MAX_TAG_LENGTH2, MAX_SCOPE_HUBS2, MAX_SCOPE_TAGS2, vaultSecretScopeSchema2, vaultCreateBody2, vaultUpdateBody2, PERMISSIONS2, MAX_NAME_LENGTH22, MAX_HUBS_PER_GRANT2, MAX_HUB_TAGS_PER_GRANT2, MAX_GRANTS2, permissionEnum2, grantScopeSchema2, grantSchema2, createTokenBody2, tokenOrgIdParam2, tokenGrantScopeSchema2, tokenGrantSchema2, tokenMetadataSchema2, listTokensResponse2, createTokenResponse2, orgTokenSummarySchema2, listOrgTokensResponse2, invitePreviewQuery2, invitePreviewResponse2, discordTier2, discordBillingCycle2, discordMetadata2, discordOAuthStartResponse2, discordOAuthFinalizeBody2, discordOAuthFinalizeResponse2, discordDisconnectResponse2, jsonSchemaSchema2, hubUserIdentity2, stateValueEntry2, getHubUserContextResponse2, updateHubUserBody2, updateHubUserResponse2, unlockHubUserNameResponse2, stateResetParams2, stateResetResponse2, hubAlertsParam2, hubAlertSeverity2, hubAlert2, hubAlertsListResponse2, noticeSeveritySchema2, noticeStatusSchema2, NOTICE_SCOPE_REGEX2, noticeScopeSchema2, noticeLinkSchema2, createNoticeBody2, updateNoticeBody2, listNoticesQuery2, noticeIdParamSchema2, templateLocaleSchema2, TEMPLATE_SLUG_REGEX2, templateSlugSchema2, templateStatusSchema2, templateFileMapSchema2, TEMPLATE_INSTANCE_ID_KEYS, TEMPLATE_OPAQUE_BLOB_KEYS, TEMPLATE_AUTHOR_DATA_KEYS, templateTextSchema2, templateUsesEntrySchema2, templateUsesSchema2, templateYamlLocaleEntry2, templateYamlWayaiBlock2, templateTagsSchema2, templateYamlSchema2, templateHeroSchema2, templatePushLocaleSchema2, templatePushBody2, templateListQuery2, templateSlugParam2, templateDetailQuery2, ADMIN_SKILL_NAME_REGEX2, adminSkillNameParam2;
12396
12669
  var init_contracts = __esm({
12397
12670
  "../../packages/core/dist/contracts/index.js"() {
12398
12671
  "use strict";
@@ -12443,6 +12716,7 @@ var init_contracts = __esm({
12443
12716
  init_zod();
12444
12717
  init_zod();
12445
12718
  init_zod();
12719
+ init_zod();
12446
12720
  uuidSchema2 = external_exports.string().uuid();
12447
12721
  paginationSchema3 = external_exports.object({
12448
12722
  limit: external_exports.coerce.number().int().min(1).max(100).default(50),
@@ -12655,7 +12929,7 @@ var init_contracts = __esm({
12655
12929
  eventName: external_exports.string().optional(),
12656
12930
  additional_instructions: external_exports.string().optional(),
12657
12931
  additional_context_schema: external_exports.record(external_exports.unknown()).refine(
12658
- (s) => JSON.stringify(s).length <= MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES2,
12932
+ (s) => withinJsonLength2(s, MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES2),
12659
12933
  `additional_context_schema must be at most ${MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES2} bytes when JSON-serialized`
12660
12934
  ).optional(),
12661
12935
  followups: external_exports.array(followupSchema2).max(MAX_FOLLOWUPS_PER_STATUS2, `followups must have at most ${MAX_FOLLOWUPS_PER_STATUS2} entries`).optional(),
@@ -12790,6 +13064,7 @@ var init_contracts = __esm({
12790
13064
  hubTeamUserDeleteParam2 = external_exports.object({ id: uuidSchema2, teamUserId: uuidSchema2 });
12791
13065
  hubSchemaQuery2 = external_exports.object({ hub_id: uuidSchema2 });
12792
13066
  PREVIEW_LABEL_MAX_LENGTH2 = 60;
13067
+ MAX_ENDED_INDEX_RETENTION_DAYS2 = 730;
12793
13068
  previewLabelField2 = external_exports.string().max(PREVIEW_LABEL_MAX_LENGTH2).optional().nullable().transform((v) => {
12794
13069
  if (v == null) return null;
12795
13070
  const trimmed = v.trim();
@@ -12817,8 +13092,14 @@ var init_contracts = __esm({
12817
13092
  // persisted via the agent path (.passthrough() agent body → HubDO column), not here.
12818
13093
  auto_close_inactive_days: external_exports.number().int().min(1).max(180).optional(),
12819
13094
  // Per-hub ConversationDO retention window (days) — keeps an ended conversation's DO
12820
- // alive for post-hoc annotation. Default 7, max 30 (= ENDED_INDEX_RETENTION_DAYS).
13095
+ // alive for post-hoc annotation. Default 7, max 30 — the floor of the retention
13096
+ // chain (≤ ended_index_retention_days ≤ effective storage retention).
12821
13097
  conversation_retention_days: external_exports.number().int().min(1).max(30).optional(),
13098
+ // Per-hub ended-conversation index retention window (days) — how long the warm
13099
+ // "Ended" tab + chat-hub continuous history serve a closed conversation before
13100
+ // the cleanup cron reaps its index row. Absent → DEFAULT_ENDED_INDEX_RETENTION_DAYS
13101
+ // (365). Re-clamped to the effective storage retention at reap time.
13102
+ ended_index_retention_days: external_exports.number().int().min(1).max(MAX_ENDED_INDEX_RETENTION_DAYS2).optional(),
12822
13103
  // Channel contact access control. Enum-validated explicitly (not via passthrough)
12823
13104
  // so `language`/`access_approval_role` can't reach the DB with an invalid value.
12824
13105
  language: external_exports.enum(["en", "pt", "es"]).optional(),
@@ -12874,6 +13155,9 @@ var init_contracts = __esm({
12874
13155
  replicatePreviewBody2 = external_exports.object({
12875
13156
  preview_label: previewLabelField2
12876
13157
  });
13158
+ updateChannelTestIdentitiesBody2 = external_exports.object({
13159
+ test_identities: external_exports.array(external_exports.string().max(320)).max(1e3)
13160
+ });
12877
13161
  claimCodeChannelParam2 = external_exports.object({
12878
13162
  id: uuidSchema2,
12879
13163
  channelId: uuidSchema2
@@ -13524,12 +13808,15 @@ var init_contracts = __esm({
13524
13808
  hubIdQuery2 = external_exports.object({
13525
13809
  hub_id: external_exports.string().uuid()
13526
13810
  });
13811
+ EVAL_INPUT_ROLES2 = ["user", "system"];
13812
+ EVAL_INPUT_ROLE_LIST2 = EVAL_INPUT_ROLES2.map((r) => `"${r}"`).join(" or ");
13813
+ ROLE_ECHO_MAX2 = 40;
13527
13814
  createEvalBody2 = external_exports.object({
13528
13815
  eval: external_exports.record(external_exports.unknown())
13529
- });
13816
+ }).superRefine(refineEvalMessageTextRole2);
13530
13817
  updateEvalBody2 = external_exports.object({
13531
13818
  eval: external_exports.record(external_exports.unknown())
13532
- });
13819
+ }).superRefine(refineEvalMessageTextRole2);
13533
13820
  getEvalsQuery2 = external_exports.object({
13534
13821
  hub_id: external_exports.string().uuid(),
13535
13822
  agent_id: external_exports.string().uuid().optional(),
@@ -13701,18 +13988,21 @@ var init_contracts = __esm({
13701
13988
  hub_user_id: external_exports.string().optional(),
13702
13989
  search_filter: external_exports.string().optional(),
13703
13990
  hub_id: external_exports.string().uuid().optional(),
13991
+ // NON-authorizing single-hub narrow. Unlike `hub_id` (which runs the
13992
+ // grant-gated `loadHub('hub:read')` and so throws for grant-less end users /
13993
+ // team members), `scope_hub_id` INTERSECTS the caller's already-resolved hub
13994
+ // roster server-side. Intersecting the caller's own roster IS the
13995
+ // authorization — a hub the caller isn't in narrows to empty and leaks
13996
+ // nothing. Continuous history sends it to take the single-hub ended-index
13997
+ // path (one HubDO read, accurate uncapped total) instead of the all-hub
13998
+ // fan-out it would otherwise discard client-side (gh #3319).
13999
+ scope_hub_id: external_exports.string().uuid().optional(),
13704
14000
  conversation_id: external_exports.string().uuid().optional(),
13705
14001
  // 'ended' = recently-closed, served warm from the HubDO index (≤ retention
13706
14002
  // window). 'archived' = the full closed-conversation history from ClickHouse.
13707
14003
  status: external_exports.enum(["active", "agent", "team", "ended", "archived"]).optional(),
13708
14004
  page: external_exports.string().regex(/^\d+$/).optional(),
13709
- page_size: external_exports.string().regex(/^\d+$/).optional(),
13710
- // Cursor for the continuous-history scroll (chat hubs): with status='archived',
13711
- // return only conversations that ended strictly before this instant. The caller
13712
- // passes the oldest warm-index `ended_at` so the CH superset excludes the
13713
- // already-loaded warm slice. UTC ISO-8601 (Timestamps standard) — datetime()
13714
- // hardens it before it reaches the parameterized CH predicate.
13715
- before_ended_at: external_exports.string().datetime().optional()
14005
+ page_size: external_exports.string().regex(/^\d+$/).optional()
13716
14006
  });
13717
14007
  getMessagesQuery2 = external_exports.object({
13718
14008
  hub_id: external_exports.string().uuid(),
@@ -13728,8 +14018,7 @@ var init_contracts = __esm({
13728
14018
  // Keyset cursor for the newest-first scroll (`page` absent): return only
13729
14019
  // messages strictly older than (before_created_at, before_message_id) — the
13730
14020
  // oldest currently-loaded VISIBLE message. UTC ISO-8601 (Timestamps standard);
13731
- // `datetime()` hardens it before the parameterized DO predicate. Mirrors the
13732
- // `before_ended_at` cursor precedent above.
14021
+ // `datetime()` hardens it before the parameterized DO predicate.
13733
14022
  before_created_at: external_exports.string().datetime().optional(),
13734
14023
  before_message_id: external_exports.string().uuid().optional(),
13735
14024
  /**
@@ -13748,6 +14037,50 @@ var init_contracts = __esm({
13748
14037
  });
13749
14038
  }
13750
14039
  });
14040
+ clientOptionalString2 = external_exports.string().nullish().transform((v) => v ?? void 0);
14041
+ clientOptionalBoolean2 = external_exports.boolean().nullish().transform((v) => v ?? void 0);
14042
+ appMessageSenderType2 = external_exports.enum(["user", "team"]);
14043
+ appMessageReceiverType2 = external_exports.enum(["user", "team", "agent", "assistant"]).transform((v) => v === "assistant" ? "agent" : v);
14044
+ appMessageAttachment2 = external_exports.object({
14045
+ file_name: external_exports.string(),
14046
+ file_binary: external_exports.string(),
14047
+ file_size: external_exports.number().nullish().transform((v) => v ?? void 0),
14048
+ file_extension: clientOptionalString2
14049
+ });
14050
+ MAX_ATTACHMENTS_PER_MESSAGE2 = 20;
14051
+ appMessageBody2 = external_exports.object({
14052
+ // Message content — three historical aliases. All optional: an attachment-only
14053
+ // or voice-only message carries no text.
14054
+ content: clientOptionalString2,
14055
+ message_text: clientOptionalString2,
14056
+ message_body: clientOptionalString2,
14057
+ // Conversation context. Ids are plain strings rather than `.uuid()` on purpose:
14058
+ // they are AUTHORIZED downstream, which is the stronger guarantee — a well-formed
14059
+ // uuid belonging to another tenant must fail just as hard as junk. `hub_id` is
14060
+ // gated by `assertHubEndUserAccess` (gh #3286) and `conversation_id` by HubDO's
14061
+ // conversation_index owner check (gh #2781, #3281). The route's own falsy guards
14062
+ // ('hub_id is required') still reject an empty one.
14063
+ hub_id: clientOptionalString2,
14064
+ channel_id: clientOptionalString2,
14065
+ conversation_id: clientOptionalString2,
14066
+ hub_type: external_exports.enum(["chat", "task"]).nullish().transform((v) => v ?? void 0),
14067
+ // Routing.
14068
+ sender_type: appMessageSenderType2.nullish().transform((v) => v ?? void 0),
14069
+ receiver_type: appMessageReceiverType2.nullish().transform((v) => v ?? void 0),
14070
+ // Only meaningful on a team send, where `validateAppTeamSendContext` proves the
14071
+ // caller may send to this receiver. The end-user branch ignores it — see the
14072
+ // receiver derivation in the route.
14073
+ user_receiver_id: clientOptionalString2,
14074
+ is_first_message: clientOptionalBoolean2,
14075
+ end_conversation: clientOptionalBoolean2,
14076
+ // Pre-generated by the client so the optimistic bubble and the stored row share
14077
+ // a key (transcription live-updates land on the same row instead of duplicating).
14078
+ message_id: clientOptionalString2,
14079
+ attachments: external_exports.array(appMessageAttachment2).max(MAX_ATTACHMENTS_PER_MESSAGE2).nullish().transform((v) => v ?? void 0),
14080
+ // Base64-encoded audio for STT. Size-capped in the route (the cap is a byte
14081
+ // budget tied to the /channels/* bodyLimit, not a shape rule).
14082
+ audio_file: clientOptionalString2
14083
+ });
13751
14084
  updateUserBody2 = external_exports.object({
13752
14085
  user_language: external_exports.string().optional(),
13753
14086
  ui_dark_mode: external_exports.boolean().optional(),
@@ -13870,7 +14203,7 @@ var init_contracts = __esm({
13870
14203
  hub_type: external_exports.enum(["chat", "task"]).default("chat"),
13871
14204
  user_id: external_exports.string().optional()
13872
14205
  });
13873
- additionalContextPayloadSchema2 = external_exports.record(external_exports.unknown()).refine((r) => JSON.stringify(r).length <= 16384, {
14206
+ additionalContextPayloadSchema2 = external_exports.record(external_exports.unknown()).refine((r) => withinJsonLength2(r, 16384), {
13874
14207
  message: "additional_context payload must be at most 16384 bytes when JSON-serialized"
13875
14208
  });
13876
14209
  kanbanUpdateBody2 = external_exports.object({
@@ -14130,6 +14463,7 @@ var init_contracts = __esm({
14130
14463
  refineHubAsCodeCustomTools2(config, ctx);
14131
14464
  refineHubAsCodeKanbanStatuses2(config, ctx);
14132
14465
  refineHubAsCodeLanes2(config, ctx);
14466
+ refineHubAsCodeEvals2(config, ctx);
14133
14467
  });
14134
14468
  ciPullHubIdParam2 = external_exports.object({
14135
14469
  hub_id: ciUuidSchema2
@@ -14257,7 +14591,7 @@ var init_contracts = __esm({
14257
14591
  adminSetHubHarnessBody2 = external_exports.object({
14258
14592
  harness_enabled: external_exports.number().int().min(0).max(1)
14259
14593
  }).strict();
14260
- adminHarnessMassDestroyBody2 = external_exports.object({
14594
+ adminScopedTargetBody2 = external_exports.object({
14261
14595
  scope: external_exports.enum(["all", "org", "hub"]),
14262
14596
  org_id: external_exports.string().uuid().optional(),
14263
14597
  hub_id: external_exports.string().optional(),
@@ -19161,6 +19495,20 @@ async function adminCommand(args2) {
19161
19495
  process.exit(1);
19162
19496
  }
19163
19497
  }
19498
+ if (group === "hubs") {
19499
+ if (!sub) {
19500
+ printHelp2();
19501
+ process.exit(1);
19502
+ }
19503
+ switch (sub) {
19504
+ case "repair-team-orphans":
19505
+ await runRepairTeamOrphans(flagArgs);
19506
+ return;
19507
+ default:
19508
+ printHelp2();
19509
+ process.exit(1);
19510
+ }
19511
+ }
19164
19512
  if (group === "harness") {
19165
19513
  if (!sub) {
19166
19514
  printHelp2();
@@ -19820,8 +20168,7 @@ async function runSandboxExec(positional, flagArgs) {
19820
20168
  process.exit(data.exit_code);
19821
20169
  }
19822
20170
  }
19823
- async function runHarnessMassDestroy(flagArgs) {
19824
- const USAGE = "wayai admin harness mass-destroy --all | --org <org_id> | --hub <hub_id> [--dry-run] [--yes] [--json]";
20171
+ function parseScopedTargetFlags(flagArgs, usage2) {
19825
20172
  let all = false;
19826
20173
  let orgId;
19827
20174
  let hubId;
@@ -19854,24 +20201,69 @@ async function runHarnessMassDestroy(flagArgs) {
19854
20201
  process.exit(1);
19855
20202
  }
19856
20203
  }
19857
- const selectorCount = (all ? 1 : 0) + (orgId ? 1 : 0) + (hubId ? 1 : 0);
19858
- if (selectorCount !== 1) {
20204
+ if ((all ? 1 : 0) + (orgId ? 1 : 0) + (hubId ? 1 : 0) !== 1) {
19859
20205
  console.error("Provide exactly ONE of --all, --org <org_id>, or --hub <hub_id>.");
19860
- console.error(USAGE);
20206
+ console.error(usage2);
19861
20207
  process.exit(1);
19862
20208
  }
19863
- let body;
19864
- let targetLabel;
19865
20209
  if (all) {
19866
- body = { scope: "all", dry_run: dryRun };
19867
- targetLabel = "ALL hubs (platform-wide)";
19868
- } else if (orgId) {
19869
- body = { scope: "org", org_id: orgId, dry_run: dryRun };
19870
- targetLabel = `org ${orgId}`;
19871
- } else {
19872
- body = { scope: "hub", hub_id: hubId, dry_run: dryRun };
19873
- targetLabel = `hub ${hubId}`;
20210
+ return { body: { scope: "all", dry_run: dryRun }, targetLabel: "ALL hubs (platform-wide)", dryRun, yes, jsonOutput };
20211
+ }
20212
+ if (orgId) {
20213
+ return { body: { scope: "org", org_id: orgId, dry_run: dryRun }, targetLabel: `org ${orgId}`, dryRun, yes, jsonOutput };
19874
20214
  }
20215
+ return { body: { scope: "hub", hub_id: hubId, dry_run: dryRun }, targetLabel: `hub ${hubId}`, dryRun, yes, jsonOutput };
20216
+ }
20217
+ async function runRepairTeamOrphans(flagArgs) {
20218
+ const USAGE = "wayai admin hubs repair-team-orphans --all | --org <org_id> | --hub <hub_id> [--dry-run] [--yes] [--json]";
20219
+ const { body, targetLabel, dryRun, yes, jsonOutput } = parseScopedTargetFlags(flagArgs, USAGE);
20220
+ if (!dryRun && !yes && !jsonOutput) {
20221
+ console.log(`About to PURGE dangling team references in: ${targetLabel}.`);
20222
+ console.log("Memberships pointing at a deleted team are removed (HubDO + UserDO mirror); conversations pinned to one are unassigned.");
20223
+ console.log("Run with --dry-run first to see what would change.");
20224
+ const ok = await confirm("Proceed?");
20225
+ if (!ok) {
20226
+ console.log("Aborted.");
20227
+ return;
20228
+ }
20229
+ }
20230
+ const { config, accessToken } = await requireAuth();
20231
+ const client = new ApiClient({ apiUrl: config.api_url, accessToken });
20232
+ let response;
20233
+ try {
20234
+ response = await client.adminRepairTeamOrphans(body);
20235
+ } catch (err) {
20236
+ exitOnApiError(err);
20237
+ throw err;
20238
+ }
20239
+ const data = response.data;
20240
+ if (jsonOutput) {
20241
+ console.log(JSON.stringify(data, null, 2));
20242
+ return;
20243
+ }
20244
+ const mode = data.dry_run ? "DRY RUN \u2014 nothing written" : "repaired";
20245
+ console.log(
20246
+ `repair-team-orphans (${data.scope}) \u2014 ${mode}: hubs_scanned=${data.hubs_scanned} hubs_repaired=${data.hubs_repaired} team_users_removed=${data.team_users_removed}`
20247
+ );
20248
+ if (data.hubs_errored > 0 || data.orgs_errored > 0) {
20249
+ console.log(
20250
+ `WARNING: ${data.orgs_errored} org(s) and ${data.hubs_errored} hub(s) errored and were SKIPPED \u2014 re-run to cover them.`
20251
+ );
20252
+ }
20253
+ if (data.details.length === 0) {
20254
+ console.log("(no dangling team references in scope)");
20255
+ return;
20256
+ }
20257
+ console.log("");
20258
+ console.log("hub_id | dangling_team_ids | team_users_removed");
20259
+ console.log("-------+-------------------+-------------------");
20260
+ for (const d of data.details) {
20261
+ console.log(`${d.hub_id} | ${d.dangling_team_ids.join(",")} | ${d.team_users_removed}`);
20262
+ }
20263
+ }
20264
+ async function runHarnessMassDestroy(flagArgs) {
20265
+ const USAGE = "wayai admin harness mass-destroy --all | --org <org_id> | --hub <hub_id> [--dry-run] [--yes] [--json]";
20266
+ const { body, targetLabel, dryRun, yes, jsonOutput } = parseScopedTargetFlags(flagArgs, USAGE);
19875
20267
  if (!dryRun && !yes && !jsonOutput) {
19876
20268
  console.log(`About to REAP every live harness sandbox / token / slot in: ${targetLabel}.`);
19877
20269
  console.log("This destroys running sandboxes and revokes their tokens. Run with --dry-run first to see the blast radius.");
@@ -19899,9 +20291,9 @@ async function runHarnessMassDestroy(flagArgs) {
19899
20291
  console.log(
19900
20292
  `harness mass-destroy (${data.scope}) \u2014 ${mode}: hubs_scanned=${data.hubs_scanned} sessions_found=${data.sessions_found} sessions_reaped=${data.sessions_reaped} sandboxes_destroyed=${data.sandboxes_destroyed}`
19901
20293
  );
19902
- if (data.hubs_errored > 0 || data.sessions_errored > 0) {
20294
+ if (data.orgs_errored > 0 || data.hubs_errored > 0 || data.sessions_errored > 0) {
19903
20295
  console.log(
19904
- `WARNING: ${data.hubs_errored} hub(s) and ${data.sessions_errored} session(s) errored and were SKIPPED \u2014 re-run to cover them.`
20296
+ `WARNING: ${data.orgs_errored} org(s), ${data.hubs_errored} hub(s) and ${data.sessions_errored} session(s) errored and were SKIPPED \u2014 re-run to cover them.`
19905
20297
  );
19906
20298
  }
19907
20299
  if (data.details.length === 0) {
@@ -20438,6 +20830,9 @@ Usage:
20438
20830
  wayai admin sandbox exec [--cmd "<c>" | <c>] --hub <id> --connection <id> [--egress open|allowlist|isolated] [--allow <host> ...] [--timeout <ms>] [--json]
20439
20831
  Run one shell command in a fresh E2B sandbox (create \u2192 run \u2192 destroy) to test the sandbox driver + egress gate
20440
20832
 
20833
+ wayai admin hubs repair-team-orphans --all | --org <org_id> | --hub <hub_id> [--dry-run] [--yes] [--json]
20834
+ Purge hub_team_id references left dangling by a pre-cascade team deletion (silently empties a support agent's queue). Idempotent \u2014 run --dry-run first
20835
+
20441
20836
  wayai admin harness disable [--org <org_id> | --hub <hub_id>]
20442
20837
  Flip harness_enabled OFF. No scope = platform (break-glass: per-turn kill switch aborts each harness turn on its next invocation); --org/--hub target that layer of the three-layer rollout gate
20443
20838
  wayai admin harness enable [--org <org_id> | --hub <hub_id>]
@@ -20468,6 +20863,13 @@ Sources:
20468
20863
  "Gemini degraded" / "Analytics delayed" notices. \`create\` authors one
20469
20864
  (severity defaults to info, scope to global); \`list\` reads them
20470
20865
  (--status active|resolved); \`resolve\` ends an active notice.
20866
+ hubs Hub data repair. \`repair-team-orphans\` purges hub_team_id references left
20867
+ dangling by a team deletion that predates the deleteHubTeam cascade (a
20868
+ \`wayai push\` / hub-sync that replaced a hub's teams orphaned its
20869
+ memberships). A dangling membership resolves to an EMPTY support scope, so
20870
+ its owner's Support list silently goes blank; a conversation pinned to a
20871
+ deleted team goes invisible to everyone. Idempotent \u2014 a healthy hub writes
20872
+ nothing, so re-running and --all are both safe.
20471
20873
  sandbox Run arbitrary code in a fresh E2B sandbox (harness-agents isolation surface).
20472
20874
  \`exec\` provisions a sandbox from a named Sandbox connection, runs one
20473
20875
  command, and destroys it. Egress omitted \u21D2 deny-all (fail-closed); opt up
@@ -21022,7 +21424,7 @@ function friendlyHint(err) {
21022
21424
  }
21023
21425
 
21024
21426
  // src/index.ts
21025
- init_redact();
21427
+ init_mask_secrets();
21026
21428
  init_utils();
21027
21429
 
21028
21430
  // src/lib/version-refresh.ts
@@ -21516,7 +21918,7 @@ async function runForeground() {
21516
21918
  captureException2(err);
21517
21919
  }
21518
21920
  await closeSentry();
21519
- console.error(redactSecrets(err instanceof Error ? err.message : String(err)));
21921
+ console.error(maskSecretsInMessage(err instanceof Error ? err.message : String(err)));
21520
21922
  const hint = friendlyHint(err);
21521
21923
  if (hint) console.error(hint);
21522
21924
  process.exit(1);