@wayai/cli 0.3.64 → 0.3.66

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
@@ -7809,6 +7809,9 @@ function resolveLayout(gitRoot, layout = WAYAI_LAYOUT) {
7809
7809
  legacyAlsoPresent: false
7810
7810
  };
7811
7811
  }
7812
+ function resolveHubsDir(gitRoot) {
7813
+ return resolveLayout(gitRoot).hubsDir;
7814
+ }
7812
7815
  function resolveTemplatesDir(gitRoot) {
7813
7816
  return path.join(gitRoot, TEMPLATES_AUTHORING_SUBDIR);
7814
7817
  }
@@ -7935,7 +7938,7 @@ function getHubFolderSlug(hubName, hubEnvironment, hubId, previewLabel, branchNa
7935
7938
  const base = slugify(hubName);
7936
7939
  if (hubEnvironment !== "preview") return base;
7937
7940
  const suffix = previewLabel || branchName || hubId.slice(0, 8);
7938
- return `${base}-${slugify(suffix)}`;
7941
+ return `${base}--${slugify(suffix)}`;
7939
7942
  }
7940
7943
  function resolveHubFolder(workspaceDir, hubId, hubName, hubEnvironment, previewLabel, branchName) {
7941
7944
  if (hubId) {
@@ -7958,6 +7961,16 @@ function findHubByFolderName(workspaceDir, hubFolderName) {
7958
7961
  const all = scanWorkspaceHubs(workspaceDir);
7959
7962
  return all.find((h) => path2.basename(h.hubFolder) === hubFolderName) ?? null;
7960
7963
  }
7964
+ function resolveHubFolderBySelector(hubsDir, selector) {
7965
+ const asPath = path2.resolve(selector);
7966
+ if (isDirectory(asPath) && fs2.existsSync(path2.join(asPath, "hub.yaml"))) return asPath;
7967
+ if (UUID_RE.test(selector)) {
7968
+ const match = scanWorkspaceHubs(hubsDir).find((h) => h.hubId === selector);
7969
+ return match ? match.hubFolder : null;
7970
+ }
7971
+ const byName = findHubByFolderName(hubsDir, selector);
7972
+ return byName ? byName.hubFolder : null;
7973
+ }
7961
7974
  function autoRenameHubFolder(currentFolder, hubName, hubEnvironment, hubId, previewLabel, branchName) {
7962
7975
  const expectedSlug = getHubFolderSlug(hubName, hubEnvironment, hubId, previewLabel, branchName);
7963
7976
  const currentSlug = path2.basename(currentFolder);
@@ -13278,10 +13291,37 @@ function isSafeTemplatePath2(path22) {
13278
13291
  (seg) => seg.length > 0 && seg !== "." && seg !== ".." && /^[A-Za-z0-9._-]+$/.test(seg)
13279
13292
  );
13280
13293
  }
13294
+ function dropTemplateKeys(value, drop) {
13295
+ if (Array.isArray(value)) return value.map((v) => dropTemplateKeys(v, drop));
13296
+ if (isPlainObject(value)) {
13297
+ const out = {};
13298
+ for (const [key, child] of Object.entries(value)) {
13299
+ if (drop.has(key)) continue;
13300
+ out[key] = TEMPLATE_OPAQUE_BLOB_KEYS.has(key) ? child : dropTemplateKeys(child, drop);
13301
+ }
13302
+ return out;
13303
+ }
13304
+ return value;
13305
+ }
13306
+ function stripTemplateInstanceIds(value) {
13307
+ return dropTemplateKeys(value, TEMPLATE_INSTANCE_ID_KEYS);
13308
+ }
13309
+ function excludeTemplateAuthorData(value) {
13310
+ return dropTemplateKeys(value, TEMPLATE_AUTHOR_DATA_KEYS);
13311
+ }
13312
+ function isPlainObject(value) {
13313
+ if (value === null || typeof value !== "object") return false;
13314
+ const proto = Object.getPrototypeOf(value);
13315
+ return proto === Object.prototype || proto === null;
13316
+ }
13317
+ function isSanitizableSliceFile(path22) {
13318
+ if (!/\.ya?ml$/i.test(path22)) return false;
13319
+ return path22 !== "resources" && !path22.startsWith("resources/");
13320
+ }
13281
13321
  function distinctUsesBackends(uses) {
13282
13322
  return [...new Set((uses ?? []).map((u) => u.backend))];
13283
13323
  }
13284
- var uuidSchema2, paginationSchema3, timestampSchema2, idParamSchema2, primaryRegionSchema2, placementSourceSchema2, orgIdParam2, orgAdminIdParam2, createOrganizationBody2, updateOrganizationBody2, addOrgAdminBody2, AUTH_TYPE2, ORG_CREDENTIAL_AUTH_TYPES2, AUTH_TYPE_DISPLAY2, LEGACY_AUTH_TYPE_MAP2, VALID_AUTH_TYPES2, 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, createHubBody2, updateHubBody2, addHubAdminBody2, addHubIdentityAuthorizationBody2, contactDecisionBody2, approveContactBody2, listContactAccessQuery2, createHubTeamBody2, updateHubTeamBody2, addHubTeamUserBody2, reassignHubUserBody2, replicatePreviewBody2, claimCodeChannelParam2, claimCodeDeleteParam2, connectionIdParam2, connectorIdParam2, listConnectionsQuery2, deleteConnectionQuery2, addConnectionBody2, editConnectionBody2, 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, 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, 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, completionsBody2, 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, adminOrganizationsQuery2, adminUserSearchQuery2, kanbanSlugMigrationQuery2, adjustQuotaBody2, updatePlanBody2, addAdminUserBody2, updatePlatformConfigBody2, updateFreeOrgLimitBody2, 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, 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, templateTextSchema2, templateUsesEntrySchema2, templateUsesSchema2, templateYamlLocaleEntry2, templateYamlWayaiBlock2, templateTagsSchema2, templateYamlSchema2, templateHeroSchema2, templatePushLocaleSchema2, templatePushBody2, templateListQuery2, templateSlugParam2, templateDetailQuery2, ADMIN_SKILL_NAME_REGEX2, adminSkillNameParam2;
13324
+ var uuidSchema2, paginationSchema3, timestampSchema2, idParamSchema2, primaryRegionSchema2, placementSourceSchema2, orgIdParam2, orgAdminIdParam2, createOrganizationBody2, updateOrganizationBody2, addOrgAdminBody2, AUTH_TYPE2, ORG_CREDENTIAL_AUTH_TYPES2, AUTH_TYPE_DISPLAY2, LEGACY_AUTH_TYPE_MAP2, VALID_AUTH_TYPES2, 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, createHubBody2, updateHubBody2, addHubAdminBody2, addHubIdentityAuthorizationBody2, contactDecisionBody2, approveContactBody2, listContactAccessQuery2, createHubTeamBody2, updateHubTeamBody2, addHubTeamUserBody2, reassignHubUserBody2, replicatePreviewBody2, claimCodeChannelParam2, claimCodeDeleteParam2, connectionIdParam2, connectorIdParam2, listConnectionsQuery2, deleteConnectionQuery2, addConnectionBody2, editConnectionBody2, 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, 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, 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, completionsBody2, 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, adminOrganizationsQuery2, adminUserSearchQuery2, kanbanSlugMigrationQuery2, adjustQuotaBody2, updatePlanBody2, addAdminUserBody2, updatePlatformConfigBody2, updateFreeOrgLimitBody2, 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, 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;
13285
13325
  var init_contracts = __esm({
13286
13326
  "../../packages/core/dist/contracts/index.js"() {
13287
13327
  "use strict";
@@ -15632,6 +15672,64 @@ var init_contracts = __esm({
15632
15672
  templateFileMapSchema2 = external_exports.record(external_exports.string()).refine((m) => Object.keys(m).every(isSafeTemplatePath2), {
15633
15673
  message: 'file map contains an unsafe path (no absolute paths, "..", or backslashes)'
15634
15674
  });
15675
+ TEMPLATE_INSTANCE_ID_KEYS = /* @__PURE__ */ new Set([
15676
+ // Top-level hub instance metadata (hub.yaml) — set by `wayai pull`, never authored.
15677
+ "hub_id",
15678
+ "hub_environment",
15679
+ "preview_label",
15680
+ "branch_name",
15681
+ // Per-entity row id + cross-entity reference UUIDs (each has a portable name twin).
15682
+ "id",
15683
+ "connection_id",
15684
+ "target_id",
15685
+ "agent_id",
15686
+ "resource_id",
15687
+ "list_id",
15688
+ // Account-scoped Meta WhatsApp template id (name twin: `template_whatsapp`).
15689
+ "template_whatsapp_id"
15690
+ ]);
15691
+ TEMPLATE_OPAQUE_BLOB_KEYS = /* @__PURE__ */ new Set([
15692
+ "settings",
15693
+ // agent + connection connector settings
15694
+ "schema_json",
15695
+ // agent response_format JSON Schema
15696
+ "json_schema",
15697
+ // state JSON Schema
15698
+ "initial_value",
15699
+ // state seed value
15700
+ "additional_context_schema",
15701
+ // kanban-status transition-form schema
15702
+ "config",
15703
+ // custom-tool OpenAI function schema
15704
+ "headers",
15705
+ "query_params",
15706
+ "body_params",
15707
+ // custom-tool HTTP shaping
15708
+ "mappings",
15709
+ // composed-tool argument mappings
15710
+ "input",
15711
+ "expected",
15712
+ "history",
15713
+ // eval message fixtures (tool_calls carry their own `id`)
15714
+ "transcript",
15715
+ "step_config"
15716
+ // journey fixtures (transcript carries `step_id`; step_config is keyed by it)
15717
+ ]);
15718
+ TEMPLATE_AUTHOR_DATA_KEYS = /* @__PURE__ */ new Set([
15719
+ // Outbound campaign subsystem (hub.yaml top-level). `outbound_contacts` is the
15720
+ // author's real leads — `phone`/`email`/`instagram_sid` + the required `name` are
15721
+ // GDPR-grade PII. `outbound_lists` group those contacts by real name. `outbound_schedules`
15722
+ // bind to the (now-absent) lists and carry the author's campaign cadence + message
15723
+ // copy — operationally tied to the author's customers; a consumer builds their own.
15724
+ "outbound_contacts",
15725
+ "outbound_lists",
15726
+ "outbound_schedules",
15727
+ // Account-scoped channel identifier on a connection (Twilio SID / WhatsApp number /
15728
+ // IG username / from-email, per connector). The connection stays as portable
15729
+ // structure re-bound by name on push; this author-account value carries no blueprint
15730
+ // value. A dedicated top-level column — never nested in the `settings` opaque blob.
15731
+ "account_sid"
15732
+ ]);
15635
15733
  templateTextSchema2 = external_exports.object({
15636
15734
  metaTitle: external_exports.string().min(1).max(200),
15637
15735
  metaDescription: external_exports.string().max(1e3).default("")
@@ -16933,10 +17031,30 @@ function writeFileMap(targetDir, files) {
16933
17031
  }
16934
17032
  return written;
16935
17033
  }
17034
+ function listDirRelFiles(dir) {
17035
+ const out = [];
17036
+ function walk(d, prefix) {
17037
+ for (const entry of fs16.readdirSync(d, { withFileTypes: true })) {
17038
+ const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
17039
+ if (entry.isDirectory()) walk(path19.join(d, entry.name), rel);
17040
+ else if (entry.isFile()) out.push(rel);
17041
+ }
17042
+ }
17043
+ if (fs16.existsSync(dir)) walk(dir, "");
17044
+ return out;
17045
+ }
17046
+ function writeSliceSnapshot(targetDir, files) {
17047
+ const keep = new Set(Object.keys(files));
17048
+ const removed = listDirRelFiles(targetDir).filter((rel) => !keep.has(rel)).sort((a, b) => a.localeCompare(b));
17049
+ const written = writeFileMap(targetDir, files).sort((a, b) => a.localeCompare(b));
17050
+ if (fs16.existsSync(targetDir)) cleanOrphanFiles(targetDir, "", keep);
17051
+ return { written, removed };
17052
+ }
16936
17053
  var init_template_files = __esm({
16937
17054
  "src/lib/template-files.ts"() {
16938
17055
  "use strict";
16939
17056
  init_contracts();
17057
+ init_resource_files();
16940
17058
  }
16941
17059
  });
16942
17060
 
@@ -17183,6 +17301,34 @@ var init_report_edit_args = __esm({
17183
17301
  }
17184
17302
  });
17185
17303
 
17304
+ // src/lib/template-sanitize.ts
17305
+ import * as yaml9 from "js-yaml";
17306
+ function sanitizeWayaiSliceFiles(files) {
17307
+ const out = {};
17308
+ for (const [filePath, body] of Object.entries(files)) {
17309
+ out[filePath] = isSanitizableSliceFile(filePath) ? sanitizeOne(body) : body;
17310
+ }
17311
+ return out;
17312
+ }
17313
+ function sanitizeOne(body) {
17314
+ let parsed;
17315
+ try {
17316
+ parsed = yaml9.load(body);
17317
+ } catch {
17318
+ return body;
17319
+ }
17320
+ const scrubbed = excludeTemplateAuthorData(stripTemplateInstanceIds(parsed));
17321
+ if (JSON.stringify(parsed) === JSON.stringify(scrubbed)) return body;
17322
+ return yaml9.dump(scrubbed, YAML_DUMP_OPTIONS);
17323
+ }
17324
+ var init_template_sanitize = __esm({
17325
+ "src/lib/template-sanitize.ts"() {
17326
+ "use strict";
17327
+ init_contracts();
17328
+ init_yaml_writer();
17329
+ }
17330
+ });
17331
+
17186
17332
  // src/lib/template-manifest.ts
17187
17333
  function buildTemplatePushCommon(manifest, hero) {
17188
17334
  return {
@@ -17210,7 +17356,7 @@ __export(admin_exports, {
17210
17356
  });
17211
17357
  import * as fs17 from "fs";
17212
17358
  import * as path21 from "path";
17213
- import * as yaml9 from "js-yaml";
17359
+ import * as yaml10 from "js-yaml";
17214
17360
  async function adminCommand(args2) {
17215
17361
  const [group, ...afterGroup] = args2;
17216
17362
  if (!group) {
@@ -17336,6 +17482,9 @@ async function adminCommand(args2) {
17336
17482
  case "pull":
17337
17483
  await runTemplatePull2(positional, flagArgs);
17338
17484
  return;
17485
+ case "freeze":
17486
+ await runTemplateFreeze(positional, flagArgs);
17487
+ return;
17339
17488
  default:
17340
17489
  printHelp2();
17341
17490
  process.exit(1);
@@ -17579,16 +17728,7 @@ function parseFlags2(flagArgs, allowed) {
17579
17728
  }
17580
17729
  return out;
17581
17730
  }
17582
- async function runTemplatePush(positional) {
17583
- const slug = positional[0];
17584
- if (!slug) {
17585
- console.error("wayai admin template push <slug>");
17586
- process.exit(1);
17587
- }
17588
- if (!TEMPLATE_SLUG_REGEX2.test(slug)) {
17589
- console.error(`Invalid template slug: ${slug}`);
17590
- process.exit(1);
17591
- }
17731
+ function loadTemplateManifest(slug) {
17592
17732
  const gitRoot = findGitRoot();
17593
17733
  if (!gitRoot) {
17594
17734
  console.error("Not in a git repository. Run from the tutorials/ authoring repo.");
@@ -17602,7 +17742,7 @@ async function runTemplatePush(positional) {
17602
17742
  }
17603
17743
  let manifest;
17604
17744
  try {
17605
- manifest = templateYamlSchema2.parse(yaml9.load(fs17.readFileSync(manifestPath, "utf-8")));
17745
+ manifest = templateYamlSchema2.parse(yaml10.load(fs17.readFileSync(manifestPath, "utf-8")));
17606
17746
  } catch (err) {
17607
17747
  console.error(`Invalid template.yaml: ${err instanceof Error ? err.message : String(err)}`);
17608
17748
  process.exit(1);
@@ -17611,6 +17751,19 @@ async function runTemplatePush(positional) {
17611
17751
  console.error(`template.yaml slug "${manifest.slug}" does not match folder "${slug}".`);
17612
17752
  process.exit(1);
17613
17753
  }
17754
+ return { gitRoot, templateDir, manifest };
17755
+ }
17756
+ async function runTemplatePush(positional) {
17757
+ const slug = positional[0];
17758
+ if (!slug) {
17759
+ console.error("wayai admin template push <slug>");
17760
+ process.exit(1);
17761
+ }
17762
+ if (!TEMPLATE_SLUG_REGEX2.test(slug)) {
17763
+ console.error(`Invalid template slug: ${slug}`);
17764
+ process.exit(1);
17765
+ }
17766
+ const { templateDir, manifest } = loadTemplateManifest(slug);
17614
17767
  const authoredLocales = new Set(
17615
17768
  Object.keys(manifest.wayai.locales)
17616
17769
  );
@@ -17624,6 +17777,11 @@ async function runTemplatePush(positional) {
17624
17777
  console.error(`wayai source not found for ${locale}: ${wayaiEntry.source} (resolved ${sliceDir})`);
17625
17778
  process.exit(1);
17626
17779
  }
17780
+ if (!isInsideTemplateDir(sliceDir, templateDir)) {
17781
+ console.warn(
17782
+ `Note: ${locale} source points at a live hub (${wayaiEntry.source}); it can go stale on a hub recreate. Run \`wayai admin template freeze ${slug} --locale ${locale} --from ${path21.basename(sliceDir)}\` to commit a stable frozen slice.`
17783
+ );
17784
+ }
17627
17785
  wayaiFiles = readDirToFileMap(sliceDir);
17628
17786
  }
17629
17787
  const readmePath = path21.join(templateDir, `README.${locale}.md`);
@@ -17665,6 +17823,119 @@ async function runTemplatePush(positional) {
17665
17823
  console.log(`(status=${manifest.status} \u2192 unpublished from the store)`);
17666
17824
  }
17667
17825
  }
17826
+ function isInsideTemplateDir(dest, templateDir) {
17827
+ return dest === templateDir || dest.startsWith(templateDir + path21.sep);
17828
+ }
17829
+ async function runTemplateFreeze(positional, flagArgs) {
17830
+ const slug = positional[0];
17831
+ if (!slug) {
17832
+ console.error("wayai admin template freeze <slug> [--locale <l>] [--from <hub>] [--dry-run]");
17833
+ process.exit(1);
17834
+ }
17835
+ if (!TEMPLATE_SLUG_REGEX2.test(slug)) {
17836
+ console.error(`Invalid template slug: ${slug}`);
17837
+ process.exit(1);
17838
+ }
17839
+ let locale;
17840
+ let from;
17841
+ let dryRun = false;
17842
+ for (let i = 0; i < flagArgs.length; i++) {
17843
+ if (flagArgs[i] === "--dry-run") {
17844
+ dryRun = true;
17845
+ continue;
17846
+ }
17847
+ if (flagArgs[i] === "--locale") {
17848
+ const v = flagArgs[++i];
17849
+ if (!v) {
17850
+ console.error("--locale requires a value");
17851
+ process.exit(1);
17852
+ }
17853
+ const parsed = templateLocaleSchema2.safeParse(v);
17854
+ if (!parsed.success) {
17855
+ console.error(`Invalid --locale "${v}": must be one of ${templateLocaleSchema2.options.join(", ")}.`);
17856
+ process.exit(1);
17857
+ }
17858
+ locale = parsed.data;
17859
+ continue;
17860
+ }
17861
+ if (flagArgs[i] === "--from") {
17862
+ from = flagArgs[++i];
17863
+ if (!from) {
17864
+ console.error("--from requires a value");
17865
+ process.exit(1);
17866
+ }
17867
+ continue;
17868
+ }
17869
+ console.error(`Unknown flag: ${flagArgs[i]}`);
17870
+ process.exit(1);
17871
+ }
17872
+ const { gitRoot, templateDir, manifest } = loadTemplateManifest(slug);
17873
+ const authored = Object.keys(manifest.wayai.locales);
17874
+ let targetLocale;
17875
+ if (locale) {
17876
+ if (!manifest.wayai.locales[locale]) {
17877
+ console.error(`Locale "${locale}" is not authored in ${slug}/template.yaml (have: ${authored.join(", ")}).`);
17878
+ process.exit(1);
17879
+ }
17880
+ targetLocale = locale;
17881
+ } else if (authored.length === 1) {
17882
+ targetLocale = authored[0];
17883
+ } else {
17884
+ console.error(`Template "${slug}" authors ${authored.length} locales (${authored.join(", ")}). Pass --locale <l> \u2014 each freezes from its own hub.`);
17885
+ process.exit(1);
17886
+ }
17887
+ const entry = manifest.wayai.locales[targetLocale];
17888
+ const dest = path21.resolve(templateDir, entry.source);
17889
+ if (!isInsideTemplateDir(dest, templateDir) || dest === templateDir) {
17890
+ console.error(
17891
+ `source for "${targetLocale}" must be a committed path inside ${slug}/ (e.g. "./${targetLocale}/slice"), but resolved to:
17892
+ ${entry.source} \u2192 ${dest}
17893
+ Set it to a subdir of the template folder and re-run freeze.`
17894
+ );
17895
+ process.exit(1);
17896
+ }
17897
+ const hubsDir = resolveHubsDir(gitRoot);
17898
+ const selector = from ?? readBinding();
17899
+ const hubFolder = selector ? resolveHubFolderBySelector(hubsDir, selector) : null;
17900
+ if (!hubFolder) {
17901
+ console.error(
17902
+ selector ? `Could not resolve a source hub matching "${selector}" in ${hubsDirLabel(gitRoot)}/.` : "No --from given and this worktree has no `wayai use` binding."
17903
+ );
17904
+ const hubs = scanWorkspaceHubs(hubsDir);
17905
+ if (hubs.length) {
17906
+ console.error("Available hubs:");
17907
+ for (const h of hubs) console.error(` ${path21.basename(h.hubFolder)} (${h.hubId})`);
17908
+ }
17909
+ console.error(`
17910
+ Pass --from <folder|uuid>${selector ? "." : " or run `wayai use <hub>` first."}`);
17911
+ process.exit(1);
17912
+ }
17913
+ const liveFiles = readDirToFileMap(hubFolder);
17914
+ if (Object.keys(liveFiles).length === 0) {
17915
+ console.error(`Source hub folder has no files to freeze: ${path21.relative(gitRoot, hubFolder)}`);
17916
+ process.exit(1);
17917
+ }
17918
+ const sanitized = sanitizeWayaiSliceFiles(liveFiles);
17919
+ const relDest = path21.relative(gitRoot, dest);
17920
+ const relSrc = path21.relative(gitRoot, hubFolder);
17921
+ if (dryRun) {
17922
+ const existing = new Set(listDirRelFiles(dest));
17923
+ const nextKeys = new Set(Object.keys(sanitized));
17924
+ console.log(`Dry run \u2014 would freeze ${relSrc}/ \u2192 ${relDest}/ (locale ${targetLocale}):`);
17925
+ for (const rel of Object.keys(sanitized).sort((a, b) => a.localeCompare(b))) {
17926
+ console.log(` ${existing.has(rel) ? "update" : "create"} ${rel}`);
17927
+ }
17928
+ for (const rel of [...existing].filter((k) => !nextKeys.has(k)).sort((a, b) => a.localeCompare(b))) {
17929
+ console.log(` remove ${rel}`);
17930
+ }
17931
+ return;
17932
+ }
17933
+ const { written, removed } = writeSliceSnapshot(dest, sanitized);
17934
+ console.log(
17935
+ `Froze ${relSrc}/ \u2192 ${relDest}/ (locale ${targetLocale}): ${written.length} file${written.length === 1 ? "" : "s"} written${removed.length ? `, ${removed.length} removed` : ""}.`
17936
+ );
17937
+ console.log(`The slice is committed \u2014 re-push is stable across hub recreates. Next: \`wayai admin template push ${slug}\`.`);
17938
+ }
17668
17939
  async function runTemplatePull2(positional, flagArgs) {
17669
17940
  const slug = positional[0];
17670
17941
  if (!slug) {
@@ -18153,6 +18424,8 @@ Usage:
18153
18424
 
18154
18425
  wayai admin template push <slug> Publish a template from wayai-templates/<slug>/ into the store
18155
18426
  wayai admin template pull <slug> [--out DIR] [--json] Pull a published template from the store for inspection
18427
+ wayai admin template freeze <slug> [--locale <l>] [--from <hub>] [--dry-run]
18428
+ Snapshot a live hub into the template's committed slice (id/PII-scrubbed)
18156
18429
 
18157
18430
  wayai admin skill install [name] Install a private operator skill (default: wayai-admin) into each present harness's skills/ dir
18158
18431
 
@@ -18214,9 +18487,11 @@ var init_admin = __esm({
18214
18487
  init_observability();
18215
18488
  init_report_edit_args();
18216
18489
  init_workspace();
18490
+ init_hub_binding();
18217
18491
  init_skill_version();
18218
18492
  init_layout();
18219
18493
  init_template_files();
18494
+ init_template_sanitize();
18220
18495
  init_template_manifest();
18221
18496
  init_contracts();
18222
18497
  VALID_TYPES = dataExplorerDebugDoType2.options;