@wayai/cli 0.3.218 → 0.3.220

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
@@ -5553,10 +5553,10 @@ var init_chunk_5DGHIY7L = __esm({
5553
5553
  }
5554
5554
  });
5555
5555
 
5556
- // ../../packages/core/dist/chunk-KWBAMM7C.js
5557
- var REKOR_ACTOR_TYPE_HEADER, REKOR_ACTOR_ID_HEADER, REKOR_ACTOR_LABEL_HEADER, REKOR_ACTOR_ORG_HEADER, REKOR_ACTOR_ADMIN_HEADER, REKOR_CLIENT_HEADER, REKOR_TOOL_ID_HEADER, REKOR_CLIENTS, rekorClientSchema, MAX_REKOR_TOOL_ID_LENGTH, rekorToolIdSchema, REKOR_V1_PREFIX, DATA_PROXY_ORG_QUERY_PARAM, MAX_PROVISIONING_BODY_BYTES, dataProxyQuery, rekorAttestation, REQUIRED_REKOR_ATTESTATION_HEADERS, REKOR_BOUND_BASE_HEADER, REKOR_BOUND_TOOLSET_HEADER, REKOR_BOUND_TOKEN_HEADER, DATA_BASE_GENERATION_HEADER, REKOR_MAX_ACTOR_ID_LENGTH, REKOR_MAX_ACTOR_LABEL_LENGTH;
5558
- var init_chunk_KWBAMM7C = __esm({
5559
- "../../packages/core/dist/chunk-KWBAMM7C.js"() {
5556
+ // ../../packages/core/dist/chunk-BEOHBREG.js
5557
+ var REKOR_ACTOR_TYPE_HEADER, REKOR_ACTOR_ID_HEADER, REKOR_ACTOR_LABEL_HEADER, REKOR_ACTOR_ORG_HEADER, REKOR_ACTOR_ADMIN_HEADER, REKOR_CLIENT_HEADER, REKOR_TOOL_ID_HEADER, REKOR_CLIENTS, rekorClientSchema, MAX_REKOR_TOOL_ID_LENGTH, rekorToolIdSchema, REKOR_V1_PREFIX, DATA_PROXY_ORG_QUERY_PARAM, MAX_PROVISIONING_BODY_BYTES, dataProxyQuery, rekorAttestation, REQUIRED_REKOR_ATTESTATION_HEADERS, REKOR_BOUND_BASE_HEADER, REKOR_BOUND_TOOLSET_HEADER, REKOR_BOUND_TOKEN_HEADER, REKOR_BOUND_CUSTOMER_HEADER, DATA_BASE_GENERATION_HEADER, REKOR_MAX_ACTOR_ID_LENGTH, REKOR_MAX_ACTOR_LABEL_LENGTH;
5558
+ var init_chunk_BEOHBREG = __esm({
5559
+ "../../packages/core/dist/chunk-BEOHBREG.js"() {
5560
5560
  "use strict";
5561
5561
  init_zod();
5562
5562
  REKOR_ACTOR_TYPE_HEADER = "X-Rekor-Actor-Type";
@@ -5589,18 +5589,19 @@ var init_chunk_KWBAMM7C = __esm({
5589
5589
  REKOR_BOUND_BASE_HEADER = "X-Rekor-Bound-Base";
5590
5590
  REKOR_BOUND_TOOLSET_HEADER = "X-Rekor-Bound-Toolset";
5591
5591
  REKOR_BOUND_TOKEN_HEADER = "X-Rekor-Bound-Token";
5592
+ REKOR_BOUND_CUSTOMER_HEADER = "X-Rekor-Bound-Customer";
5592
5593
  DATA_BASE_GENERATION_HEADER = "X-Data-Base-Generation";
5593
5594
  REKOR_MAX_ACTOR_ID_LENGTH = 256;
5594
5595
  REKOR_MAX_ACTOR_LABEL_LENGTH = 256;
5595
5596
  }
5596
5597
  });
5597
5598
 
5598
- // ../../packages/core/dist/chunk-4I3WSYXD.js
5599
+ // ../../packages/core/dist/chunk-BVQE66I2.js
5599
5600
  var TOOLSET_SLUG_PATTERN, REKOR_STRUCTURAL_ID_PATTERN, baseEnvironmentSchema, TOOLSET_FILE_OPERATIONS, toolsetFileToolSchema, toolsetSurfaceSchema, toolsetConnectionBindingSchema, rekorToolsetToolsSchema, rekorBoundAttestation, rekorResolvedToolsetSchema, resolvedFileToolSchema, rekorToolsetFileSchema, rekorToolsetFileListSchema, rekorToolsetFileGetSchema, rekorToolsetFilePutSchema, TOOLSET_CUSTOMER_FACING_REFUSAL_MARK, TOOLSET_CUSTOMER_FACING_REFUSAL;
5600
- var init_chunk_4I3WSYXD = __esm({
5601
- "../../packages/core/dist/chunk-4I3WSYXD.js"() {
5601
+ var init_chunk_BVQE66I2 = __esm({
5602
+ "../../packages/core/dist/chunk-BVQE66I2.js"() {
5602
5603
  "use strict";
5603
- init_chunk_KWBAMM7C();
5604
+ init_chunk_BEOHBREG();
5604
5605
  init_chunk_DHPUPI4Y();
5605
5606
  init_zod();
5606
5607
  TOOLSET_SLUG_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
@@ -5624,6 +5625,20 @@ var init_chunk_4I3WSYXD = __esm({
5624
5625
  records: external_exports.boolean(),
5625
5626
  sql_query: external_exports.boolean(),
5626
5627
  batch: external_exports.boolean(),
5628
+ /**
5629
+ * The toolset serves one customer per call (#5083 RK2): its every call names the customer it serves,
5630
+ * and reaches only that customer's records and shared ones. Absent on a surface recorded before it
5631
+ * was, which reads as not scoped until the connection's next tool sync or token save records it: its
5632
+ * calls name no customer, and the customer-facing rule admits none of its record tools.
5633
+ */
5634
+ customer_scoped: external_exports.boolean().optional(),
5635
+ /**
5636
+ * A key of the resolve this side neither describes nor classifies exposes something: a kind of tool
5637
+ * the data product added later, counted in `records`. The customer-facing rule never admits it, a
5638
+ * customer scope included, until it is classified here. Absent on a surface recorded before it was,
5639
+ * which reads as present.
5640
+ */
5641
+ unclassified_tools: external_exports.boolean().optional(),
5627
5642
  /**
5628
5643
  * Any of its file tools writes: an operation other than `list` and `get` (`put`, `delete`, or one
5629
5644
  * the data product adds later), or an entry this side cannot read. Absent on a surface recorded
@@ -5678,7 +5693,12 @@ var init_chunk_4I3WSYXD = __esm({
5678
5693
  */
5679
5694
  [DATA_BASE_GENERATION_HEADER]: external_exports.string().regex(/^[1-9]\d{0,14}$/),
5680
5695
  /** The token the binding was resolved from, when the connection records it (owner decision 41). */
5681
- [REKOR_BOUND_TOKEN_HEADER]: external_exports.string().regex(REKOR_STRUCTURAL_ID_PATTERN).optional()
5696
+ [REKOR_BOUND_TOKEN_HEADER]: external_exports.string().regex(REKOR_STRUCTURAL_ID_PATTERN).optional(),
5697
+ /**
5698
+ * The customer the call serves (#5083 RK2): a contact id, which the contact book mints as a UUID.
5699
+ * Every UUID is an id the far side reads back as the customer's external id.
5700
+ */
5701
+ [REKOR_BOUND_CUSTOMER_HEADER]: external_exports.string().uuid().optional()
5682
5702
  });
5683
5703
  rekorResolvedToolsetSchema = external_exports.object({
5684
5704
  data: external_exports.object({
@@ -5706,7 +5726,9 @@ var init_chunk_4I3WSYXD = __esm({
5706
5726
  relationships: external_exports.array(external_exports.unknown()).optional(),
5707
5727
  files: external_exports.array(external_exports.unknown()).optional(),
5708
5728
  batch: external_exports.object({ enabled: external_exports.boolean().optional() }).passthrough().nullable().optional(),
5709
- sql_query: external_exports.boolean().optional()
5729
+ sql_query: external_exports.boolean().optional(),
5730
+ /** The toolset serves one customer per call (#5083 RK2). Absent reads as not scoped. */
5731
+ customer_scope: external_exports.boolean().optional()
5710
5732
  }).passthrough()
5711
5733
  });
5712
5734
  resolvedFileToolSchema = external_exports.object({
@@ -5731,7 +5753,7 @@ var init_chunk_4I3WSYXD = __esm({
5731
5753
  });
5732
5754
  rekorToolsetFilePutSchema = external_exports.object({ data: rekorToolsetFileSchema });
5733
5755
  TOOLSET_CUSTOMER_FACING_REFUSAL_MARK = "A customer-facing agent (a pilot, pilot specialist or pilot advisor) can use a toolset only when it exposes files alone: no record, composite or relationship tools, and neither sql_query nor batch";
5734
- TOOLSET_CUSTOMER_FACING_REFUSAL = `${TOOLSET_CUSTOMER_FACING_REFUSAL_MARK}, nor a file put or delete`;
5756
+ TOOLSET_CUSTOMER_FACING_REFUSAL = `${TOOLSET_CUSTOMER_FACING_REFUSAL_MARK}, nor a file put or delete \u2014 unless the toolset is customer-scoped, which admits its record, composite and relationship tools, since each of their calls reaches only the conversation's customer and shared records`;
5735
5757
  }
5736
5758
  });
5737
5759
 
@@ -6184,7 +6206,7 @@ var init_chunk_E4DIIOOE = __esm({
6184
6206
  }
6185
6207
  });
6186
6208
 
6187
- // ../../packages/core/dist/chunk-LR5WDVCH.js
6209
+ // ../../packages/core/dist/chunk-FMXFEZN4.js
6188
6210
  function spokenLineField(label, description2) {
6189
6211
  return { type: "text", label, maxLength: SPOKEN_LINE_MAX_CHARS, default: "", description: description2 };
6190
6212
  }
@@ -6194,8 +6216,8 @@ function byLowercaseName(a, b) {
6194
6216
  return x < y ? -1 : x > y ? 1 : 0;
6195
6217
  }
6196
6218
  var CALLER_LANGUAGE, TTS_VOICE_REPLY_ENABLED_FIELD, COPILOT_TRIGGER_FIELD, SANDBOX_AGENT_FIELDS, AUDIO_LANGUAGE_OPTIONS, whatsapp, instagram, resend, telegram, API_CHANNEL_DELIVERY_EVENTS, apiChannel, OPENAI_REASONING_MODELS, openai, anthropic, googleAiStudio, openRouter, xai, groqStt, openaiStt, elevenLabsStt, openaiTts, groqTts, elevenLabsTts, GEMINI_TTS_VOICES, googleTts, wayai, externalResources, restApiTool, mcpServer, REKOR_TOOLSET_SERVICE_NAME, rekorToolset, CLAUDE_HARNESS_MODELS, CLAUDE_HARNESS_MODEL_OPTIONS, HARNESS_MCP_SERVERS_FIELD, HARNESS_EGRESS_FIELDS, claudeManagedAgents, SPOKEN_LINE_MAX_CHARS, gptLive, CONNECTORS;
6197
- var init_chunk_LR5WDVCH = __esm({
6198
- "../../packages/core/dist/chunk-LR5WDVCH.js"() {
6219
+ var init_chunk_FMXFEZN4 = __esm({
6220
+ "../../packages/core/dist/chunk-FMXFEZN4.js"() {
6199
6221
  "use strict";
6200
6222
  CALLER_LANGUAGE = "caller";
6201
6223
  TTS_VOICE_REPLY_ENABLED_FIELD = {
@@ -7149,13 +7171,13 @@ var init_chunk_LR5WDVCH = __esm({
7149
7171
  }
7150
7172
  });
7151
7173
 
7152
- // ../../packages/core/dist/chunk-73J42LZ3.js
7174
+ // ../../packages/core/dist/chunk-VOC3AGY4.js
7153
7175
  var evalCallInstant, EVAL_CALL_MIN_SECONDS, EVAL_CALL_MAX_SECONDS, EVAL_CALL_SPOKEN_LINE_MAX_CHARS, hubScoped2, createEvalCallBody, createEvalCallResponse, evalCallConversationQuery, evalCallRecordQuery, evalCallSpeaker, evalCallUtterance, evalCallTurn, evalCallRecording, evalCallRecordResponse, evalCallFinishResponse;
7154
- var init_chunk_73J42LZ3 = __esm({
7155
- "../../packages/core/dist/chunk-73J42LZ3.js"() {
7176
+ var init_chunk_VOC3AGY4 = __esm({
7177
+ "../../packages/core/dist/chunk-VOC3AGY4.js"() {
7156
7178
  "use strict";
7157
7179
  init_chunk_E4DIIOOE();
7158
- init_chunk_LR5WDVCH();
7180
+ init_chunk_FMXFEZN4();
7159
7181
  init_chunk_HZ6CADSY();
7160
7182
  init_chunk_MIWZOSPI();
7161
7183
  init_zod();
@@ -7522,15 +7544,15 @@ var init_chunk_MH4O3YEX = __esm({
7522
7544
  }
7523
7545
  });
7524
7546
 
7525
- // ../../packages/core/dist/chunk-45TIBJK6.js
7547
+ // ../../packages/core/dist/chunk-QCQUZL4L.js
7526
7548
  function catalogToolSideEffects(toolName) {
7527
7549
  const sideEffects = CATALOG_SIDE_EFFECTS.get(toolName);
7528
7550
  if (sideEffects === void 0) return "unknown";
7529
7551
  return sideEffects ? "side_effects" : "none";
7530
7552
  }
7531
7553
  var NATIVE_TOOL_SCHEMAS, WAYAI_CONNECTOR, SANDBOX_AGENT_ROLES, BASE_NATIVE_TOOLS, NATIVE_TOOLS, CATALOG_SIDE_EFFECTS;
7532
- var init_chunk_45TIBJK6 = __esm({
7533
- "../../packages/core/dist/chunk-45TIBJK6.js"() {
7554
+ var init_chunk_QCQUZL4L = __esm({
7555
+ "../../packages/core/dist/chunk-QCQUZL4L.js"() {
7534
7556
  "use strict";
7535
7557
  init_chunk_DHPUPI4Y();
7536
7558
  NATIVE_TOOL_SCHEMAS = {
@@ -8410,12 +8432,12 @@ var init_chunk_45TIBJK6 = __esm({
8410
8432
  SANDBOX_AGENT_ROLES = [...PILOT_TRACK_ROLES, ...COPILOT_TRACK_ROLES];
8411
8433
  BASE_NATIVE_TOOLS = [
8412
8434
  // --- Wayai core tools ---
8413
- { tool_native_id: "nt-001", tool_name: "transfer_to_agent", tool_display_name: "Transfer to Agent", tool_description: "Transfer the conversation to another AI agent", connector_id: WAYAI_CONNECTOR, operation: "transfer_to_agent", tool_method: "internal", tool_group: "Native Tools", is_delegation: true, is_auto_set: false, execution_config: null, side_effects: false, replay: "reconcile" },
8414
- { tool_native_id: "nt-002", tool_name: "transfer_to_team", tool_display_name: "Transfer to Team", tool_description: "Escalate conversation to a human support team", connector_id: WAYAI_CONNECTOR, operation: "transfer_to_team", tool_method: "internal", tool_group: "Native Tools", is_delegation: true, is_auto_set: false, execution_config: null, side_effects: false, replay: "reconcile" },
8435
+ { tool_native_id: "nt-001", tool_name: "transfer_to_agent", tool_display_name: "Transfer to Agent", tool_description: "Transfer the conversation to another AI agent", connector_id: WAYAI_CONNECTOR, operation: "transfer_to_agent", tool_method: "internal", tool_group: "Native Tools", is_delegation: true, is_auto_set: false, execution_config: null, side_effects: false, replay: "keyed" },
8436
+ { tool_native_id: "nt-002", tool_name: "transfer_to_team", tool_display_name: "Transfer to Team", tool_description: "Escalate conversation to a human support team", connector_id: WAYAI_CONNECTOR, operation: "transfer_to_team", tool_method: "internal", tool_group: "Native Tools", is_delegation: true, is_auto_set: false, execution_config: null, side_effects: false, replay: "keyed" },
8415
8437
  { tool_native_id: "nt-003", tool_name: "close_conversation", tool_display_name: "Close Conversation", tool_description: "Close and end the current conversation", connector_id: WAYAI_CONNECTOR, operation: "close_conversation", tool_method: "internal", tool_group: "Native Tools", is_delegation: false, is_auto_set: false, execution_config: null, side_effects: true, replay: "keyed" },
8416
8438
  { tool_native_id: "nt-004", tool_name: "update_kanban_status", tool_display_name: "Update Kanban Status", tool_description: "Update the kanban status of the conversation", connector_id: WAYAI_CONNECTOR, operation: "update_kanban_status", tool_method: "internal", tool_group: "Native Tools", is_delegation: false, is_auto_set: false, execution_config: null, side_effects: false, replay: "rerun" },
8417
8439
  { tool_native_id: "nt-005", tool_name: "schedule_followup", tool_display_name: "Schedule Follow-up", tool_description: "Schedule a follow-up message for the conversation", connector_id: WAYAI_CONNECTOR, operation: "schedule_followup", tool_method: "internal", tool_group: "Native Tools", is_delegation: false, is_auto_set: true, execution_config: null, side_effects: true, replay: "keyed" },
8418
- { tool_native_id: "nt-006", tool_name: "send_files", tool_display_name: "Send Files", tool_description: "Send files to the user", connector_id: WAYAI_CONNECTOR, operation: "send_files", tool_method: "internal", tool_group: "Native Tools", is_delegation: false, is_auto_set: false, execution_config: null, side_effects: true, replay: "reconcile" },
8440
+ { tool_native_id: "nt-006", tool_name: "send_files", tool_display_name: "Send Files", tool_description: "Send files to the user", connector_id: WAYAI_CONNECTOR, operation: "send_files", tool_method: "internal", tool_group: "Native Tools", is_delegation: false, is_auto_set: false, execution_config: null, side_effects: true, replay: "keyed" },
8419
8441
  { tool_native_id: "nt-007", tool_name: "update_state", tool_display_name: "Update State", tool_description: "Update conversation or user state variables", connector_id: WAYAI_CONNECTOR, operation: "update_state", tool_method: "internal", tool_group: "Native Tools", is_delegation: false, is_auto_set: false, execution_config: null, side_effects: false, replay: "rerun" },
8420
8442
  { tool_native_id: "nt-008", tool_name: "get_state", tool_display_name: "Get State", tool_description: "Retrieve conversation or user state values", connector_id: WAYAI_CONNECTOR, operation: "get_state", tool_method: "internal", tool_group: "Native Tools", is_delegation: false, is_auto_set: false, execution_config: null, side_effects: false, replay: "rerun" },
8421
8443
  { tool_native_id: "nt-009", tool_name: "reset_state", tool_display_name: "Reset State", tool_description: "Reset conversation or user state to initial values", connector_id: WAYAI_CONNECTOR, operation: "reset_state", tool_method: "internal", tool_group: "Native Tools", is_delegation: false, is_auto_set: false, execution_config: null, side_effects: false, replay: "rerun" },
@@ -8507,7 +8529,7 @@ var init_chunk_45TIBJK6 = __esm({
8507
8529
  { tool_native_id: "nt-031", tool_name: "copy_to_sandbox", tool_display_name: "Copy File to Sandbox", tool_description: "Copy one of the conversation's files into its code sandbox", connector_id: WAYAI_CONNECTOR, operation: "copy_to_sandbox", tool_method: "internal", tool_group: "Native Tools", is_delegation: false, is_auto_set: false, execution_config: null, side_effects: false, replay: "rerun", assignable_roles: SANDBOX_AGENT_ROLES },
8508
8530
  // Copies a sandbox file OUT into the conversation, as an internal note for the team: nothing
8509
8531
  // reaches the customer until `send_files` sends it.
8510
- { tool_native_id: "nt-032", tool_name: "copy_from_sandbox", tool_display_name: "Copy File from Sandbox", tool_description: "Copy a file out of the code sandbox into the conversation, for the team", connector_id: WAYAI_CONNECTOR, operation: "copy_from_sandbox", tool_method: "internal", tool_group: "Native Tools", is_delegation: false, is_auto_set: false, execution_config: null, side_effects: false, replay: "reconcile", assignable_roles: SANDBOX_AGENT_ROLES },
8532
+ { tool_native_id: "nt-032", tool_name: "copy_from_sandbox", tool_display_name: "Copy File from Sandbox", tool_description: "Copy a file out of the code sandbox into the conversation, for the team", connector_id: WAYAI_CONNECTOR, operation: "copy_from_sandbox", tool_method: "internal", tool_group: "Native Tools", is_delegation: false, is_auto_set: false, execution_config: null, side_effects: false, replay: "keyed", assignable_roles: SANDBOX_AGENT_ROLES },
8511
8533
  // The `data/` mount's writes (#5142 step 2): a document of the agent's Base Toolset, written
8512
8534
  // through the toolset's own `put` tool with its version check. `reconcile`, not `keyed`: a re-run
8513
8535
  // after a first write that changed the file is refused by that check (its version, or the create's
@@ -8742,7 +8764,7 @@ var init_chunk_T7KQKDET = __esm({
8742
8764
  }
8743
8765
  });
8744
8766
 
8745
- // ../../packages/core/dist/chunk-STST7XWM.js
8767
+ // ../../packages/core/dist/chunk-BQWVW6JO.js
8746
8768
  function resolveMonitorTrigger(monitorConfig) {
8747
8769
  if (!monitorConfig || typeof monitorConfig !== "object") return "idle";
8748
8770
  const raw = monitorConfig.trigger;
@@ -9048,10 +9070,10 @@ function refineMonitorRulesStructuredOutput(body, ctx) {
9048
9070
  if (refusal2) ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["response_format"], message: refusal2 });
9049
9071
  }
9050
9072
  var NATIVE_TOOL_NAMES, previousConversationsCountField, summarizationThresholdField, flagConditionSchema, MONITOR_TRIGGERS, monitorTriggerSchema, AUTOMATION_GATE_TRIGGERS, NON_FIRING_TRIGGERS, MONITOR_FIRING_TRIGGERS, MONITOR_DELAY_SECONDS_MIN, MONITOR_IDLE_DELAY_REQUIRED_MESSAGE, MONITOR_HISTORY_MESSAGES_MAX, monitorHistoryMessagesSchema, monitorIncludeToolResultsSchema, MONITOR_INPUT_SHAPING_KEYS, MONITOR_INPUT_SHAPING_SCHEMAS, MONITOR_INPUT_SHAPING_IDLE_MESSAGE, monitorArgumentSourceSchema, MONITOR_NOTE_TEMPLATE_MAX, MONITOR_STEER_NOTE_MAX, MONITOR_GATE_AGENT_NAME_MAX, monitorActionSchema, monitorRuleSchema, MONITOR_RULE_KEYS, MONITOR_RULE_SCHEMAS, MONITOR_RULE_TRIGGERS, MONITOR_RULE_TRIGGER_MESSAGE, CALL_UTTERANCE_SPEAKERS, callUtteranceSpeakerSchema, MONITOR_CALL_KEYS, MONITOR_CALL_SCHEMAS, MONITOR_CALL_KEY_MESSAGE, CALL_STEERING_MIN_CONFIDENCE, CALL_UTTERANCE_RULE_NOT_CONFIDENT_MESSAGE, CALL_UTTERANCE_FALLBACK_MESSAGE, CALL_UTTERANCE_FLAG_CONDITIONS_MESSAGE, CALL_STEER_NOTE_BLANK_MESSAGE, MONITOR_USER_MESSAGE_ACTION_KINDS, MONITOR_ASSISTANT_REPLY_ACTION_KINDS, MONITOR_CALL_UTTERANCE_ACTION_KINDS, MONITOR_AUTOMATION_FIRE_ACTION_KINDS, MONITOR_AUTOMATION_ITEM_ACTION_KINDS, INSERT_NOTE_TOOL_NAME, RUN_MONITOR_TOOL_NAME, MONITOR_RULE_ALLOWED_NATIVE_TOOLS, MONITOR_RULE_REENTRY_TOOLS, MONITOR_RULE_REENTRY_TRACKS, AUTOMATION_FIRE_FLAG_CONDITIONS_MESSAGE, AUTOMATION_FIRE_INPUT_SHAPING_MESSAGE, AUTOMATION_ITEM_FLAG_CONDITIONS_MESSAGE, AUTOMATION_ITEM_INPUT_SHAPING_MESSAGE, AUTOMATION_GATE_KEY_MESSAGES, monitorConfigField, flagConditionsField, agentIdParam, listAgentsQuery, agentConnectionsQuery, createAgentBody, updateAgentBody, AGENT_PARAMETER_TYPES, AGENT_PARAMETER_NAME_REGEX, agentParameterCreateSchema, MAX_AGENT_PARAMETERS_PER_REQUEST, createAgentParametersBody;
9051
- var init_chunk_STST7XWM = __esm({
9052
- "../../packages/core/dist/chunk-STST7XWM.js"() {
9073
+ var init_chunk_BQWVW6JO = __esm({
9074
+ "../../packages/core/dist/chunk-BQWVW6JO.js"() {
9053
9075
  "use strict";
9054
- init_chunk_45TIBJK6();
9076
+ init_chunk_QCQUZL4L();
9055
9077
  init_chunk_IBL7FANV();
9056
9078
  init_chunk_PFDZEKDE();
9057
9079
  init_chunk_HZ6CADSY();
@@ -9274,12 +9296,12 @@ var init_chunk_STST7XWM = __esm({
9274
9296
  }
9275
9297
  });
9276
9298
 
9277
- // ../../packages/core/dist/chunk-RKJYFGBO.js
9299
+ // ../../packages/core/dist/chunk-SPE6FAYO.js
9278
9300
  var conversationIdParam, conversationHubQuery, claimBody, releaseBody, transferBody, closeBody, additionalContextPayloadSchema, kanbanUpdateBody, annotateConversationBody, observabilityParams, observabilityListParams, deleteUserConversationsBody, deleteUserConversationsResponse, sendMessageBody, listConversationsQuery, flagSourceSchema, getConversationsResponse, getConversationDetailParams, getConversationDetailQuery, getConversationDetailResponse, listWhatsAppTemplatesQuery, sendWhatsAppTemplateBody;
9279
- var init_chunk_RKJYFGBO = __esm({
9280
- "../../packages/core/dist/chunk-RKJYFGBO.js"() {
9301
+ var init_chunk_SPE6FAYO = __esm({
9302
+ "../../packages/core/dist/chunk-SPE6FAYO.js"() {
9281
9303
  "use strict";
9282
- init_chunk_STST7XWM();
9304
+ init_chunk_BQWVW6JO();
9283
9305
  init_chunk_HZ6CADSY();
9284
9306
  init_chunk_DHPUPI4Y();
9285
9307
  init_zod();
@@ -9735,7 +9757,7 @@ var init_chunk_BPCNB5RT = __esm({
9735
9757
  }
9736
9758
  });
9737
9759
 
9738
- // ../../packages/core/dist/chunk-OMZEKMYZ.js
9760
+ // ../../packages/core/dist/chunk-LM3FU67F.js
9739
9761
  function idempotencyHeaderRefusal(value) {
9740
9762
  if (typeof value !== "string" || !/^[A-Za-z0-9][A-Za-z0-9-]{0,63}$/.test(value)) {
9741
9763
  return "idempotency_header must be a header name: letters, digits and dashes, at most 64";
@@ -9746,10 +9768,10 @@ function idempotencyHeaderRefusal(value) {
9746
9768
  return null;
9747
9769
  }
9748
9770
  var CATALOG_REPLAY, REPLAY_OVERRIDES, RESERVED_HEADERS;
9749
- var init_chunk_OMZEKMYZ = __esm({
9750
- "../../packages/core/dist/chunk-OMZEKMYZ.js"() {
9771
+ var init_chunk_LM3FU67F = __esm({
9772
+ "../../packages/core/dist/chunk-LM3FU67F.js"() {
9751
9773
  "use strict";
9752
- init_chunk_45TIBJK6();
9774
+ init_chunk_QCQUZL4L();
9753
9775
  CATALOG_REPLAY = new Map(
9754
9776
  NATIVE_TOOLS.map((tool) => [tool.tool_name, tool.replay])
9755
9777
  );
@@ -9982,7 +10004,7 @@ var init_chunk_WEXVYJ5H = __esm({
9982
10004
  }
9983
10005
  });
9984
10006
 
9985
- // ../../packages/core/dist/chunk-L3SN4B6Q.js
10007
+ // ../../packages/core/dist/chunk-GEYJNCIJ.js
9986
10008
  function refineToolConfig(value, ctx) {
9987
10009
  const raw = value.tool_config;
9988
10010
  if (raw == null) return;
@@ -10018,10 +10040,10 @@ function refineToolConfig(value, ctx) {
10018
10040
  }
10019
10041
  }
10020
10042
  var toolIdParam, listToolsQuery, toolAgentQuery, deleteToolQuery, toolConnectionsQuery, nativeToolIdSchema, CONTEXT_BOUNDARIES, contextBoundarySchema, addNativeToolBody, addMcpToolBody, toolReplaySettingsFields, toolReplaySettingsSchema, createCustomToolBody, updateCustomToolBody, updateToolExecutionConfigBody;
10021
- var init_chunk_L3SN4B6Q = __esm({
10022
- "../../packages/core/dist/chunk-L3SN4B6Q.js"() {
10043
+ var init_chunk_GEYJNCIJ = __esm({
10044
+ "../../packages/core/dist/chunk-GEYJNCIJ.js"() {
10023
10045
  "use strict";
10024
- init_chunk_OMZEKMYZ();
10046
+ init_chunk_LM3FU67F();
10025
10047
  init_chunk_WEXVYJ5H();
10026
10048
  init_chunk_HZ6CADSY();
10027
10049
  init_zod();
@@ -10132,7 +10154,7 @@ var init_chunk_2ISUBJG7 = __esm({
10132
10154
  }
10133
10155
  });
10134
10156
 
10135
- // ../../packages/core/dist/chunk-KVO4NTS2.js
10157
+ // ../../packages/core/dist/chunk-7MRZJN4O.js
10136
10158
  function describeRole(role) {
10137
10159
  if (typeof role === "string") {
10138
10160
  return JSON.stringify(role.length > ROLE_ECHO_MAX ? `${role.slice(0, ROLE_ECHO_MAX)}\u2026` : role);
@@ -10220,6 +10242,13 @@ function evalInitialStateError(input) {
10220
10242
  }
10221
10243
  return null;
10222
10244
  }
10245
+ function evalCustomerContactIdError(input) {
10246
+ const record = asEvalInputRecord(input);
10247
+ if (record === null) return null;
10248
+ const value = record.customer_contact_id;
10249
+ if (value === void 0 || value === null) return null;
10250
+ return evalCustomerContactIdSchema.safeParse(value).success ? null : "customer_contact_id must be a contact id (a UUID)";
10251
+ }
10223
10252
  function evalNameError(name) {
10224
10253
  if (name === void 0) return null;
10225
10254
  if (typeof name === "string" && name.trim().length > 0) return null;
@@ -10251,6 +10280,12 @@ function refineEvalInitialState(value, ctx) {
10251
10280
  });
10252
10281
  }
10253
10282
  }
10283
+ function refineEvalCustomer(value, ctx) {
10284
+ const error = evalCustomerContactIdError(value.eval);
10285
+ if (error) {
10286
+ ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["eval", "customer_contact_id"], message: error });
10287
+ }
10288
+ }
10254
10289
  function refineEvalAttachments(value, ctx) {
10255
10290
  const triggerError = evalTurnAttachmentsError(value.eval.message_text);
10256
10291
  if (triggerError) {
@@ -10292,9 +10327,9 @@ function unprovenRunCount(counts) {
10292
10327
  function terminalRunCount(counts) {
10293
10328
  return counts.successful_runs + counts.failed_runs;
10294
10329
  }
10295
- var evalIdParam, sessionIdParam, scenarioSetIdParam, hubIdQuery, EVAL_FIXTURE_NAME_MAX_LENGTH, evalFixtureOverrideSchema, runSessionQuery, runJourneyQuery, EVAL_INPUT_ROLES, EVAL_INPUT_ROLE_LIST, ROLE_ECHO_MAX, EVAL_INITIAL_STATE_SCOPES, MAX_INITIAL_STATE_ENTRIES, evalInitialStateEntry, evalBody, EVAL_LIST_MAX_LIMIT, evalListLimit, getEvalsQuery, toggleEvalBody, bulkToggleEvalsBody, pacingConfigSchema, EVAL_MAX_SELECTED_SCENARIOS, evalScenarioSelectionEntrySchema, evalScenarioSelectionSchema, sessionConfigSchema, createSessionBody, getSessionsQuery, getSessionResultsQuery, getSessionRunsQuery, evalAnalyticsQuery, getSessionCostQuery, compareSessionsQuery, evalsSqlBody, evalsSqlSchemaQuery, exportResultsQuery, validateEvalBody, hubAgentsQuery, createScenarioSetBody, updateScenarioSetBody, scenarioSetsHubQuery, createScenarioFromConversationBody, createJourneyFromConversationBody, evalAttachmentRef, turnMayCarryAttachments, ATTACHMENTS_USER_ONLY_MESSAGE, journeyIdParam, journeyToolCallSchema, journeyTurnSchema, journeyStepOverrideSchema, fixtureField, createJourneyBody, updateJourneyBody, evalSessionConfigResponseSchema, evalSessionResponseSchema, evalSessionListConfigSchema, evalSessionListItemSchema, seedReleaseStatusSchema, EVAL_SESSION_NOT_QUIESCENT;
10296
- var init_chunk_KVO4NTS2 = __esm({
10297
- "../../packages/core/dist/chunk-KVO4NTS2.js"() {
10330
+ var evalIdParam, sessionIdParam, scenarioSetIdParam, hubIdQuery, EVAL_FIXTURE_NAME_MAX_LENGTH, evalFixtureOverrideSchema, runSessionQuery, runJourneyQuery, EVAL_INPUT_ROLES, EVAL_INPUT_ROLE_LIST, ROLE_ECHO_MAX, EVAL_INITIAL_STATE_SCOPES, MAX_INITIAL_STATE_ENTRIES, evalInitialStateEntry, evalCustomerContactIdSchema, evalBody, EVAL_LIST_MAX_LIMIT, evalListLimit, getEvalsQuery, toggleEvalBody, bulkToggleEvalsBody, pacingConfigSchema, EVAL_MAX_SELECTED_SCENARIOS, evalScenarioSelectionEntrySchema, evalScenarioSelectionSchema, sessionConfigSchema, createSessionBody, getSessionsQuery, getSessionResultsQuery, getSessionRunsQuery, evalAnalyticsQuery, getSessionCostQuery, compareSessionsQuery, evalsSqlBody, evalsSqlSchemaQuery, exportResultsQuery, validateEvalBody, hubAgentsQuery, createScenarioSetBody, updateScenarioSetBody, scenarioSetsHubQuery, createScenarioFromConversationBody, createJourneyFromConversationBody, evalAttachmentRef, turnMayCarryAttachments, ATTACHMENTS_USER_ONLY_MESSAGE, journeyIdParam, journeyToolCallSchema, journeyTurnSchema, journeyStepOverrideSchema, fixtureField, createJourneyBody, updateJourneyBody, evalSessionConfigResponseSchema, evalSessionResponseSchema, evalSessionListConfigSchema, evalSessionListItemSchema, seedReleaseStatusSchema, EVAL_SESSION_NOT_QUIESCENT;
10331
+ var init_chunk_7MRZJN4O = __esm({
10332
+ "../../packages/core/dist/chunk-7MRZJN4O.js"() {
10298
10333
  "use strict";
10299
10334
  init_chunk_4LXDRTO4();
10300
10335
  init_chunk_LZDVDC2S();
@@ -10331,9 +10366,10 @@ var init_chunk_KVO4NTS2 = __esm({
10331
10366
  scope: external_exports.enum(EVAL_INITIAL_STATE_SCOPES).default("user"),
10332
10367
  value: external_exports.record(external_exports.unknown())
10333
10368
  });
10369
+ evalCustomerContactIdSchema = uuidSchema;
10334
10370
  evalBody = external_exports.object({
10335
10371
  eval: external_exports.record(external_exports.unknown())
10336
- }).superRefine(refineEvalName).superRefine(refineEvalMessageTextRole).superRefine(refineEvalAttachments).superRefine(refineEvalInitialState);
10372
+ }).superRefine(refineEvalName).superRefine(refineEvalMessageTextRole).superRefine(refineEvalAttachments).superRefine(refineEvalInitialState).superRefine(refineEvalCustomer);
10337
10373
  EVAL_LIST_MAX_LIMIT = 1e3;
10338
10374
  evalListLimit = external_exports.string().regex(/^\d+$/).refine((v) => Number(v) <= EVAL_LIST_MAX_LIMIT, {
10339
10375
  message: `limit must be ${EVAL_LIST_MAX_LIMIT} or less`
@@ -11379,7 +11415,7 @@ var init_chunk_6NI5RAM4 = __esm({
11379
11415
  }
11380
11416
  });
11381
11417
 
11382
- // ../../packages/core/dist/chunk-UBTZT3O4.js
11418
+ // ../../packages/core/dist/chunk-54QBGDXF.js
11383
11419
  function refineHubAsCodeCustomTools(config, ctx) {
11384
11420
  const agents = config.agents;
11385
11421
  if (!Array.isArray(agents)) return;
@@ -11523,6 +11559,14 @@ function refineHubAsCodeEvals(config, ctx) {
11523
11559
  message: `eval "${entry?.name ?? "<unnamed>"}": ${initialStateError}`
11524
11560
  });
11525
11561
  }
11562
+ const customerError = evalCustomerContactIdError(entry);
11563
+ if (customerError) {
11564
+ ctx.addIssue({
11565
+ code: external_exports.ZodIssueCode.custom,
11566
+ path: ["evals", e, "customer_contact_id"],
11567
+ message: `eval "${entry?.name ?? "<unnamed>"}": ${customerError}`
11568
+ });
11569
+ }
11526
11570
  }
11527
11571
  }
11528
11572
  function refineHubAsCodeEvalAttachments(config, ctx) {
@@ -11899,12 +11943,12 @@ function refineHubAsCodeMonitorRulesOutput(config, ctx) {
11899
11943
  });
11900
11944
  }
11901
11945
  var MAX_10MB_BASE64_ENCODED_BYTES, MAX_EVAL_ATTACHMENT_ENCODED_BYTES, MAX_EVAL_ATTACHMENT_CARRIERS, MAX_EVAL_ATTACHMENT_AGGREGATE_ENCODED_BYTES, MAX_RESOURCE_ENCODED_BYTES, MAX_HUB_AS_CODE_RESOURCES, MAX_HUB_AS_CODE_RESOURCE_FILES, MAX_RESOURCE_AGGREGATE_ENCODED_BYTES, MAX_CI_CONFIG_BODY_BYTES, MAX_CALL_OPENING_CARRIERS, MAX_CALL_OPENING_AGGREGATE_ENCODED_BYTES, hubAsCodeStateSchema, hubAsCodeResourceFileSchema, hubAsCodeResourceSchema, uuidPattern, ciUuidSchema, boundedHubAsCodeResourcesSchema, hubAsCodeConfigSchema, ciPullHubIdParam, ciBranchParam, ciPullQuery, ciHubsQuery, ciLookupQuery, ciBranchesQuery, ciSyncBody, ciPushBody, ciDiffBody, ciPublishBody, ciPublishPreviewBody, ciSyncMcpBody, ciOrgResourcesParam, orgResourcesConfigSchema, ciOrgResourcesPushBody, ciOrgResourcesDiffBody, CI_APPLY_ENTITY_KINDS, CI_APPLY_OPERATIONS, ciApplyErrorBaseSchema, ciApplyErrorSchema, ciSyncCountSchema, ciSyncChangesSchema, ciSyncWarningSchema, ciSyncResponseSchema;
11902
- var init_chunk_UBTZT3O4 = __esm({
11903
- "../../packages/core/dist/chunk-UBTZT3O4.js"() {
11946
+ var init_chunk_54QBGDXF = __esm({
11947
+ "../../packages/core/dist/chunk-54QBGDXF.js"() {
11904
11948
  "use strict";
11905
- init_chunk_L3SN4B6Q();
11906
- init_chunk_KVO4NTS2();
11907
- init_chunk_STST7XWM();
11949
+ init_chunk_GEYJNCIJ();
11950
+ init_chunk_7MRZJN4O();
11951
+ init_chunk_BQWVW6JO();
11908
11952
  init_chunk_LBDH7LCG();
11909
11953
  init_chunk_4LXDRTO4();
11910
11954
  init_chunk_T4Q5COKJ();
@@ -12340,7 +12384,7 @@ var init_chunk_6J742GLA = __esm({
12340
12384
  }
12341
12385
  });
12342
12386
 
12343
- // ../../packages/core/dist/chunk-JR2ITK6N.js
12387
+ // ../../packages/core/dist/chunk-3HSB6J4J.js
12344
12388
  function normalizeContactPhone(raw) {
12345
12389
  const compact = raw.trim().replace(/[\s\-.()]/g, "");
12346
12390
  const withPlus = compact.startsWith("00") ? `+${compact.slice(2)}` : compact;
@@ -12352,9 +12396,9 @@ function normalizeContactLabel(raw) {
12352
12396
  function importRowLabels(row, batchLabels) {
12353
12397
  return [.../* @__PURE__ */ new Set([...row.labels ?? [], ...batchLabels ?? []])];
12354
12398
  }
12355
- var CONTACT_ENVIRONMENTS, CONTACT_NAME_MAX, CONTACT_EMAIL_MAX, CONTACT_PHONE_INPUT_MAX, CONTACT_INSTAGRAM_SID_MAX, CONTACT_METADATA_MAX_BYTES, CONTACT_LABEL_MAX, CONTACT_LABELS_MAX, CONTACT_SCOPE_TAGS_MAX, CONTACT_PAGE_MAX, CONTACT_IMPORT_BATCH_MAX, CONTACT_SEARCH_MAX, CONTACT_LIST_NAME_MAX, CONTACT_LIST_NAME_REGEX, CONTACT_LIST_DESCRIPTION_MAX, CONTACT_LIST_FILTER_MAX, CONTACT_LIST_PINS_PER_REQUEST_MAX, SUPPRESSION_SCOPES, SUPPRESSION_ID_REGEX, contactName, contactPhone, contactEmail, contactInstagramSid, contactLabel, contactLabels, contactMetadata, scopeTagIds, contactVisibilitySchema, hasIdentity, IDENTITY_REQUIRED, contactBookOrgQuery, contactBookContactParam, contactBookListParam, contactBookHubParam, contactBookPageQuery, listContactBookContactsQuery, listHubContactBookContactsQuery, contactBookLinkCandidatesQuery, listContactBookListMembersQuery, contactRowFields, createContactBookContactBody, updateContactBookContactBody, contactImportRowSchema, importContactBookContactsBody, linkContactBookContactBody, listName, contactListFilterSchema, createContactBookListBody, updateContactBookListBody, updateContactBookListPinsBody, suppressionIdentitySchema, createContactBookSuppressionBody, contactBookSuppressionParam, listContactBookSuppressionsQuery, contactBookEmailUnsubscribeTokenSchema, contactBookEmailUnsubscribeQuery, orgListReferenceSchema;
12356
- var init_chunk_JR2ITK6N = __esm({
12357
- "../../packages/core/dist/chunk-JR2ITK6N.js"() {
12399
+ var CONTACT_ENVIRONMENTS, CONTACT_NAME_MAX, CONTACT_EMAIL_MAX, CONTACT_PHONE_INPUT_MAX, CONTACT_INSTAGRAM_SID_MAX, CONTACT_METADATA_MAX_BYTES, CONTACT_LABEL_MAX, CONTACT_LABELS_MAX, CONTACT_SCOPE_TAGS_MAX, CONTACT_PAGE_MAX, CONTACT_IMPORT_BATCH_MAX, CONTACT_SEARCH_MAX, CONTACT_LIST_NAME_MAX, CONTACT_LIST_NAME_REGEX, CONTACT_LIST_DESCRIPTION_MAX, CONTACT_LIST_FILTER_MAX, CONTACT_LIST_PINS_PER_REQUEST_MAX, SUPPRESSION_SCOPES, SUPPRESSION_ID_REGEX, contactName, contactPhone, contactEmail, contactInstagramSid, contactLabel, contactLabels, contactMetadata, scopeTagIds, contactVisibilitySchema, hasIdentity, IDENTITY_REQUIRED, contactBookOrgQuery, contactBookContactParam, contactBookListParam, contactBookHubParam, contactBookPageQuery, listContactBookContactsQuery, listHubContactBookContactsQuery, contactBookLinkCandidatesQuery, listContactBookListMembersQuery, contactRowFields, createContactBookContactBody, updateContactBookContactBody, contactImportRowSchema, importContactBookContactsBody, linkContactBookContactBody, CONTACT_CUSTOMER_BASE_ID_PATTERN, baseId, recordId, linkContactCustomerBody, unlinkContactCustomerQuery, listName, contactListFilterSchema, createContactBookListBody, updateContactBookListBody, updateContactBookListPinsBody, suppressionIdentitySchema, createContactBookSuppressionBody, contactBookSuppressionParam, listContactBookSuppressionsQuery, contactBookEmailUnsubscribeTokenSchema, contactBookEmailUnsubscribeQuery, orgListReferenceSchema;
12400
+ var init_chunk_3HSB6J4J = __esm({
12401
+ "../../packages/core/dist/chunk-3HSB6J4J.js"() {
12358
12402
  "use strict";
12359
12403
  init_zod();
12360
12404
  CONTACT_ENVIRONMENTS = ["production", "preview", "all"];
@@ -12473,6 +12517,16 @@ var init_chunk_JR2ITK6N = __esm({
12473
12517
  linkContactBookContactBody = external_exports.object({
12474
12518
  user_id: external_exports.string().min(1).max(128)
12475
12519
  }).strict();
12520
+ CONTACT_CUSTOMER_BASE_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
12521
+ baseId = external_exports.string().regex(CONTACT_CUSTOMER_BASE_ID_PATTERN, { message: "Must be a base id" });
12522
+ recordId = external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_\-.:]{0,254}$/, { message: "Must be a record id" });
12523
+ linkContactCustomerBody = external_exports.object({
12524
+ base_id: baseId,
12525
+ record_id: recordId
12526
+ }).strict();
12527
+ unlinkContactCustomerQuery = contactBookOrgQuery.extend({
12528
+ base_id: baseId
12529
+ });
12476
12530
  listName = external_exports.string().trim().min(1).max(CONTACT_LIST_NAME_MAX).regex(CONTACT_LIST_NAME_REGEX, {
12477
12531
  message: 'Must be lowercase alphanumeric with hyphens (e.g. "vip-customers")'
12478
12532
  });
@@ -12515,14 +12569,14 @@ var init_chunk_JR2ITK6N = __esm({
12515
12569
  }
12516
12570
  });
12517
12571
 
12518
- // ../../packages/core/dist/chunk-EA2IJGKN.js
12572
+ // ../../packages/core/dist/chunk-XCDUP42J.js
12519
12573
  var COMMUNITIES_PER_ORG_MAX, COMMUNITY_NAME_MAX_LENGTH, COMMUNITY_REGISTRY_CLOSED_REASON, COMMUNITY_MEMBERS_MAX, COMMUNITY_ADMISSIONS, COMMUNITY_ACCESS_MAX, COMMUNITY_ACCESS_ADD_MAX, COMMUNITY_ACCESS_FULL_REASON, COMMUNITY_JOIN_SOURCE_MAX_LENGTH, COMMUNITY_JOIN_FLOW_TOKEN_MAX_LENGTH, COMMUNITY_ROOMS_MAX, COMMUNITY_ROOM_NAME_MAX_LENGTH, COMMUNITY_MESSAGE_MAX_LENGTH, COMMUNITY_MESSAGES_PAGE_SIZE, COMMUNITY_ATTACHMENT_URLS_MAX, COMMUNITY_POST_TITLE_MAX_LENGTH, COMMUNITY_POST_SEARCH_MAX_LENGTH, COMMUNITY_MEMBER_STATUSES, COMMUNITY_RULES_MAX_LENGTH, COMMUNITY_SLOW_MODE_MAX_SECONDS, COMMUNITY_COURSES_LABEL_MAX_LENGTH, COMMUNITY_LIVE_TICKET_PREFIX, COMMUNITY_STATS_DAYS, communityNameSchema, adminCreateCommunityBody, communityIdParam, communityJoinTokenSchema, communityJoinSourceSchema, communityJoinPreviewQuery, communityJoinBody, communityRoomKindSchema, communityRoomNameSchema, communityRoomIdParam, communityMessageIdParam, communityRoomCreateBody, communityRoomUpdateBody, communityMessagesQuery, communityMessageBodySchema, communityPostTitleSchema, communityAttachmentUploadSchema, communitySendBody, communityEditBody, communityPostIdParam, communityPostsQuery, communityAnswerBody, communityReadBody, communityAttachmentUrlsBody, communityPersonParam, communityOrgParam, communityPeopleQuery, communityCoursesLabelSchema, communityAdmissionSchema, communitySettingsBody, communityAccessEmailSchema, communityAccessAddBody, communityAccessQuery, communityAccessIdParam, communityBanBody, communityLockBody, communityPinBody, communityModLogQuery, communityReportsQuery, communityReportIdParam, communityLiveTicketSchema, communityLiveQuery, communityMuteBody, communityEmailUnsubscribeTokenSchema, communityEmailUnsubscribeQuery;
12520
- var init_chunk_EA2IJGKN = __esm({
12521
- "../../packages/core/dist/chunk-EA2IJGKN.js"() {
12574
+ var init_chunk_XCDUP42J = __esm({
12575
+ "../../packages/core/dist/chunk-XCDUP42J.js"() {
12522
12576
  "use strict";
12523
12577
  init_chunk_6J742GLA();
12524
12578
  init_chunk_ZVXO3XL6();
12525
- init_chunk_JR2ITK6N();
12579
+ init_chunk_3HSB6J4J();
12526
12580
  init_chunk_HZ6CADSY();
12527
12581
  init_zod();
12528
12582
  COMMUNITIES_PER_ORG_MAX = 10;
@@ -12623,7 +12677,7 @@ var init_chunk_EA2IJGKN = __esm({
12623
12677
  }
12624
12678
  });
12625
12679
 
12626
- // ../../packages/core/dist/chunk-QAWIPRNA.js
12680
+ // ../../packages/core/dist/chunk-3KYTITOR.js
12627
12681
  function parseCommunityLessonVideoUrl(url) {
12628
12682
  const parts = /^https?:\/\/([^/?#]+)([^?#]*)(?:\?([^#]*))?(?:#.*)?$/i.exec(url.trim());
12629
12683
  if (!parts) return null;
@@ -12649,10 +12703,10 @@ function communityLessonVideoWatchUrl(video) {
12649
12703
  }
12650
12704
  }
12651
12705
  var COMMUNITY_COURSES_MAX, COMMUNITY_COURSE_MODULES_MAX, COMMUNITY_COURSE_LESSONS_MAX, COMMUNITY_LESSONS_MAX, COMMUNITY_COURSE_TITLE_MAX_LENGTH, COMMUNITY_COURSE_DESCRIPTION_MAX_LENGTH, COMMUNITY_LESSON_BODY_MAX_LENGTH, COMMUNITY_LESSON_LINKS_MAX, COMMUNITY_LESSON_URL_MAX_LENGTH, YOUTUBE_ID, YOUTUBE_HOSTS, YOUTU_BE, YOUTUBE_ID_PATH, communityCourseIdParam, communityCourseModuleIdParam, communityLessonIdParam, communityCourseTitleSchema, communityCourseDescriptionSchema, communityCoursePositionSchema, communityLessonVideoUrlSchema, communityLessonLinkSchema, communityLessonLinksSchema, communityLessonBodySchema, communityCourseCreateBody, communityCourseUpdateBody, communityModuleCreateBody, communityModuleUpdateBody, communityLessonCreateBody, communityLessonUpdateBody;
12652
- var init_chunk_QAWIPRNA = __esm({
12653
- "../../packages/core/dist/chunk-QAWIPRNA.js"() {
12706
+ var init_chunk_3KYTITOR = __esm({
12707
+ "../../packages/core/dist/chunk-3KYTITOR.js"() {
12654
12708
  "use strict";
12655
- init_chunk_EA2IJGKN();
12709
+ init_chunk_XCDUP42J();
12656
12710
  init_chunk_HZ6CADSY();
12657
12711
  init_zod();
12658
12712
  COMMUNITY_COURSES_MAX = 20;
@@ -12868,15 +12922,15 @@ var init_chunk_ZHJEQBXJ = __esm({
12868
12922
  }
12869
12923
  });
12870
12924
 
12871
- // ../../packages/core/dist/chunk-WNWIYFR3.js
12925
+ // ../../packages/core/dist/chunk-LQY2OCQL.js
12872
12926
  function filterNamesAnything(filter) {
12873
12927
  return filter.labels.length + filter.scope_tag_ids.length > 0;
12874
12928
  }
12875
12929
  var hubListNameSchema, HUB_LIST_FILTER_REQUIRED, hubContactListFilterSchema, hubContactListIdParam, hubContactListHubQuery, description, createHubContactListBody, updateHubContactListBody;
12876
- var init_chunk_WNWIYFR3 = __esm({
12877
- "../../packages/core/dist/chunk-WNWIYFR3.js"() {
12930
+ var init_chunk_LQY2OCQL = __esm({
12931
+ "../../packages/core/dist/chunk-LQY2OCQL.js"() {
12878
12932
  "use strict";
12879
- init_chunk_JR2ITK6N();
12933
+ init_chunk_3HSB6J4J();
12880
12934
  init_zod();
12881
12935
  hubListNameSchema = orgListReferenceSchema;
12882
12936
  HUB_LIST_FILTER_REQUIRED = "A hub list names at least one label or scope tag";
@@ -12918,14 +12972,14 @@ var init_chunk_F3JHI4Y4 = __esm({
12918
12972
  }
12919
12973
  });
12920
12974
 
12921
- // ../../packages/core/dist/chunk-FAVLH62F.js
12975
+ // ../../packages/core/dist/chunk-MTQ6G7VB.js
12922
12976
  var AUTOMATION_TRIGGER_TYPES, AUTOMATION_EVENT_TYPES, AUTOMATION_TARGET_TYPES, AUTOMATION_ACTION_TYPES, AUTOMATION_CHANNEL_TYPES, AUTOMATION_PURPOSES, AUTOMATION_NAME_MAX, AUTOMATION_DESCRIPTION_MAX, AUTOMATION_INSTRUCTIONS_MAX, AUTOMATION_TEXT_MAX, AUTOMATION_CRON_MAX, AUTOMATION_WEBHOOK_AUTHS, AUTOMATION_WEBHOOK_HEADERS, AUTOMATION_WEBHOOK_BODY_MAX_BYTES, AUTOMATION_WEBHOOK_HEADER_NAME_MAX, WEBHOOK_RESERVED_HEADERS, automationTriggerSchema, automationTargetSchema, automationActionSchema, automationGateSchema, automationName, automationDescription, automationIdParam, automationHubQuery, automationWebhookParams, AUTOMATION_RUNS_PAGE_MAX, listAutomationRunsQuery, createAutomationBody, updateAutomationBody, AUTOMATION_ALERT_CATEGORIES, AUTOMATION_BLOCKED_ALERT_CATEGORY, automationEventSubscriberParam;
12923
- var init_chunk_FAVLH62F = __esm({
12924
- "../../packages/core/dist/chunk-FAVLH62F.js"() {
12977
+ var init_chunk_MTQ6G7VB = __esm({
12978
+ "../../packages/core/dist/chunk-MTQ6G7VB.js"() {
12925
12979
  "use strict";
12926
- init_chunk_WNWIYFR3();
12927
- init_chunk_STST7XWM();
12928
- init_chunk_JR2ITK6N();
12980
+ init_chunk_LQY2OCQL();
12981
+ init_chunk_BQWVW6JO();
12982
+ init_chunk_3HSB6J4J();
12929
12983
  init_chunk_F3JHI4Y4();
12930
12984
  init_chunk_DHPUPI4Y();
12931
12985
  init_chunk_T7KQKDET();
@@ -14182,15 +14236,15 @@ var init_contracts = __esm({
14182
14236
  init_chunk_ACKF2MVU();
14183
14237
  init_chunk_Y7CFCYX4();
14184
14238
  init_chunk_5DGHIY7L();
14185
- init_chunk_4I3WSYXD();
14186
- init_chunk_KWBAMM7C();
14239
+ init_chunk_BVQE66I2();
14240
+ init_chunk_BEOHBREG();
14187
14241
  init_chunk_IPDOHAZ5();
14188
14242
  init_chunk_GPM7PE44();
14189
14243
  init_chunk_YUZFHVB2();
14190
14244
  init_chunk_34LE6P7E();
14191
14245
  init_chunk_FPSDNS2E();
14192
14246
  init_chunk_ZXK6N2HN();
14193
- init_chunk_73J42LZ3();
14247
+ init_chunk_VOC3AGY4();
14194
14248
  init_chunk_C4HEZ7ZI();
14195
14249
  init_chunk_IR2NOSI3();
14196
14250
  init_chunk_EA23LSDS();
@@ -14198,25 +14252,25 @@ var init_contracts = __esm({
14198
14252
  init_chunk_LWMLR2WI();
14199
14253
  init_chunk_ACGAI25T();
14200
14254
  init_chunk_MH4O3YEX();
14201
- init_chunk_RKJYFGBO();
14255
+ init_chunk_SPE6FAYO();
14202
14256
  init_chunk_KSTYTQ7I();
14203
14257
  init_chunk_LKBSHANA();
14204
14258
  init_chunk_BPCNB5RT();
14205
- init_chunk_UBTZT3O4();
14206
- init_chunk_L3SN4B6Q();
14207
- init_chunk_KVO4NTS2();
14259
+ init_chunk_54QBGDXF();
14260
+ init_chunk_GEYJNCIJ();
14261
+ init_chunk_7MRZJN4O();
14208
14262
  init_chunk_JDJ4EUOL();
14209
- init_chunk_QAWIPRNA();
14210
- init_chunk_EA2IJGKN();
14263
+ init_chunk_3KYTITOR();
14264
+ init_chunk_XCDUP42J();
14211
14265
  init_chunk_6J742GLA();
14212
14266
  init_chunk_ZVXO3XL6();
14213
14267
  init_chunk_YULHXJ5M();
14214
14268
  init_chunk_3O5XTDI2();
14215
14269
  init_chunk_ZHJEQBXJ();
14216
- init_chunk_FAVLH62F();
14217
- init_chunk_WNWIYFR3();
14218
- init_chunk_STST7XWM();
14219
- init_chunk_JR2ITK6N();
14270
+ init_chunk_MTQ6G7VB();
14271
+ init_chunk_LQY2OCQL();
14272
+ init_chunk_BQWVW6JO();
14273
+ init_chunk_3HSB6J4J();
14220
14274
  init_chunk_IG6QBZMA();
14221
14275
  init_chunk_ZJJ5ODOD();
14222
14276
  init_chunk_PZPOUXJR();
@@ -14224,9 +14278,9 @@ var init_contracts = __esm({
14224
14278
  init_chunk_4LXDRTO4();
14225
14279
  init_chunk_E4DIIOOE();
14226
14280
  init_chunk_7CYHPF35();
14227
- init_chunk_LR5WDVCH();
14228
- init_chunk_OMZEKMYZ();
14229
- init_chunk_45TIBJK6();
14281
+ init_chunk_FMXFEZN4();
14282
+ init_chunk_LM3FU67F();
14283
+ init_chunk_QCQUZL4L();
14230
14284
  init_chunk_NVKU5PPQ();
14231
14285
  init_chunk_2FCLSQSQ();
14232
14286
  init_chunk_FECLIZTY();
@@ -14430,6 +14484,19 @@ var init_api_client = __esm({
14430
14484
  }
14431
14485
  // The org-admin community routes (gh #5003, `wayai communities`): an owner or admin of the
14432
14486
  // community's org, on an interactive session only — a scoped token is refused with 403.
14487
+ /**
14488
+ * Link a contact to its customer record, a root record of one of the org's bases (#5083 RK2 A3).
14489
+ * A browser sign-in only: the route refuses an API token.
14490
+ */
14491
+ async linkContactCustomer(orgId, contactId, body) {
14492
+ const qs = new URLSearchParams({ organization_id: orgId });
14493
+ return this.request("PUT", `/api/contact-book/contacts/${encodeURIComponent(contactId)}/customer?${qs}`, body);
14494
+ }
14495
+ /** Unlink a contact from its customer record in one base (owner decision 142). A browser sign-in only. */
14496
+ async unlinkContactCustomer(orgId, contactId, baseId2) {
14497
+ const qs = new URLSearchParams({ organization_id: orgId, base_id: baseId2 });
14498
+ return this.request("DELETE", `/api/contact-book/contacts/${encodeURIComponent(contactId)}/customer?${qs}`);
14499
+ }
14433
14500
  async listOrgCommunities(orgId) {
14434
14501
  return this.request("GET", `/api/communities/orgs/${encodeURIComponent(orgId)}`);
14435
14502
  }
@@ -17263,6 +17330,7 @@ var init_utils = __esm({
17263
17330
  "conversations",
17264
17331
  "alerts",
17265
17332
  "communities",
17333
+ "contacts",
17266
17334
  "knowledge"
17267
17335
  ]);
17268
17336
  HELP_AND_VERSION = ["help", "--help", "-h", "--version", "-v"];
@@ -17270,6 +17338,7 @@ var init_utils = __esm({
17270
17338
  ["pull", "all"],
17271
17339
  ["push", "all"],
17272
17340
  ["communities", "all"],
17341
+ ["contacts", "all"],
17273
17342
  ["knowledge", "all"],
17274
17343
  ["use", "selectors"],
17275
17344
  ["unbind", "selectors"],
@@ -20217,6 +20286,13 @@ function parseEvalYaml(filePath2, relPath, setName, hubFolder, bytesByHash) {
20217
20286
  if (targetBase) evalEntry.target_base = targetBase;
20218
20287
  const initialState = parseInitialStateField(data.initial_state, `Eval "${evalName}" in ${relPath}`);
20219
20288
  if (initialState) evalEntry.initial_state = initialState;
20289
+ const customer = parseFixtureField(
20290
+ data.customer_contact_id,
20291
+ `Eval "${evalName}" in ${relPath}`,
20292
+ "customer_contact_id",
20293
+ "the customer's contact id"
20294
+ );
20295
+ if (customer) evalEntry.customer_contact_id = customer;
20220
20296
  return evalEntry;
20221
20297
  }
20222
20298
  function parseInitialStateField(raw, label) {
@@ -20253,10 +20329,10 @@ function parseVariablesMap(raw, label) {
20253
20329
  }
20254
20330
  return vars;
20255
20331
  }
20256
- function parseFixtureField(raw, label, key) {
20332
+ function parseFixtureField(raw, label, key, hint = "the Rekor fixture name") {
20257
20333
  if (raw === void 0 || raw === null) return void 0;
20258
20334
  if (typeof raw !== "string") {
20259
- throw expected(`${label}: "${key}" must be a string (the Rekor fixture name).`);
20335
+ throw expected(`${label}: "${key}" must be a string (${hint}).`);
20260
20336
  }
20261
20337
  const trimmed = raw.trim();
20262
20338
  return trimmed.length > 0 ? trimmed : void 0;
@@ -20506,6 +20582,9 @@ function buildEvalYamlObject(evalEntry, slug) {
20506
20582
  if (Array.isArray(evalEntry.initial_state) && evalEntry.initial_state.length > 0) {
20507
20583
  out.initial_state = evalEntry.initial_state;
20508
20584
  }
20585
+ if (typeof evalEntry.customer_contact_id === "string" && evalEntry.customer_contact_id) {
20586
+ out.customer_contact_id = evalEntry.customer_contact_id;
20587
+ }
20509
20588
  assertAttachmentsAreLocalPaths(evalEntry.input, `eval "${evalEntry.name}" input`);
20510
20589
  out.input = evalEntry.input;
20511
20590
  out.expected = evalEntry.expected;
@@ -21611,12 +21690,12 @@ function writeBaseFolder(folder, meta, config) {
21611
21690
  }
21612
21691
  return delta;
21613
21692
  }
21614
- function markProductionMirror(folder, baseId) {
21693
+ function markProductionMirror(folder, baseId2) {
21615
21694
  const file = path21.join(folder, BASE_META_FILE);
21616
21695
  try {
21617
21696
  const body = readFileNoFollow(folder, file)?.toString("utf-8");
21618
21697
  if (body === void 0 || body.startsWith(MIRROR_MARKER_PREFIX)) return;
21619
- const banner = `${MIRROR_MARKER_PREFIX} "${baseId}". Edits are ignored; \`wayai push\` refuses it. Edit the linked preview instead.
21698
+ const banner = `${MIRROR_MARKER_PREFIX} "${baseId2}". Edits are ignored; \`wayai push\` refuses it. Edit the linked preview instead.
21620
21699
  `;
21621
21700
  writeFileNoFollow(folder, file, Buffer.from(banner + body, "utf-8"));
21622
21701
  } catch {
@@ -21742,10 +21821,10 @@ function createPreview(client, originId, opts) {
21742
21821
  ...opts.analytics ? { analytics: opts.analytics } : {}
21743
21822
  });
21744
21823
  }
21745
- function deleteEntity(client, baseId, kind, id) {
21824
+ function deleteEntity(client, baseId2, kind, id) {
21746
21825
  return client.request(
21747
21826
  "DELETE",
21748
- `/v1/${pathSegment(baseId, "base id")}/${ENTITY_DIRS[kind]}/${pathSegment(id, `${kind} id`)}`
21827
+ `/v1/${pathSegment(baseId2, "base id")}/${ENTITY_DIRS[kind]}/${pathSegment(id, `${kind} id`)}`
21749
21828
  );
21750
21829
  }
21751
21830
  var init_api = __esm({
@@ -21944,40 +22023,40 @@ async function pullBase(gitRootOrNull, selector, args2) {
21944
22023
  const gitRoot = requireGitRoot(gitRootOrNull);
21945
22024
  const target = resolveBaseTarget(gitRoot, selector);
21946
22025
  const basesDir = resolveBasesDir(gitRoot);
21947
- const baseId = targetBaseId(target, selector);
21948
- if (!baseId) {
22026
+ const baseId2 = targetBaseId(target, selector);
22027
+ if (!baseId2) {
21949
22028
  throw expected(
21950
22029
  `Could not determine the base id for ${target.folder}. Pass the base id explicitly.`
21951
22030
  );
21952
22031
  }
21953
22032
  const client = await createDataClient();
21954
22033
  console.log("Fetching base configuration...");
21955
- const record = await getBaseRecord(client, baseId);
22034
+ const record = await getBaseRecord(client, baseId2);
21956
22035
  if (record.environment === "production") {
21957
- const folder = await writeProductionMirror(client, basesDir, record.id ?? baseId, record);
22036
+ const folder = await writeProductionMirror(client, basesDir, record.id ?? baseId2, record);
21958
22037
  console.log(`Production base mirrored (read-only) \u2192 ${folder}`);
21959
22038
  return;
21960
22039
  }
21961
- assertInScope("bases", baseId);
22040
+ assertInScope("bases", baseId2);
21962
22041
  if (target.exists && !autoConfirm) {
21963
22042
  const ok = await confirm(
21964
- `Overwrite local files in ${path23.relative(gitRoot, target.folder)} with the server config for "${sanitizeTerminalText(baseId)}"?`
22043
+ `Overwrite local files in ${path23.relative(gitRoot, target.folder)} with the server config for "${sanitizeTerminalText(baseId2)}"?`
21965
22044
  );
21966
22045
  if (!ok) {
21967
22046
  console.log("Cancelled.");
21968
22047
  return;
21969
22048
  }
21970
22049
  }
21971
- const config = await getConfig(client, baseId);
22050
+ const config = await getConfig(client, baseId2);
21972
22051
  const isFirstPull = !target.exists;
21973
- const delta = writeBaseFolder(target.folder, metaFromRecord(record, baseId), config);
22052
+ const delta = writeBaseFolder(target.folder, metaFromRecord(record, baseId2), config);
21974
22053
  console.log(`Base configuration written to ${target.folder}`);
21975
22054
  console.log(
21976
22055
  ` ${ENTITY_KINDS.map((kind) => `${(config[kind] ?? []).length} ${kind}`).join(", ")}`
21977
22056
  );
21978
22057
  if (!isFirstPull) printLocalFileChanges(delta);
21979
22058
  console.log(" Credential values are not written. Manage them with `wayai bases credentials`.");
21980
- seedScopeIfEmpty("bases", baseId);
22059
+ seedScopeIfEmpty("bases", baseId2);
21981
22060
  if (record.origin_base_id) {
21982
22061
  await mirrorLinkedProduction(client, basesDir, record.origin_base_id);
21983
22062
  }
@@ -22047,25 +22126,25 @@ async function pushBase(gitRootOrNull, selector, args2) {
22047
22126
  return;
22048
22127
  }
22049
22128
  const client = await createDataClient();
22050
- let baseId = meta.base_id;
22051
- if (!baseId) {
22129
+ let baseId2 = meta.base_id;
22130
+ if (!baseId2) {
22052
22131
  const created = await createDeclaredPreview(client, target, parsed, autoConfirm);
22053
22132
  if (!created) return;
22054
- baseId = created;
22133
+ baseId2 = created;
22055
22134
  } else {
22056
- const record = await getBaseRecord(client, baseId);
22135
+ const record = await getBaseRecord(client, baseId2);
22057
22136
  if (record.environment && record.environment !== "preview") {
22058
22137
  throw expected(
22059
- `"${sanitizeTerminalText(baseId)}" is a ${sanitizeTerminalText(record.environment)} base. Push operates on previews \u2014 promote with \`wayai bases promote\`.`
22138
+ `"${sanitizeTerminalText(baseId2)}" is a ${sanitizeTerminalText(record.environment)} base. Push operates on previews \u2014 promote with \`wayai bases promote\`.`
22060
22139
  );
22061
22140
  }
22062
- assertInScope("bases", baseId);
22141
+ assertInScope("bases", baseId2);
22063
22142
  }
22064
- const diff = await diffConfig(client, baseId, config);
22143
+ const diff = await diffConfig(client, baseId2, config);
22065
22144
  printLintWarnings(diff.warnings);
22066
22145
  if (isDiffEmpty(diff)) {
22067
- console.log(`No changes \u2014 preview "${sanitizeTerminalText(baseId)}" already matches your files.`);
22068
- if (!dryRun) seedScopeIfEmpty("bases", baseId);
22146
+ console.log(`No changes \u2014 preview "${sanitizeTerminalText(baseId2)}" already matches your files.`);
22147
+ if (!dryRun) seedScopeIfEmpty("bases", baseId2);
22069
22148
  return;
22070
22149
  }
22071
22150
  console.log(renderDiff(diff));
@@ -22075,13 +22154,13 @@ async function pushBase(gitRootOrNull, selector, args2) {
22075
22154
  }
22076
22155
  if (!autoConfirm) {
22077
22156
  const ok = await confirm(`
22078
- Apply these changes to preview "${sanitizeTerminalText(baseId)}"?`);
22157
+ Apply these changes to preview "${sanitizeTerminalText(baseId2)}"?`);
22079
22158
  if (!ok) {
22080
22159
  console.log("Cancelled.");
22081
22160
  return;
22082
22161
  }
22083
22162
  }
22084
- const result = await applyConfig(client, baseId, config);
22163
+ const result = await applyConfig(client, baseId2, config);
22085
22164
  const secretGroups = [
22086
22165
  ["trigger", result.new_trigger_secrets],
22087
22166
  ["inbound webhook", result.new_inbound_webhook_secrets]
@@ -22108,7 +22187,7 @@ ${RED}${removals.length} ${word} not in your files were left on the base. Re-run
22108
22187
  Delete ${removals.length} server ${word} not in your files? Record types cascade to their records.`
22109
22188
  )) {
22110
22189
  for (const removal of removals) {
22111
- await deleteEntity(client, baseId, removal.kind, removal.id);
22190
+ await deleteEntity(client, baseId2, removal.kind, removal.id);
22112
22191
  console.log(` - deleted ${removal.kind} ${sanitizeTerminalText(removal.id)}`);
22113
22192
  }
22114
22193
  } else {
@@ -22116,8 +22195,8 @@ Delete ${removals.length} server ${word} not in your files? Record types cascade
22116
22195
  }
22117
22196
  }
22118
22197
  console.log(`
22119
- Pushed to preview "${sanitizeTerminalText(baseId)}".`);
22120
- seedScopeIfEmpty("bases", baseId);
22198
+ Pushed to preview "${sanitizeTerminalText(baseId2)}".`);
22199
+ seedScopeIfEmpty("bases", baseId2);
22121
22200
  }
22122
22201
  var init_sync = __esm({
22123
22202
  "src/data/config-as-code/sync.ts"() {
@@ -27518,9 +27597,9 @@ async function conversationsCommand(args2) {
27518
27597
  if (result.partial || result.hubs_queried === 0) process.exit(1);
27519
27598
  return;
27520
27599
  }
27521
- for (const failure of result.errors) {
27522
- const where = failure.scope_kind === "hub" ? `hub ${sanitizeTerminalText(failure.hub_name || failure.hub_id || "")} (${failure.hub_id})` : `organization ${failure.organization_id}`;
27523
- console.error(`Could not read ${where}: ${sanitizeTerminalText(failure.error)}`);
27600
+ for (const failure2 of result.errors) {
27601
+ const where = failure2.scope_kind === "hub" ? `hub ${sanitizeTerminalText(failure2.hub_name || failure2.hub_id || "")} (${failure2.hub_id})` : `organization ${failure2.organization_id}`;
27602
+ console.error(`Could not read ${where}: ${sanitizeTerminalText(failure2.error)}`);
27524
27603
  }
27525
27604
  if (result.hubs_queried === 0) {
27526
27605
  console.error(
@@ -33017,12 +33096,128 @@ These commands need a browser sign-in (\`wayai login\`). An API token
33017
33096
  }
33018
33097
  });
33019
33098
 
33099
+ // src/commands/contacts.ts
33100
+ var contacts_exports = {};
33101
+ __export(contacts_exports, {
33102
+ contactsCommand: () => contactsCommand
33103
+ });
33104
+ import { parseArgs as parseArgs22 } from "util";
33105
+ function usageError2(message) {
33106
+ return expected(`${message}
33107
+
33108
+ ${USAGE3}`);
33109
+ }
33110
+ function parse2(args2) {
33111
+ try {
33112
+ return parseArgs22({
33113
+ args: args2,
33114
+ options: {
33115
+ org: { type: "string" },
33116
+ base: { type: "string" },
33117
+ record: { type: "string" },
33118
+ json: { type: "boolean" }
33119
+ },
33120
+ allowPositionals: true,
33121
+ strict: true
33122
+ });
33123
+ } catch (err) {
33124
+ throw usageError2(err instanceof Error ? err.message : String(err));
33125
+ }
33126
+ }
33127
+ function resolveOrgId2(flag) {
33128
+ if (flag !== void 0) {
33129
+ if (!UUID_RE3.test(flag)) throw expected(`Invalid --org ${JSON.stringify(flag)}: expected an organization id (a UUID).`);
33130
+ return flag;
33131
+ }
33132
+ const bound = readRepoConfigUnlessBlocked()?.organization_id;
33133
+ if (bound) return bound;
33134
+ throw expected("No organization: pass --org <org_id>, or run this inside a workspace scoped with `wayai init`.");
33135
+ }
33136
+ function failure(err, accessToken) {
33137
+ if (!(err instanceof ApiError)) return err;
33138
+ if (err.status === 403 && identifyTokenType(accessToken) === "way_token") {
33139
+ const override2 = envTokenOverride() ? " WAYAI_TOKEN is set in this shell and is sent instead of your sign-in: unset it first." : "";
33140
+ return expected(
33141
+ `A contact's customer record is linked from a browser sign-in only, and this login is an API token. Run \`wayai login\` (without --token).${override2}`
33142
+ );
33143
+ }
33144
+ if (err.status >= 400 && err.status < 500) return expected(sanitizeTerminalText(extractApiMessage(err)));
33145
+ return err;
33146
+ }
33147
+ async function contactsCommand(args2) {
33148
+ if (wantsHelp(args2) || args2.length === 0) {
33149
+ console.log(USAGE3);
33150
+ return;
33151
+ }
33152
+ const { values, positionals } = parse2(args2);
33153
+ const [sub, contactId, ...extra] = positionals;
33154
+ if (!SUBCOMMANDS2.includes(sub)) throw usageError2(`Unknown subcommand ${JSON.stringify(sub)}.`);
33155
+ if (contactId === void 0 || extra.length > 0) throw usageError2(`${sub} takes one <contact_id>.`);
33156
+ if (!UUID_RE3.test(contactId)) throw usageError2(`Invalid <contact_id> ${JSON.stringify(contactId)}: expected a contact id (a UUID).`);
33157
+ if (!values.base) throw usageError2(`${sub} needs --base <base_id>.`);
33158
+ if (!isValidBaseId(values.base)) throw usageError2(`Invalid --base ${JSON.stringify(values.base)}: a base id is ${BASE_ID_RULE}.`);
33159
+ if (sub === "link-customer" && !values.record) throw usageError2("link-customer needs --record <record_id>.");
33160
+ if (sub === "unlink-customer" && values.record !== void 0) throw usageError2("--record applies only to link-customer.");
33161
+ const orgId = resolveOrgId2(values.org);
33162
+ const { config, accessToken } = await requireAuth();
33163
+ const api = new ApiClient({ apiUrl: config.api_url, accessToken, onUnauthorized: () => getAccessToken(config) });
33164
+ let customer;
33165
+ try {
33166
+ ({ customer } = sub === "link-customer" ? await api.linkContactCustomer(orgId, contactId, { base_id: values.base, record_id: values.record }) : await api.unlinkContactCustomer(orgId, contactId, values.base));
33167
+ } catch (err) {
33168
+ throw failure(err, accessToken);
33169
+ }
33170
+ if (values.json) {
33171
+ console.log(JSON.stringify(customer, null, 2));
33172
+ return;
33173
+ }
33174
+ const where = `base ${sanitizeTerminalText(customer.base_id)} (${sanitizeTerminalText(customer.record_type)})`;
33175
+ console.log(sub === "link-customer" ? `Contact ${customer.contact_id} is linked to customer record ${sanitizeTerminalText(customer.record_id)} in ${where}.` : `Contact ${customer.contact_id} is unlinked from customer record ${sanitizeTerminalText(customer.record_id)} in ${where}; the record keeps the contact id under ${customer.external_source}.`);
33176
+ }
33177
+ var USAGE3, SUBCOMMANDS2;
33178
+ var init_contacts = __esm({
33179
+ "src/commands/contacts.ts"() {
33180
+ "use strict";
33181
+ init_auth();
33182
+ init_api_client();
33183
+ init_errors2();
33184
+ init_expected();
33185
+ init_repo_config();
33186
+ init_terminal_output();
33187
+ init_token_store();
33188
+ init_base_id();
33189
+ init_utils();
33190
+ USAGE3 = `
33191
+ wayai contacts \u2014 a contact's customer record in one of the organization's bases
33192
+
33193
+ Usage:
33194
+ wayai contacts link-customer <contact_id> --base <base_id> --record <record_id> [--org <org_id>] [--json]
33195
+ wayai contacts unlink-customer <contact_id> --base <base_id> [--org <org_id>] [--json]
33196
+
33197
+ link-customer Make the record the contact's customer record: a conversation with the
33198
+ contact (its WhatsApp phone, Instagram id or app account) then serves that
33199
+ customer through a customer-scoped toolset. The record is one of the base's
33200
+ customer record type (x-customer-scope role root), holding no external key
33201
+ or the contact id under another source. A record keyed under another
33202
+ external_id is refused: re-keying it would orphan its owned records.
33203
+ unlink-customer Unlink the contact's customer record in the base. The record keeps the
33204
+ contact id under the source wayai_contact_unlinked, so its owned records stay
33205
+ its own, and link-customer on the same record links it again.
33206
+
33207
+ The organization is --org, else this repo's (wayai-ws/wayai.yaml). You must be an
33208
+ organization admin. These commands need a browser sign-in (\`wayai login\`): an API
33209
+ token (\`wayai login --token\`, or WAYAI_TOKEN) is refused.
33210
+ `.trim();
33211
+ SUBCOMMANDS2 = ["link-customer", "unlink-customer"];
33212
+ }
33213
+ });
33214
+
33020
33215
  // ../../packages/core/dist/contracts/rekor-toolset.js
33021
33216
  var init_rekor_toolset = __esm({
33022
33217
  "../../packages/core/dist/contracts/rekor-toolset.js"() {
33023
33218
  "use strict";
33024
- init_chunk_4I3WSYXD();
33025
- init_chunk_KWBAMM7C();
33219
+ init_chunk_BVQE66I2();
33220
+ init_chunk_BEOHBREG();
33026
33221
  init_chunk_DHPUPI4Y();
33027
33222
  }
33028
33223
  });
@@ -33986,14 +34181,14 @@ var init_plan = __esm({
33986
34181
 
33987
34182
  // src/knowledge/migrate.ts
33988
34183
  import { isDeepStrictEqual as isDeepStrictEqual3 } from "util";
33989
- async function resolveBases(kb, baseId) {
33990
- const base = await kb.getBase(baseId);
33991
- if (!base || base.deleted) throw expected(`Base "${safe(baseId)}" not found in this organization.`);
34184
+ async function resolveBases(kb, baseId2) {
34185
+ const base = await kb.getBase(baseId2);
34186
+ if (!base || base.deleted) throw expected(`Base "${safe(baseId2)}" not found in this organization.`);
33992
34187
  if (base.environment === "preview") {
33993
34188
  const origin = base.origin_base_id ? await kb.getBase(base.origin_base_id) : null;
33994
34189
  if (!origin || origin.deleted || origin.environment !== "production") {
33995
34190
  throw expected(
33996
- `Base "${safe(baseId)}" is a preview with no production origin, so its file types can never be promoted. Name the production knowledge base, or a preview created from it.`
34191
+ `Base "${safe(baseId2)}" is a preview with no production origin, so its file types can never be promoted. Name the production knowledge base, or a preview created from it.`
33997
34192
  );
33998
34193
  }
33999
34194
  return { production: origin.id, preview: base.id };
@@ -34006,7 +34201,7 @@ async function resolveBases(kb, baseId) {
34006
34201
  }
34007
34202
  if (previews.length !== 1) {
34008
34203
  throw expected(
34009
- previews.length === 0 ? `Base "${safe(baseId)}" has no preview to write its file types in. Create one with \`wayai bases create-preview ${safe(baseId)} --name <name>\`.` : `Base "${safe(baseId)}" has ${previews.length} previews (${previews.map(safe).join(", ")}). Pass the one to write its file types in as --base.`
34204
+ previews.length === 0 ? `Base "${safe(baseId2)}" has no preview to write its file types in. Create one with \`wayai bases create-preview ${safe(baseId2)} --name <name>\`.` : `Base "${safe(baseId2)}" has ${previews.length} previews (${previews.map(safe).join(", ")}). Pass the one to write its file types in as --base.`
34010
34205
  );
34011
34206
  }
34012
34207
  return { production: base.id, preview: previews[0] };
@@ -34459,28 +34654,28 @@ __export(knowledge_exports, {
34459
34654
  knowledgeCommand: () => knowledgeCommand,
34460
34655
  parseKnowledgeArgs: () => parseKnowledgeArgs
34461
34656
  });
34462
- import { parseArgs as parseArgs22 } from "util";
34463
- function usageError2(message) {
34657
+ import { parseArgs as parseArgs23 } from "util";
34658
+ function usageError3(message) {
34464
34659
  return expected(`${message}
34465
- ${USAGE3}`);
34660
+ ${USAGE4}`);
34466
34661
  }
34467
34662
  function readArgs(args2) {
34468
34663
  try {
34469
- return parseArgs22({ args: args2, options: OPTIONS, allowPositionals: true, strict: true });
34664
+ return parseArgs23({ args: args2, options: OPTIONS, allowPositionals: true, strict: true });
34470
34665
  } catch (err) {
34471
- throw usageError2(err instanceof Error ? err.message : String(err));
34666
+ throw usageError3(err instanceof Error ? err.message : String(err));
34472
34667
  }
34473
34668
  }
34474
34669
  function parseKnowledgeArgs(args2) {
34475
34670
  const { values, positionals } = readArgs(args2);
34476
34671
  const [verb, ...extra] = positionals;
34477
- if (verb !== "migrate") throw usageError2(verb === void 0 ? "No subcommand given." : `Unknown subcommand ${JSON.stringify(verb)}.`);
34478
- if (extra.length > 0) throw usageError2(`Unexpected argument ${JSON.stringify(extra[0])}.`);
34479
- if (!values.org) throw usageError2("--org <org_id> is required.");
34480
- if (!UUID_RE3.test(values.org)) throw usageError2(`Invalid --org ${JSON.stringify(values.org)}: expected an organization id (a UUID).`);
34481
- if (!values.base) throw usageError2("--base <knowledge base> is required.");
34672
+ if (verb !== "migrate") throw usageError3(verb === void 0 ? "No subcommand given." : `Unknown subcommand ${JSON.stringify(verb)}.`);
34673
+ if (extra.length > 0) throw usageError3(`Unexpected argument ${JSON.stringify(extra[0])}.`);
34674
+ if (!values.org) throw usageError3("--org <org_id> is required.");
34675
+ if (!UUID_RE3.test(values.org)) throw usageError3(`Invalid --org ${JSON.stringify(values.org)}: expected an organization id (a UUID).`);
34676
+ if (!values.base) throw usageError3("--base <knowledge base> is required.");
34482
34677
  if (values.hub !== void 0 && !UUID_RE3.test(values.hub)) {
34483
- throw usageError2(`Invalid --hub ${JSON.stringify(values.hub)}: expected a hub id (a UUID).`);
34678
+ throw usageError3(`Invalid --hub ${JSON.stringify(values.hub)}: expected a hub id (a UUID).`);
34484
34679
  }
34485
34680
  return {
34486
34681
  orgId: values.org,
@@ -34492,12 +34687,12 @@ function parseKnowledgeArgs(args2) {
34492
34687
  }
34493
34688
  async function knowledgeCommand(args2) {
34494
34689
  if (wantsHelp(args2) || args2.length === 0) {
34495
- console.log(USAGE3);
34690
+ console.log(USAGE4);
34496
34691
  return;
34497
34692
  }
34498
34693
  const options = parseKnowledgeArgs(args2);
34499
34694
  if (!options.dryRun && !options.yes && !isInteractive()) {
34500
- throw usageError2("It asks before it writes; pass -y when not running in a terminal, or --dry-run.");
34695
+ throw usageError3("It asks before it writes; pass -y when not running in a terminal, or --dry-run.");
34501
34696
  }
34502
34697
  const { config, accessToken } = await requireAuth();
34503
34698
  const api = new ApiClient({ apiUrl: config.api_url, accessToken, onUnauthorized: () => getAccessToken(config) });
@@ -34507,7 +34702,7 @@ async function knowledgeCommand(args2) {
34507
34702
  confirm
34508
34703
  });
34509
34704
  }
34510
- var USAGE3, OPTIONS;
34705
+ var USAGE4, OPTIONS;
34511
34706
  var init_knowledge = __esm({
34512
34707
  "src/commands/knowledge.ts"() {
34513
34708
  "use strict";
@@ -34519,7 +34714,7 @@ var init_knowledge = __esm({
34519
34714
  init_helpers();
34520
34715
  init_migrate2();
34521
34716
  init_remote();
34522
- USAGE3 = `
34717
+ USAGE4 = `
34523
34718
  wayai knowledge migrate \u2014 move knowledge resources into the organization's knowledge base
34524
34719
 
34525
34720
  Usage:
@@ -35190,8 +35385,8 @@ function parseScopedTargetFlags(flagArgs, usage3, opts = {}) {
35190
35385
  return { body: { scope: "hub", hub_id: hubId, dry_run: dryRun }, targetLabel: `hub ${hubId}`, dryRun, yes, jsonOutput };
35191
35386
  }
35192
35387
  async function runRepairTeamOrphans(flagArgs) {
35193
- const USAGE4 = "wayai admin hubs repair-team-orphans --all | --org <org_id> | --hub <hub_id> [--dry-run] [--yes] [--json]";
35194
- const { body, targetLabel, dryRun, yes, jsonOutput } = parseScopedTargetFlags(flagArgs, USAGE4);
35388
+ const USAGE5 = "wayai admin hubs repair-team-orphans --all | --org <org_id> | --hub <hub_id> [--dry-run] [--yes] [--json]";
35389
+ const { body, targetLabel, dryRun, yes, jsonOutput } = parseScopedTargetFlags(flagArgs, USAGE5);
35195
35390
  if (!dryRun && !yes && !jsonOutput) {
35196
35391
  console.log(`About to PURGE dangling team references in: ${targetLabel}.`);
35197
35392
  console.log("Memberships pointing at a deleted team are removed (HubDO + UserDO mirror); conversations pinned to one are unassigned.");
@@ -35237,7 +35432,7 @@ async function runRepairTeamOrphans(flagArgs) {
35237
35432
  }
35238
35433
  }
35239
35434
  async function runRepairBranchingOrphans(flagArgs) {
35240
- const USAGE4 = "wayai admin hubs repair-branching-orphans --all | --org <org_id> | --hub <hub_id> [--id <type>:<id> ...] [--dry-run] [--yes] [--json]";
35435
+ const USAGE5 = "wayai admin hubs repair-branching-orphans --all | --org <org_id> | --hub <hub_id> [--id <type>:<id> ...] [--dry-run] [--yes] [--json]";
35241
35436
  const targets = [];
35242
35437
  const scopeArgs = [];
35243
35438
  for (let i = 0; i < flagArgs.length; i++) {
@@ -35255,10 +35450,10 @@ async function runRepairBranchingOrphans(flagArgs) {
35255
35450
  }
35256
35451
  targets.push({ entity_type: entityType, entity_id: entityId });
35257
35452
  }
35258
- const { body, targetLabel, dryRun, yes, jsonOutput } = parseScopedTargetFlags(scopeArgs, USAGE4);
35453
+ const { body, targetLabel, dryRun, yes, jsonOutput } = parseScopedTargetFlags(scopeArgs, USAGE5);
35259
35454
  if (targets.length > 0 && body.scope !== "hub") {
35260
35455
  console.error("--id deletes rows of ONE production hub: combine it with --hub <hub_id>.");
35261
- console.error(USAGE4);
35456
+ console.error(USAGE5);
35262
35457
  process.exit(1);
35263
35458
  }
35264
35459
  if (targets.length > 0 && !dryRun && !yes && !jsonOutput) {
@@ -35320,8 +35515,8 @@ async function runRepairBranchingOrphans(flagArgs) {
35320
35515
  }
35321
35516
  }
35322
35517
  async function runRepairLegacyOrgGrants(flagArgs) {
35323
- const USAGE4 = "wayai admin orgs repair-legacy-grants --all | --org <org_id> [--dry-run] [--yes] [--json]";
35324
- const scoped = parseScopedTargetFlags(flagArgs, USAGE4, {
35518
+ const USAGE5 = "wayai admin orgs repair-legacy-grants --all | --org <org_id> [--dry-run] [--yes] [--json]";
35519
+ const scoped = parseScopedTargetFlags(flagArgs, USAGE5, {
35325
35520
  scopes: ["all", "org"],
35326
35521
  allLabel: "ALL organizations (platform-wide)"
35327
35522
  });
@@ -35373,8 +35568,8 @@ async function runRepairLegacyOrgGrants(flagArgs) {
35373
35568
  }
35374
35569
  }
35375
35570
  async function runHarnessMassDestroy(flagArgs) {
35376
- const USAGE4 = "wayai admin harness mass-destroy --all | --org <org_id> | --hub <hub_id> [--dry-run] [--yes] [--json]";
35377
- const { body, targetLabel, dryRun, yes, jsonOutput } = parseScopedTargetFlags(flagArgs, USAGE4);
35571
+ const USAGE5 = "wayai admin harness mass-destroy --all | --org <org_id> | --hub <hub_id> [--dry-run] [--yes] [--json]";
35572
+ const { body, targetLabel, dryRun, yes, jsonOutput } = parseScopedTargetFlags(flagArgs, USAGE5);
35378
35573
  if (!dryRun && !yes && !jsonOutput) {
35379
35574
  console.log(`About to REAP every live harness session / token / slot in: ${targetLabel}.`);
35380
35575
  console.log("This destroys running harness sessions and revokes their tokens. Run with --dry-run first to see the blast radius.");
@@ -37668,8 +37863,8 @@ function buildBasesReportCommand() {
37668
37863
  if (opts.errorMessage) body.error_message = opts.errorMessage;
37669
37864
  if (opts.context) body.context = opts.context;
37670
37865
  if (opts.reporterEmail) body.reporter_email = opts.reporterEmail;
37671
- const baseId = opts.baseId ?? findBase(this) ?? process.env.WAYAI_BASE;
37672
- if (baseId) body.base_id = baseId;
37866
+ const baseId2 = opts.baseId ?? findBase(this) ?? process.env.WAYAI_BASE;
37867
+ if (baseId2) body.base_id = baseId2;
37673
37868
  if (opts.recordType) body.record_type = opts.recordType;
37674
37869
  if (opts.recordId) body.record_id = opts.recordId;
37675
37870
  if (opts.externalId) body.external_id = opts.externalId;
@@ -38513,28 +38708,28 @@ function buildBasesCommand() {
38513
38708
  bases.command("use <base>").description(
38514
38709
  "Deprecated alias of `wayai use bases/<id>` \u2014 scope this worktree to a base"
38515
38710
  ).action(async function(selector) {
38516
- const baseId = resolveBaseSelectorToId(findGitRoot(), selector);
38711
+ const baseId2 = resolveBaseSelectorToId(findGitRoot(), selector);
38517
38712
  const previous = readScope().bases;
38518
- const changed = previous.length !== 1 || previous[0] !== baseId;
38713
+ const changed = previous.length !== 1 || previous[0] !== baseId2;
38519
38714
  if (changed) {
38520
38715
  try {
38521
- setScopeAxis("bases", [baseId]);
38716
+ setScopeAxis("bases", [baseId2]);
38522
38717
  } catch (err) {
38523
38718
  throw expected(err instanceof Error ? err.message : String(err));
38524
38719
  }
38525
38720
  }
38526
38721
  if (outputFormat(this) === "json") {
38527
38722
  printOutput(
38528
- { base_id: baseId, previous_base_id: previous[0] ?? null, changed },
38723
+ { base_id: baseId2, previous_base_id: previous[0] ?? null, changed },
38529
38724
  "json"
38530
38725
  );
38531
38726
  return;
38532
38727
  }
38533
38728
  if (!changed) {
38534
- console.log(`Worktree already bound to base ${baseId}.`);
38729
+ console.log(`Worktree already bound to base ${baseId2}.`);
38535
38730
  } else {
38536
38731
  console.log(
38537
- previous.length > 0 ? `Worktree rebound: ${previous.join(", ")} -> ${baseId}.` : `Worktree bound to base ${baseId}.`
38732
+ previous.length > 0 ? `Worktree rebound: ${previous.join(", ")} -> ${baseId2}.` : `Worktree bound to base ${baseId2}.`
38538
38733
  );
38539
38734
  }
38540
38735
  });
@@ -40963,6 +41158,11 @@ async function main() {
40963
41158
  await communitiesCommand2(args);
40964
41159
  break;
40965
41160
  }
41161
+ case "contacts": {
41162
+ const { contactsCommand: contactsCommand2 } = await Promise.resolve().then(() => (init_contacts(), contacts_exports));
41163
+ await contactsCommand2(args);
41164
+ break;
41165
+ }
40966
41166
  case "knowledge": {
40967
41167
  const { knowledgeCommand: knowledgeCommand2 } = await Promise.resolve().then(() => (init_knowledge(), knowledge_exports));
40968
41168
  await knowledgeCommand2(args);
@@ -41057,6 +41257,7 @@ Commands:
41057
41257
  sync-mcp Re-discover an MCP connection's tools (refresh stale schemas)
41058
41258
  list List organizations and hubs
41059
41259
  communities An organization's communities: list, join link (get/rotate/off), stats, access list (list/add/remove) \u2014 \`wayai communities --help\`
41260
+ contacts Link a contact to its customer record in a base, or unlink it (browser sign-in only) \u2014 \`wayai contacts --help\`
41060
41261
  knowledge migrate Move an organization's knowledge resources, then a hub's (--hub), into its knowledge base as file types and files \u2014 \`wayai knowledge --help\`
41061
41262
  report create Report a platform bug (submits to the triage queue)
41062
41263
  report edit Amend your own pending report (title/description/error/steps/context)