@wayai/cli 0.3.215 → 0.3.216

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
@@ -447,11 +447,11 @@ function captureException2(error, context) {
447
447
  Sentry.captureException(error);
448
448
  });
449
449
  }
450
- function addApiBreadcrumb(method, path41) {
450
+ function addApiBreadcrumb(method, path42) {
451
451
  if (!initialized) return;
452
452
  Sentry.addBreadcrumb({
453
453
  category: "http",
454
- message: `${method} ${path41}`,
454
+ message: `${method} ${path42}`,
455
455
  level: "info"
456
456
  });
457
457
  }
@@ -512,7 +512,7 @@ var init_chunk_VORPHGDT = __esm({
512
512
  }
513
513
  });
514
514
 
515
- // ../../packages/core/dist/chunk-2TNXNKRP.js
515
+ // ../../packages/core/dist/chunk-MXDUKZPW.js
516
516
  function spokenLineField(label, description2) {
517
517
  return { type: "text", label, maxLength: SPOKEN_LINE_MAX_CHARS, default: "", description: description2 };
518
518
  }
@@ -521,9 +521,9 @@ function byLowercaseName(a, b) {
521
521
  const y = b.connector_name.toLowerCase();
522
522
  return x < y ? -1 : x > y ? 1 : 0;
523
523
  }
524
- var CALLER_LANGUAGE, TTS_VOICE_REPLY_ENABLED_FIELD, COPILOT_TRIGGER_FIELD, 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;
525
- var init_chunk_2TNXNKRP = __esm({
526
- "../../packages/core/dist/chunk-2TNXNKRP.js"() {
524
+ 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;
525
+ var init_chunk_MXDUKZPW = __esm({
526
+ "../../packages/core/dist/chunk-MXDUKZPW.js"() {
527
527
  "use strict";
528
528
  CALLER_LANGUAGE = "caller";
529
529
  TTS_VOICE_REPLY_ENABLED_FIELD = {
@@ -546,6 +546,33 @@ var init_chunk_2TNXNKRP = __esm({
546
546
  description: 'When this agent runs as a Copilot, whether it drafts a suggestion automatically on every incoming message ("Every message") or only when a team member clicks "Suggest reply" ("On demand"). On demand reduces cost and noise. No effect on Pilot agents.'
547
547
  }
548
548
  };
549
+ SANDBOX_AGENT_FIELDS = {
550
+ code_execution_enabled: {
551
+ type: "toggle",
552
+ label: "Code Execution Sandbox",
553
+ default: false,
554
+ description: "Let this agent run code in a WayAI sandbox with the sandbox tools, bash, copy_to_sandbox and copy_from_sandbox (add them under Tools): one disposable Linux container per conversation, started on first use and ended after 10 minutes without use or 60 minutes in all. On Anthropic and OpenAI agents this also enables download_file and upload_file, which use the provider's own sandbox."
555
+ },
556
+ sandbox_network: {
557
+ type: "select",
558
+ label: "Sandbox Network",
559
+ options: [
560
+ { value: "none", label: "No network" },
561
+ { value: "allowlist", label: "Allowlist" },
562
+ { value: "web", label: "Web" }
563
+ ],
564
+ default: "none",
565
+ description: "What code in this agent's sandbox can reach. No network: nothing leaves the sandbox. Allowlist: HTTP and HTTPS to the hosts listed below only, through WayAI; no DNS or other protocol leaves, but data can still be sent to those hosts. Web: HTTP and HTTPS to any public host, through WayAI; data can be sent to any of them. WayAI adds no credentials to these requests."
566
+ },
567
+ sandbox_allowed_hosts: {
568
+ type: "array",
569
+ itemType: "text",
570
+ maxItems: 50,
571
+ label: "Sandbox Allowed Hosts",
572
+ description: "The exact host names the sandbox may reach under Allowlist, such as api.example.com: no wildcards, IP addresses, ports or paths.",
573
+ dependsOn: { field: "sandbox_network", values: ["allowlist"] }
574
+ }
575
+ };
549
576
  AUDIO_LANGUAGE_OPTIONS = [
550
577
  { value: "", label: "Auto-detect" },
551
578
  { value: "en", label: "en" },
@@ -728,7 +755,7 @@ var init_chunk_2TNXNKRP = __esm({
728
755
  verbosity: { type: "select", label: "Verbosity", options: ["low", "medium", "high"], default: "medium", description: "Output detail level. Only for reasoning models.", dependsOn: { field: "model", values: OPENAI_REASONING_MODELS } },
729
756
  service_tier: { type: "select", label: "Service Tier", options: ["auto", "flex", "default", "priority"], default: "auto", description: "Service tier (flex=50% cheaper, higher latency). Only for reasoning models.", dependsOn: { field: "model", values: OPENAI_REASONING_MODELS } },
730
757
  max_tokens: { type: "number", label: "Max Tokens", min: 1, default: 4096, description: "Maximum tokens to generate. On reasoning models, this cap includes reasoning tokens." },
731
- code_execution_enabled: { type: "toggle", label: "Code Execution Sandbox", default: false, description: "Allow this agent to use the OpenAI code_interpreter sandbox for the download_file/upload_file tools. Off keeps the agent read-only on resources even if the tools are attached." },
758
+ ...SANDBOX_AGENT_FIELDS,
732
759
  streaming_enabled: { type: "toggle", label: "Stream Responses", default: false, description: "Stream responses in real-time (app channel only)" },
733
760
  deliver_preamble: { type: "toggle", label: "Deliver Pre-Tool Messages", default: true, description: 'Send the short message the model writes before running tools ("Let me check that\u2026") as its own message, so the user hears something during the tool-execution wait. Off = only the final reply is delivered (pre-tool text is discarded). Not applied on email channels; on voice conversations each preamble is spoken as its own audio clip.' },
734
761
  file_handling_mode: { type: "select", label: "File handling", options: [{ value: "always_attach", label: "Attach files" }, { value: "metadata_only", label: "Metadata only (retrieve on demand)" }], default: "always_attach", description: "No longer changes what the model receives \u2014 a conversation's earlier files are always announced by path, never re-sent as content. metadata_only still auto-enables read_file so the agent can open one of those paths on demand." },
@@ -767,7 +794,7 @@ var init_chunk_2TNXNKRP = __esm({
767
794
  max_tokens: { type: "number", label: "Max Tokens", min: 1, max: 8192, default: 4096, description: "Maximum tokens to generate", required: true },
768
795
  thinking_enabled: { type: "toggle", label: "Extended Thinking", default: false, description: "Enable Claude extended thinking for deeper reasoning. Uses output tokens; temperature/top_p are ignored when on. Not shown for Claude Fable and Claude Opus 5.5, which always reason adaptively. On Claude Sonnet 5.5 and Claude Haiku 5.5, off applies at Reasoning Effort High or below; at Extra high or Max they keep thinking.", dependsOn: { field: "model", values: ["claude-sonnet-5-5", "claude-haiku-5-5", "claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-6", "claude-sonnet-5", "claude-sonnet-4-6", "claude-sonnet-4-5", "claude-haiku-4-5", "claude-opus-4-5"] } },
769
796
  effort: { type: "select", label: "Reasoning Effort", options: [{ value: "low", label: "Low" }, { value: "medium", label: "Medium" }, { value: "high", label: "High" }, { value: "xhigh", label: "Extra high" }, { value: "max", label: "Max" }], default: "high", description: "How hard Claude reasons and how many tokens it spends overall (output_config.effort). Higher = better quality, more cost/latency. xhigh needs Opus 4.7+/Sonnet 5+/Haiku 5.5/Fable; max excludes Opus 4.5. Levels the chosen model does not support are clamped down to the highest it allows.", dependsOn: { field: "model", values: ["claude-fable-5-1", "claude-opus-5-5", "claude-sonnet-5-5", "claude-haiku-5-5", "claude-fable-5", "claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-6", "claude-opus-4-5", "claude-sonnet-5", "claude-sonnet-4-6"] } },
770
- code_execution_enabled: { type: "toggle", label: "Code Execution Sandbox", default: false, description: "Allow this agent to use the Anthropic code_execution sandbox for the download_file/upload_file tools. Off keeps the agent read-only on resources even if the tools are attached." },
797
+ ...SANDBOX_AGENT_FIELDS,
771
798
  cache_ttl: { type: "select", label: "System Prompt Cache TTL", options: [{ value: "1h", label: "1 hour (recommended)" }, { value: "5m", label: "5 minutes" }, { value: "off", label: "Disabled" }], default: "1h", description: "Caches system prompt and tool definitions (shared across all conversations on this agent). 1h amortizes the 2\xD7 write premium across concurrent conversations." },
772
799
  cache_ttl_history: { type: "select", label: "Conversation History Cache TTL", options: [{ value: "5m", label: "5 minutes (recommended)" }, { value: "1h", label: "1 hour" }, { value: "off", label: "Disabled" }], default: "5m", description: "Caches per-conversation history. Primary readers are tool-loop iterations (seconds apart) \u2014 5m captures these at 1.25\xD7 write premium instead of 2\xD7. Use 1h only if conversations frequently re-engage between 5min\u20131h." },
773
800
  streaming_enabled: { type: "toggle", label: "Stream Responses", default: false, description: "Stream responses in real-time (app channel only)" },
@@ -811,6 +838,7 @@ var init_chunk_2TNXNKRP = __esm({
811
838
  deliver_preamble: { type: "toggle", label: "Deliver Pre-Tool Messages", default: true, description: 'Send the short message the model writes before running tools ("Let me check that\u2026") as its own message, so the user hears something during the tool-execution wait. Off = only the final reply is delivered (pre-tool text is discarded). Not applied on email channels; on voice conversations each preamble is spoken as its own audio clip.' },
812
839
  file_handling_mode: { type: "select", label: "File handling", options: [{ value: "always_attach", label: "Attach files" }, { value: "metadata_only", label: "Metadata only (retrieve on demand)" }], default: "always_attach", description: "No longer changes what the model receives \u2014 a conversation's earlier files are always announced by path, never re-sent as content. metadata_only still auto-enables read_file so the agent can open one of those paths on demand." },
813
840
  max_attachment_size_mb: { type: "number", label: "Max attachment size (MB)", min: 1, description: "No longer has any effect: earlier files are announced by path rather than attached, so there is no attachment size to cap." },
841
+ ...SANDBOX_AGENT_FIELDS,
814
842
  ...COPILOT_TRIGGER_FIELD
815
843
  },
816
844
  channel_settings_schema: null,
@@ -852,6 +880,7 @@ var init_chunk_2TNXNKRP = __esm({
852
880
  deliver_preamble: { type: "toggle", label: "Deliver Pre-Tool Messages", default: true, description: 'Send the short message the model writes before running tools ("Let me check that\u2026") as its own message, so the user hears something during the tool-execution wait. Off = only the final reply is delivered (pre-tool text is discarded). Not applied on email channels; on voice conversations each preamble is spoken as its own audio clip.' },
853
881
  file_handling_mode: { type: "select", label: "File handling", options: [{ value: "always_attach", label: "Attach files" }, { value: "metadata_only", label: "Metadata only (retrieve on demand)" }], default: "always_attach", description: "No longer changes what the model receives \u2014 a conversation's earlier files are always announced by path, never re-sent as content. metadata_only still auto-enables read_file so the agent can open one of those paths on demand." },
854
882
  max_attachment_size_mb: { type: "number", label: "Max attachment size (MB)", min: 1, description: "No longer has any effect: earlier files are announced by path rather than attached, so there is no attachment size to cap." },
883
+ ...SANDBOX_AGENT_FIELDS,
855
884
  ...COPILOT_TRIGGER_FIELD
856
885
  },
857
886
  channel_settings_schema: null,
@@ -890,6 +919,7 @@ var init_chunk_2TNXNKRP = __esm({
890
919
  deliver_preamble: { type: "toggle", label: "Deliver Pre-Tool Messages", default: true, description: 'Send the short message the model writes before running tools ("Let me check that\u2026") as its own message, so the user hears something during the tool-execution wait. Off = only the final reply is delivered (pre-tool text is discarded). Not applied on email channels; on voice conversations each preamble is spoken as its own audio clip.' },
891
920
  file_handling_mode: { type: "select", label: "File handling", options: [{ value: "always_attach", label: "Attach files" }, { value: "metadata_only", label: "Metadata only (retrieve on demand)" }], default: "always_attach", description: "No longer changes what the model receives \u2014 a conversation's earlier files are always announced by path, never re-sent as content. metadata_only still auto-enables read_file so the agent can open one of those paths on demand." },
892
921
  max_attachment_size_mb: { type: "number", label: "Max attachment size (MB)", min: 1, description: "No longer has any effect: earlier files are announced by path rather than attached, so there is no attachment size to cap." },
922
+ ...SANDBOX_AGENT_FIELDS,
893
923
  ...COPILOT_TRIGGER_FIELD
894
924
  },
895
925
  channel_settings_schema: null,
@@ -1447,16 +1477,78 @@ var init_chunk_2TNXNKRP = __esm({
1447
1477
  }
1448
1478
  });
1449
1479
 
1450
- // ../../packages/core/dist/chunk-SNA2DXAC.js
1480
+ // ../../packages/core/dist/chunk-DHPUPI4Y.js
1481
+ function normalizeAuthType(raw) {
1482
+ if (VALID_AUTH_TYPES.has(raw)) return raw;
1483
+ return LEGACY_AUTH_TYPE_MAP[raw] ?? raw;
1484
+ }
1485
+ var AUTH_TYPE, ORG_CREDENTIAL_AUTH_TYPES, AUTH_TYPE_DISPLAY, LEGACY_AUTH_TYPE_MAP, VALID_AUTH_TYPES, AGENT_ROLES, PILOT_TRACK_ROLES, COPILOT_TRACK_ROLES, CUSTOMER_FACING_AGENT_ROLES, SAFE_USER_ID_REGEX, SUPPORTED_LOCALES, SKILL_INSTALL_COMMAND;
1486
+ var init_chunk_DHPUPI4Y = __esm({
1487
+ "../../packages/core/dist/chunk-DHPUPI4Y.js"() {
1488
+ "use strict";
1489
+ AUTH_TYPE = {
1490
+ OAUTH: "oauth",
1491
+ API_KEY: "api_key",
1492
+ BASIC_AUTH: "basic_auth",
1493
+ BEARER: "bearer",
1494
+ NONE: "none"
1495
+ };
1496
+ ORG_CREDENTIAL_AUTH_TYPES = [
1497
+ AUTH_TYPE.API_KEY,
1498
+ AUTH_TYPE.BEARER,
1499
+ AUTH_TYPE.BASIC_AUTH
1500
+ ];
1501
+ AUTH_TYPE_DISPLAY = {
1502
+ [AUTH_TYPE.OAUTH]: "OAuth",
1503
+ [AUTH_TYPE.API_KEY]: "API Key",
1504
+ [AUTH_TYPE.BASIC_AUTH]: "Basic Auth",
1505
+ [AUTH_TYPE.BEARER]: "Bearer Token",
1506
+ [AUTH_TYPE.NONE]: "No Authentication"
1507
+ };
1508
+ LEGACY_AUTH_TYPE_MAP = {
1509
+ "OAuth": AUTH_TYPE.OAUTH,
1510
+ "API Key": AUTH_TYPE.API_KEY,
1511
+ "Basic Auth": AUTH_TYPE.BASIC_AUTH,
1512
+ "Bearer Token": AUTH_TYPE.BEARER,
1513
+ "No authentication": AUTH_TYPE.NONE,
1514
+ // Also handle the old DISPLAY_TO_CODE bug where 'basic' was used instead of 'basic_auth'
1515
+ "basic": AUTH_TYPE.BASIC_AUTH
1516
+ };
1517
+ VALID_AUTH_TYPES = new Set(Object.values(AUTH_TYPE));
1518
+ AGENT_ROLES = [
1519
+ "pilot",
1520
+ "copilot",
1521
+ "pilot_specialist",
1522
+ "copilot_specialist",
1523
+ "pilot_advisor",
1524
+ "copilot_advisor",
1525
+ "monitor",
1526
+ "conversation_evaluator",
1527
+ "message_evaluator",
1528
+ "summarizer",
1529
+ "consultant",
1530
+ "pilot_voice"
1531
+ ];
1532
+ PILOT_TRACK_ROLES = ["pilot", "pilot_specialist"];
1533
+ COPILOT_TRACK_ROLES = ["copilot", "copilot_specialist"];
1534
+ CUSTOMER_FACING_AGENT_ROLES = [...PILOT_TRACK_ROLES, "pilot_advisor"];
1535
+ SAFE_USER_ID_REGEX = /^[A-Za-z0-9_-]{1,64}$/;
1536
+ SUPPORTED_LOCALES = ["en", "pt", "es"];
1537
+ SKILL_INSTALL_COMMAND = "mkdir -p .claude && npx skills add wayai-pro/wayai-skill -y";
1538
+ }
1539
+ });
1540
+
1541
+ // ../../packages/core/dist/chunk-QT7NKKPO.js
1451
1542
  function catalogToolSideEffects(toolName) {
1452
1543
  const sideEffects = CATALOG_SIDE_EFFECTS.get(toolName);
1453
1544
  if (sideEffects === void 0) return "unknown";
1454
1545
  return sideEffects ? "side_effects" : "none";
1455
1546
  }
1456
- var NATIVE_TOOL_SCHEMAS, WAYAI_CONNECTOR, BASE_NATIVE_TOOLS, NATIVE_TOOLS, CATALOG_SIDE_EFFECTS;
1457
- var init_chunk_SNA2DXAC = __esm({
1458
- "../../packages/core/dist/chunk-SNA2DXAC.js"() {
1547
+ var NATIVE_TOOL_SCHEMAS, WAYAI_CONNECTOR, SANDBOX_AGENT_ROLES, BASE_NATIVE_TOOLS, NATIVE_TOOLS, CATALOG_SIDE_EFFECTS;
1548
+ var init_chunk_QT7NKKPO = __esm({
1549
+ "../../packages/core/dist/chunk-QT7NKKPO.js"() {
1459
1550
  "use strict";
1551
+ init_chunk_DHPUPI4Y();
1460
1552
  NATIVE_TOOL_SCHEMAS = {
1461
1553
  "close_conversation": {
1462
1554
  "tool_config": {
@@ -1750,6 +1842,86 @@ var init_chunk_SNA2DXAC = __esm({
1750
1842
  },
1751
1843
  "tool_instructions": "Use to commit either an edit (file_id + sandbox_file_id) or a new file (resource_id + filename + sandbox_file_id). Returns { saved, file_id, file_hash, bytes } on success \u2014 the file_id you can reference later. Errors clearly when write access is denied or when neither identifier set is provided."
1752
1844
  },
1845
+ // The code sandbox (wayai#5083 Phase 3). The figures in its description are the backend's
1846
+ // sandbox limits (`apps/backend/src/sandbox/limits.ts`), pinned there by a test, so the model is
1847
+ // told the limits the sandbox enforces.
1848
+ "bash": {
1849
+ "tool_config": {
1850
+ "name": "bash",
1851
+ "description": "Run a Bash command in this conversation's sandbox: a disposable Linux container (Debian, with Python 3, curl, jq, zip and other common tools) whose working directory is /workspace. The sandbox starts on the first command and keeps its files between commands in this conversation, but it ends after 10 minutes without use or 60 minutes in all; the next command then starts an empty one, and its result says so. What the sandbox can reach over the network is set for this agent by a hub admin; with no network, nothing leaves it. A command runs for at most timeout_seconds and never past the turn's own time limit. Long output keeps only its first and last parts. The result gives the exit code, stdout and stderr.",
1852
+ "strict": false,
1853
+ "parameters": {
1854
+ "type": "object",
1855
+ "properties": {
1856
+ "command": {
1857
+ "type": "string",
1858
+ "description": "The Bash script to run, as with `bash -c`. It runs in /workspace unless it changes directory."
1859
+ },
1860
+ "timeout_seconds": {
1861
+ "type": "integer",
1862
+ "description": "How long the command may run before it is killed, in seconds: 120 by default, at most 540.",
1863
+ "minimum": 1,
1864
+ "maximum": 540
1865
+ }
1866
+ },
1867
+ "required": [
1868
+ "command"
1869
+ ],
1870
+ "additionalProperties": false
1871
+ }
1872
+ },
1873
+ "tool_instructions": null
1874
+ },
1875
+ "copy_to_sandbox": {
1876
+ "tool_config": {
1877
+ "name": "copy_to_sandbox",
1878
+ "description": `Copy one of this conversation's files into the code sandbox, so commands run with bash can read or edit it there. path names the file as read_file does: this conversation's attachments under "conversation/" (e.g. "conversation/report.xlsx"), or an earlier conversation's under "conversations/<conversation_id>/<name>". Hub resource files cannot be copied. The copy lands at sandbox_path, replacing any file there; a file larger than 25 MiB is refused. If no sandbox is running, the copy starts an empty one.`,
1879
+ "strict": false,
1880
+ "parameters": {
1881
+ "type": "object",
1882
+ "properties": {
1883
+ "path": {
1884
+ "type": "string",
1885
+ "description": `The file to copy, as read_file names it: "conversation/<name>" (a shorter unambiguous form or the file's id also works) or "conversations/<conversation_id>/<name>".`
1886
+ },
1887
+ "sandbox_path": {
1888
+ "type": "string",
1889
+ "description": "Where the copy lands in the sandbox, under /workspace (a relative path is taken from /workspace). Defaults to the file's name in /workspace."
1890
+ }
1891
+ },
1892
+ "required": [
1893
+ "path"
1894
+ ],
1895
+ "additionalProperties": false
1896
+ }
1897
+ },
1898
+ "tool_instructions": null
1899
+ },
1900
+ "copy_from_sandbox": {
1901
+ "tool_config": {
1902
+ "name": "copy_from_sandbox",
1903
+ "description": 'Copy a file out of the code sandbox into this conversation, so what your commands produced (a chart, a converted document) is kept after the sandbox ends. The file is stored for the support team on an internal note and is NOT sent to the customer: the result gives its path under "conversation/", and send_files with that path delivers it when it should reach them. A file larger than 25 MiB is refused.',
1904
+ "strict": false,
1905
+ "parameters": {
1906
+ "type": "object",
1907
+ "properties": {
1908
+ "sandbox_path": {
1909
+ "type": "string",
1910
+ "description": "The file to copy, under /workspace (a relative path is taken from /workspace)."
1911
+ },
1912
+ "name": {
1913
+ "type": "string",
1914
+ "description": `The stored file's name, with no folders (e.g. "q3-report.xlsx"). Defaults to the file's name in the sandbox.`
1915
+ }
1916
+ },
1917
+ "required": [
1918
+ "sandbox_path"
1919
+ ],
1920
+ "additionalProperties": false
1921
+ }
1922
+ },
1923
+ "tool_instructions": null
1924
+ },
1753
1925
  "send_files": {
1754
1926
  "tool_config": {
1755
1927
  "name": "send_files",
@@ -2232,6 +2404,7 @@ var init_chunk_SNA2DXAC = __esm({
2232
2404
  }
2233
2405
  };
2234
2406
  WAYAI_CONNECTOR = "b17d9f3a-4e1b-46c9-b648-a2f0c3611aa4";
2407
+ SANDBOX_AGENT_ROLES = [...PILOT_TRACK_ROLES, ...COPILOT_TRACK_ROLES];
2235
2408
  BASE_NATIVE_TOOLS = [
2236
2409
  // --- Wayai core tools ---
2237
2410
  { 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 },
@@ -2323,7 +2496,17 @@ var init_chunk_SNA2DXAC = __esm({
2323
2496
  // would need remapping on both branching mechanisms and normalizing on both CI
2324
2497
  // directions. `action.tool_name`, one key away in the same object, is the
2325
2498
  // precedent.
2326
- { tool_native_id: "nt-029", tool_name: "run_monitor", tool_display_name: "Run Monitor", tool_description: "Run another monitor on this hub and let it act on its own rules", connector_id: WAYAI_CONNECTOR, operation: "run_monitor", tool_method: "internal", tool_group: "Native Tools", is_delegation: false, is_auto_set: false, execution_config: null, side_effects: true, assignable_roles: ["monitor"], model_callable: false }
2499
+ { tool_native_id: "nt-029", tool_name: "run_monitor", tool_display_name: "Run Monitor", tool_description: "Run another monitor on this hub and let it act on its own rules", connector_id: WAYAI_CONNECTOR, operation: "run_monitor", tool_method: "internal", tool_group: "Native Tools", is_delegation: false, is_auto_set: false, execution_config: null, side_effects: true, assignable_roles: ["monitor"], model_callable: false },
2500
+ // The code sandbox (wayai#5083 Phase 3): runs only for an agent whose `code_execution_enabled`
2501
+ // setting is on, on any provider. Side effects: under an Allowlist or Web network setting, the
2502
+ // code it runs can send data out of the conversation.
2503
+ { tool_native_id: "nt-030", tool_name: "bash", tool_display_name: "Run Code (Bash)", tool_description: "Run a Bash command in the conversation's code sandbox", connector_id: WAYAI_CONNECTOR, operation: "bash", tool_method: "internal", tool_group: "Native Tools", is_delegation: false, is_auto_set: false, execution_config: null, side_effects: true, assignable_roles: SANDBOX_AGENT_ROLES },
2504
+ // Copies a conversation file INTO the sandbox: the sandbox is conversation state, so nothing
2505
+ // leaves the conversation.
2506
+ { 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, assignable_roles: SANDBOX_AGENT_ROLES },
2507
+ // Copies a sandbox file OUT into the conversation, as an internal note for the team: nothing
2508
+ // reaches the customer until `send_files` sends it.
2509
+ { 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, assignable_roles: SANDBOX_AGENT_ROLES }
2327
2510
  ];
2328
2511
  NATIVE_TOOLS = BASE_NATIVE_TOOLS.map((base) => {
2329
2512
  const schema = NATIVE_TOOL_SCHEMAS[base.tool_name];
@@ -2812,8 +2995,8 @@ var init_parseUtil = __esm({
2812
2995
  init_errors();
2813
2996
  init_en();
2814
2997
  makeIssue = (params) => {
2815
- const { data, path: path41, errorMaps, issueData } = params;
2816
- const fullPath = [...path41, ...issueData.path || []];
2998
+ const { data, path: path42, errorMaps, issueData } = params;
2999
+ const fullPath = [...path42, ...issueData.path || []];
2817
3000
  const fullIssue = {
2818
3001
  ...issueData,
2819
3002
  path: fullPath
@@ -3124,11 +3307,11 @@ var init_types = __esm({
3124
3307
  init_parseUtil();
3125
3308
  init_util();
3126
3309
  ParseInputLazyPath = class {
3127
- constructor(parent, value, path41, key) {
3310
+ constructor(parent, value, path42, key) {
3128
3311
  this._cachedPath = [];
3129
3312
  this.parent = parent;
3130
3313
  this.data = value;
3131
- this._path = path41;
3314
+ this._path = path42;
3132
3315
  this._key = key;
3133
3316
  }
3134
3317
  get path() {
@@ -6552,66 +6735,6 @@ var init_chunk_3NS3HULK = __esm({
6552
6735
  }
6553
6736
  });
6554
6737
 
6555
- // ../../packages/core/dist/chunk-DHPUPI4Y.js
6556
- function normalizeAuthType(raw) {
6557
- if (VALID_AUTH_TYPES.has(raw)) return raw;
6558
- return LEGACY_AUTH_TYPE_MAP[raw] ?? raw;
6559
- }
6560
- var AUTH_TYPE, ORG_CREDENTIAL_AUTH_TYPES, AUTH_TYPE_DISPLAY, LEGACY_AUTH_TYPE_MAP, VALID_AUTH_TYPES, AGENT_ROLES, PILOT_TRACK_ROLES, CUSTOMER_FACING_AGENT_ROLES, SAFE_USER_ID_REGEX, SUPPORTED_LOCALES, SKILL_INSTALL_COMMAND;
6561
- var init_chunk_DHPUPI4Y = __esm({
6562
- "../../packages/core/dist/chunk-DHPUPI4Y.js"() {
6563
- "use strict";
6564
- AUTH_TYPE = {
6565
- OAUTH: "oauth",
6566
- API_KEY: "api_key",
6567
- BASIC_AUTH: "basic_auth",
6568
- BEARER: "bearer",
6569
- NONE: "none"
6570
- };
6571
- ORG_CREDENTIAL_AUTH_TYPES = [
6572
- AUTH_TYPE.API_KEY,
6573
- AUTH_TYPE.BEARER,
6574
- AUTH_TYPE.BASIC_AUTH
6575
- ];
6576
- AUTH_TYPE_DISPLAY = {
6577
- [AUTH_TYPE.OAUTH]: "OAuth",
6578
- [AUTH_TYPE.API_KEY]: "API Key",
6579
- [AUTH_TYPE.BASIC_AUTH]: "Basic Auth",
6580
- [AUTH_TYPE.BEARER]: "Bearer Token",
6581
- [AUTH_TYPE.NONE]: "No Authentication"
6582
- };
6583
- LEGACY_AUTH_TYPE_MAP = {
6584
- "OAuth": AUTH_TYPE.OAUTH,
6585
- "API Key": AUTH_TYPE.API_KEY,
6586
- "Basic Auth": AUTH_TYPE.BASIC_AUTH,
6587
- "Bearer Token": AUTH_TYPE.BEARER,
6588
- "No authentication": AUTH_TYPE.NONE,
6589
- // Also handle the old DISPLAY_TO_CODE bug where 'basic' was used instead of 'basic_auth'
6590
- "basic": AUTH_TYPE.BASIC_AUTH
6591
- };
6592
- VALID_AUTH_TYPES = new Set(Object.values(AUTH_TYPE));
6593
- AGENT_ROLES = [
6594
- "pilot",
6595
- "copilot",
6596
- "pilot_specialist",
6597
- "copilot_specialist",
6598
- "pilot_advisor",
6599
- "copilot_advisor",
6600
- "monitor",
6601
- "conversation_evaluator",
6602
- "message_evaluator",
6603
- "summarizer",
6604
- "consultant",
6605
- "pilot_voice"
6606
- ];
6607
- PILOT_TRACK_ROLES = ["pilot", "pilot_specialist"];
6608
- CUSTOMER_FACING_AGENT_ROLES = [...PILOT_TRACK_ROLES, "pilot_advisor"];
6609
- SAFE_USER_ID_REGEX = /^[A-Za-z0-9_-]{1,64}$/;
6610
- SUPPORTED_LOCALES = ["en", "pt", "es"];
6611
- SKILL_INSTALL_COMMAND = "mkdir -p .claude && npx skills add wayai-pro/wayai-skill -y";
6612
- }
6613
- });
6614
-
6615
6738
  // ../../packages/core/dist/chunk-L5F7ZOUJ.js
6616
6739
  function schemaToQuestions(schema) {
6617
6740
  const classified = classifySchema(schema);
@@ -6790,7 +6913,7 @@ var init_chunk_T7KQKDET = __esm({
6790
6913
  }
6791
6914
  });
6792
6915
 
6793
- // ../../packages/core/dist/chunk-6O3TITL5.js
6916
+ // ../../packages/core/dist/chunk-2745FTNX.js
6794
6917
  function containsKanbanPlaceholders(value) {
6795
6918
  if (value == null) return false;
6796
6919
  const serialized = typeof value === "string" ? value : JSON.stringify(value);
@@ -6822,12 +6945,12 @@ function typeMatches(typeField, allowed) {
6822
6945
  if (Array.isArray(typeField)) return typeField.every((t) => typeof t === "string" && allowed.has(t));
6823
6946
  return false;
6824
6947
  }
6825
- function validateSchema(schema, path41, errors, opts = {}) {
6948
+ function validateSchema(schema, path42, errors, opts = {}) {
6826
6949
  if (typeof schema === "boolean") return;
6827
6950
  const depth = opts.depth ?? 0;
6828
6951
  if (depth > MAX_SCHEMA_DEPTH) {
6829
6952
  errors.push({
6830
- path: path41 || "<root>",
6953
+ path: path42 || "<root>",
6831
6954
  message: `schema nesting exceeds ${MAX_SCHEMA_DEPTH} levels`,
6832
6955
  suggestion: "Flatten the schema; LLM providers reject deeply nested tool input_schemas."
6833
6956
  });
@@ -6835,7 +6958,7 @@ function validateSchema(schema, path41, errors, opts = {}) {
6835
6958
  }
6836
6959
  if (!isRecord2(schema)) {
6837
6960
  errors.push({
6838
- path: path41,
6961
+ path: path42,
6839
6962
  message: `expected object, got ${schema === null ? "null" : typeof schema}`
6840
6963
  });
6841
6964
  return;
@@ -6843,14 +6966,14 @@ function validateSchema(schema, path41, errors, opts = {}) {
6843
6966
  if (opts.isRoot) {
6844
6967
  if ("type" in schema && schema.type !== "object") {
6845
6968
  errors.push({
6846
- path: path41 ? `${path41}.type` : "type",
6969
+ path: path42 ? `${path42}.type` : "type",
6847
6970
  message: `root type must be 'object', got ${JSON.stringify(schema.type)}`,
6848
6971
  suggestion: "Tool parameters at the root must be an object: `{ type: 'object', properties: { ... } }`."
6849
6972
  });
6850
6973
  }
6851
6974
  } else if ("type" in schema && !typeMatches(schema.type, ALLOWED_TYPES)) {
6852
6975
  errors.push({
6853
- path: `${path41}.type`,
6976
+ path: `${path42}.type`,
6854
6977
  message: `type must be one of ${[...ALLOWED_TYPES].join("/")} or an array of those, got ${JSON.stringify(schema.type)}`
6855
6978
  });
6856
6979
  }
@@ -6860,25 +6983,25 @@ function validateSchema(schema, path41, errors, opts = {}) {
6860
6983
  const isPlaceholder = PLACEHOLDER_TOKENS.includes(e);
6861
6984
  const isOutcomePlaceholder = e === "[KANBAN_OUTCOME_VALUES]";
6862
6985
  errors.push({
6863
- path: `${path41}.enum`,
6986
+ path: `${path42}.enum`,
6864
6987
  message: `enum must be a non-empty array of primitives, got string ${JSON.stringify(e)}`,
6865
6988
  suggestion: isOutcomePlaceholder ? "Declare `outcomes` on the hub's terminal kanban status so the platform can render the placeholder into a valid array; with none configured the platform drops the parameter instead." : isPlaceholder ? "Set `operation: 'update_kanban_status'` on the tool and ensure at least one hub.kanban_status has `allowsAgentUpdate: true` so the platform can render the placeholder into a valid array." : 'Wrap the value in an array: `enum: ["value"]`.'
6866
6989
  });
6867
6990
  } else if (!Array.isArray(e)) {
6868
6991
  errors.push({
6869
- path: `${path41}.enum`,
6992
+ path: `${path42}.enum`,
6870
6993
  message: `enum must be a non-empty array of primitives, got ${typeof e}`
6871
6994
  });
6872
6995
  } else if (e.length === 0) {
6873
6996
  errors.push({
6874
- path: `${path41}.enum`,
6997
+ path: `${path42}.enum`,
6875
6998
  message: "enum must not be empty"
6876
6999
  });
6877
7000
  } else {
6878
7001
  for (let i = 0; i < e.length; i++) {
6879
7002
  if (!isPrimitive(e[i])) {
6880
7003
  errors.push({
6881
- path: `${path41}.enum[${i}]`,
7004
+ path: `${path42}.enum[${i}]`,
6882
7005
  message: `enum entry must be a primitive (string/number/boolean/null), got ${typeof e[i]}`
6883
7006
  });
6884
7007
  }
@@ -6888,7 +7011,7 @@ function validateSchema(schema, path41, errors, opts = {}) {
6888
7011
  for (const key of ["exclusiveMinimum", "exclusiveMaximum"]) {
6889
7012
  if (key in schema && typeof schema[key] === "boolean") {
6890
7013
  errors.push({
6891
- path: `${path41}.${key}`,
7014
+ path: `${path42}.${key}`,
6892
7015
  message: `${key} as boolean is draft-04 syntax; draft 2020-12 requires a numeric value`,
6893
7016
  suggestion: `Replace with the numeric bound, e.g. \`${key}: 0\`.`
6894
7017
  });
@@ -6897,45 +7020,45 @@ function validateSchema(schema, path41, errors, opts = {}) {
6897
7020
  if ("properties" in schema) {
6898
7021
  if (!isRecord2(schema.properties)) {
6899
7022
  errors.push({
6900
- path: `${path41}.properties`,
7023
+ path: `${path42}.properties`,
6901
7024
  message: `properties must be an object, got ${Array.isArray(schema.properties) ? "array" : typeof schema.properties}`
6902
7025
  });
6903
7026
  } else {
6904
7027
  for (const [propName, propSchema] of Object.entries(schema.properties)) {
6905
- validateSchema(propSchema, `${path41}.properties.${propName}`, errors, { depth: depth + 1 });
7028
+ validateSchema(propSchema, `${path42}.properties.${propName}`, errors, { depth: depth + 1 });
6906
7029
  }
6907
7030
  }
6908
7031
  }
6909
7032
  if (schemaTypeIncludes(schema, "array") && "items" in schema) {
6910
7033
  if (Array.isArray(schema.items)) {
6911
- schema.items.forEach((sub, i) => validateSchema(sub, `${path41}.items[${i}]`, errors, { depth: depth + 1 }));
7034
+ schema.items.forEach((sub, i) => validateSchema(sub, `${path42}.items[${i}]`, errors, { depth: depth + 1 }));
6912
7035
  } else {
6913
- validateSchema(schema.items, `${path41}.items`, errors, { depth: depth + 1 });
7036
+ validateSchema(schema.items, `${path42}.items`, errors, { depth: depth + 1 });
6914
7037
  }
6915
7038
  }
6916
7039
  for (const key of SUBSCHEMA_OBJECT_KEYWORDS) {
6917
7040
  if (key in schema && isRecord2(schema[key])) {
6918
- validateSchema(schema[key], `${path41}.${key}`, errors, { depth: depth + 1 });
7041
+ validateSchema(schema[key], `${path42}.${key}`, errors, { depth: depth + 1 });
6919
7042
  }
6920
7043
  }
6921
7044
  for (const key of SUBSCHEMA_LIST_KEYWORDS) {
6922
7045
  const list = schema[key];
6923
7046
  if (Array.isArray(list)) {
6924
- list.forEach((sub, i) => validateSchema(sub, `${path41}.${key}[${i}]`, errors, { depth: depth + 1 }));
7047
+ list.forEach((sub, i) => validateSchema(sub, `${path42}.${key}[${i}]`, errors, { depth: depth + 1 }));
6925
7048
  }
6926
7049
  }
6927
7050
  for (const key of SUBSCHEMA_MAP_KEYWORDS) {
6928
7051
  const map = schema[key];
6929
7052
  if (isRecord2(map)) {
6930
7053
  for (const [name, sub] of Object.entries(map)) {
6931
- validateSchema(sub, `${path41}.${key}.${name}`, errors, { depth: depth + 1 });
7054
+ validateSchema(sub, `${path42}.${key}.${name}`, errors, { depth: depth + 1 });
6932
7055
  }
6933
7056
  }
6934
7057
  }
6935
7058
  const reportedPaths = new Set(errors.map((e) => e.path));
6936
7059
  for (const [k, v] of Object.entries(schema)) {
6937
7060
  if (typeof v !== "string") continue;
6938
- const fieldPath = `${path41}.${k}`;
7061
+ const fieldPath = `${path42}.${k}`;
6939
7062
  if (reportedPaths.has(fieldPath)) continue;
6940
7063
  for (const token of PLACEHOLDER_TOKENS) {
6941
7064
  if (v === token) {
@@ -6991,12 +7114,12 @@ function validateFollowupLinks(followups, label, ctx) {
6991
7114
  const linkTargets = /* @__PURE__ */ new Set();
6992
7115
  followups.forEach((followup, i) => {
6993
7116
  const ref = followup?.after_followup_id;
6994
- const path41 = ["followups", i, "after_followup_id"];
7117
+ const path42 = ["followups", i, "after_followup_id"];
6995
7118
  if (followup?.type !== "inactivity_after_before_event") {
6996
7119
  if (ref !== void 0) {
6997
7120
  ctx.addIssue({
6998
7121
  code: external_exports.ZodIssueCode.custom,
6999
- path: path41,
7122
+ path: path42,
7000
7123
  message: `kanban status ${label}: after_followup_id is only valid on inactivity_after_before_event followups (this one is ${followup?.type})`
7001
7124
  });
7002
7125
  }
@@ -7005,7 +7128,7 @@ function validateFollowupLinks(followups, label, ctx) {
7005
7128
  if (ref === void 0) {
7006
7129
  ctx.addIssue({
7007
7130
  code: external_exports.ZodIssueCode.custom,
7008
- path: path41,
7131
+ path: path42,
7009
7132
  message: `kanban status ${label}: inactivity_after_before_event requires after_followup_id naming the id of a before_event followup in the same status`
7010
7133
  });
7011
7134
  return;
@@ -7015,7 +7138,7 @@ function validateFollowupLinks(followups, label, ctx) {
7015
7138
  if (matches.length > 1) {
7016
7139
  ctx.addIssue({
7017
7140
  code: external_exports.ZodIssueCode.custom,
7018
- path: path41,
7141
+ path: path42,
7019
7142
  message: `kanban status ${label}: after_followup_id "${ref}" matches ${matches.length} followups \u2014 a link must name exactly one`
7020
7143
  });
7021
7144
  return;
@@ -7027,7 +7150,7 @@ function validateFollowupLinks(followups, label, ctx) {
7027
7150
  );
7028
7151
  ctx.addIssue({
7029
7152
  code: external_exports.ZodIssueCode.custom,
7030
- path: path41,
7153
+ path: path42,
7031
7154
  message: hasIdlessBeforeEvent ? `kanban status ${label}: after_followup_id "${ref}" matches no followup \u2014 a link target must declare an explicit id, and this status has before_event followups without one` : `kanban status ${label}: after_followup_id "${ref}" matches no followup in this status`
7032
7155
  });
7033
7156
  return;
@@ -7035,7 +7158,7 @@ function validateFollowupLinks(followups, label, ctx) {
7035
7158
  if (target.type !== "before_event") {
7036
7159
  ctx.addIssue({
7037
7160
  code: external_exports.ZodIssueCode.custom,
7038
- path: path41,
7161
+ path: path42,
7039
7162
  message: `kanban status ${label}: after_followup_id "${ref}" points at a ${target.type} followup \u2014 only before_event followups can anchor a chain`
7040
7163
  });
7041
7164
  }
@@ -7305,9 +7428,9 @@ function monitorRuleActions(monitorConfig) {
7305
7428
  if (!monitorConfig || typeof monitorConfig !== "object") return [];
7306
7429
  const config = monitorConfig;
7307
7430
  const found = [];
7308
- const visit = (action, path41) => {
7431
+ const visit = (action, path42) => {
7309
7432
  if (!action || typeof action !== "object" || Array.isArray(action)) return;
7310
- found.push({ action, path: path41 });
7433
+ found.push({ action, path: path42 });
7311
7434
  };
7312
7435
  if (Array.isArray(config.rules)) {
7313
7436
  config.rules.forEach((rule, index) => {
@@ -7339,25 +7462,25 @@ function collectMonitorRuleIssues(monitorConfig) {
7339
7462
  const trigger = resolveMonitorTrigger(monitorConfig);
7340
7463
  const kinds = monitorRuleActionKinds(trigger);
7341
7464
  const issues = [...callUtteranceRuleIssues(monitorConfig), ...automationGateIssues(monitorConfig)];
7342
- for (const { action, path: path41 } of monitorRuleActions(monitorConfig)) {
7343
- if (trigger === "call_utterance" && path41[0] === "fallback") continue;
7465
+ for (const { action, path: path42 } of monitorRuleActions(monitorConfig)) {
7466
+ if (trigger === "call_utterance" && path42[0] === "fallback") continue;
7344
7467
  const kind = action.kind;
7345
7468
  if (typeof kind === "string" && !kinds.includes(kind)) {
7346
- issues.push({ path: [...path41, "kind"], message: monitorActionKindMessage(kind, trigger) });
7469
+ issues.push({ path: [...path42, "kind"], message: monitorActionKindMessage(kind, trigger) });
7347
7470
  }
7348
7471
  const toolName = action.tool_name;
7349
7472
  if (kind === "call_tool" && typeof toolName === "string" && isRefusedNativeToolName(toolName, trigger)) {
7350
- issues.push({ path: [...path41, "tool_name"], message: monitorRuleToolNotAllowedMessage(toolName, trigger) });
7473
+ issues.push({ path: [...path42, "tool_name"], message: monitorRuleToolNotAllowedMessage(toolName, trigger) });
7351
7474
  continue;
7352
7475
  }
7353
7476
  if (kind === "call_tool" && toolName === INSERT_NOTE_TOOL_NAME) {
7354
- issues.push(...insertNoteArgumentIssues(action, path41));
7477
+ issues.push(...insertNoteArgumentIssues(action, path42));
7355
7478
  }
7356
7479
  if (kind === "call_tool" && toolName === RUN_MONITOR_TOOL_NAME) {
7357
7480
  const callee = readRunMonitorCallee(action);
7358
7481
  if (!callee.ok) {
7359
7482
  issues.push({
7360
- path: [...path41, "args", "monitor_name"],
7483
+ path: [...path42, "args", "monitor_name"],
7361
7484
  message: runMonitorCalleeMessage(callee.reason)
7362
7485
  });
7363
7486
  }
@@ -7417,11 +7540,11 @@ function insertNoteTemplateMessage(reason) {
7417
7540
  return `insert_note's template is longer than the ${MONITOR_NOTE_TEMPLATE_MAX}-character limit.`;
7418
7541
  }
7419
7542
  }
7420
- function insertNoteArgumentIssues(action, path41) {
7543
+ function insertNoteArgumentIssues(action, path42) {
7421
7544
  const result = readInsertNoteTemplate(action);
7422
7545
  if (result.ok) return [];
7423
7546
  return [{
7424
- path: [...path41, "args", "template"],
7547
+ path: [...path42, "args", "template"],
7425
7548
  message: insertNoteTemplateMessage(result.reason)
7426
7549
  }];
7427
7550
  }
@@ -7518,8 +7641,8 @@ function evalInitialStateError(input) {
7518
7641
  const parsed = evalInitialStateEntry.safeParse(entries[i]);
7519
7642
  if (!parsed.success) {
7520
7643
  const issue = parsed.error.issues[0];
7521
- const path41 = issue?.path.join(".") || "?";
7522
- return `initial_state[${i}].${path41} is invalid: ${issue?.message ?? "malformed"}`;
7644
+ const path42 = issue?.path.join(".") || "?";
7645
+ return `initial_state[${i}].${path42} is invalid: ${issue?.message ?? "malformed"}`;
7523
7646
  }
7524
7647
  if (seenSlugs.has(parsed.data.slug)) {
7525
7648
  return `initial_state[${i}].slug "${parsed.data.slug}" is declared more than once`;
@@ -7743,10 +7866,10 @@ function refineHubAsCodeEvals(config, ctx) {
7743
7866
  function refineHubAsCodeEvalAttachments(config, ctx) {
7744
7867
  const cfg = config;
7745
7868
  const referencedHashes = /* @__PURE__ */ new Set();
7746
- const addTurnIssue = (path41, turn, name) => {
7869
+ const addTurnIssue = (path42, turn, name) => {
7747
7870
  const error = evalTurnAttachmentsError(turn);
7748
7871
  if (error) {
7749
- ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: path41, message: `${name}: ${error}` });
7872
+ ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: path42, message: `${name}: ${error}` });
7750
7873
  return;
7751
7874
  }
7752
7875
  for (const hash of collectTurnAttachmentHashes(turn)) referencedHashes.add(hash);
@@ -7821,17 +7944,17 @@ function refineHubAsCodeCallOpenings(config, ctx) {
7821
7944
  const agent = entry;
7822
7945
  const openings = agent?.call_openings;
7823
7946
  if (openings === void 0 || openings === null) return;
7824
- const path41 = ["agents", a, "call_openings"];
7947
+ const path42 = ["agents", a, "call_openings"];
7825
7948
  const name = `agent "${typeof agent?.name === "string" ? agent.name : "<unnamed>"}"`;
7826
7949
  if (typeof openings !== "object" || Array.isArray(openings)) {
7827
- ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: path41, message: `${name}: call_openings must map a language to an opening` });
7950
+ ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: path42, message: `${name}: call_openings must map a language to an opening` });
7828
7951
  return;
7829
7952
  }
7830
7953
  if (agent?.role !== "pilot_voice" && Object.keys(openings).length > 0) {
7831
- ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: path41, message: `${name}: only a pilot_voice agent has call_openings` });
7954
+ ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: path42, message: `${name}: only a pilot_voice agent has call_openings` });
7832
7955
  }
7833
7956
  for (const [language, raw] of Object.entries(openings)) {
7834
- const at = [...path41, language];
7957
+ const at = [...path42, language];
7835
7958
  if (!callOpeningLanguage.safeParse(language).success) {
7836
7959
  ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: at, message: `${name}: call_openings language must be one of ${CALL_OPENING_LANGUAGES.join(", ")}` });
7837
7960
  continue;
@@ -7958,11 +8081,11 @@ function refineHubAsCodeDelegation(config, ctx) {
7958
8081
  }
7959
8082
  }
7960
8083
  if (del.context_boundary === void 0) return;
7961
- const path41 = ["agents", agentIndex, "tools", "delegation", delIndex, "context_boundary"];
8084
+ const path42 = ["agents", agentIndex, "tools", "delegation", delIndex, "context_boundary"];
7962
8085
  if (del.type !== "hub") {
7963
8086
  ctx.addIssue({
7964
8087
  code: external_exports.ZodIssueCode.custom,
7965
- path: path41,
8088
+ path: path42,
7966
8089
  message: `context_boundary applies only to \`type: hub\` delegations (got type "${String(del.type)}")`
7967
8090
  });
7968
8091
  return;
@@ -7970,7 +8093,7 @@ function refineHubAsCodeDelegation(config, ctx) {
7970
8093
  if (!CONTEXT_BOUNDARIES.includes(del.context_boundary)) {
7971
8094
  ctx.addIssue({
7972
8095
  code: external_exports.ZodIssueCode.custom,
7973
- path: path41,
8096
+ path: path42,
7974
8097
  message: `context_boundary must be one of: ${CONTEXT_BOUNDARIES.join(", ")}`
7975
8098
  });
7976
8099
  }
@@ -8114,10 +8237,10 @@ function refineHubAsCodeMonitorRulesOutput(config, ctx) {
8114
8237
  });
8115
8238
  }
8116
8239
  var PLACEHOLDER_TOKENS, ALLOWED_TYPES, SUBSCHEMA_OBJECT_KEYWORDS, SUBSCHEMA_LIST_KEYWORDS, SUBSCHEMA_MAP_KEYWORDS, MAX_SCHEMA_DEPTH, uuidSchema, USER_ID_REGEX, timestampSchema, idParamSchema, clientOptionalString, clientOptionalBoolean, clientOptionalNumber, messageAttachment, MAX_MESSAGE_BODY_BYTES, MAX_ATTACHMENTS_PER_MESSAGE, MESSAGE_ENVELOPE_HEADROOM_BYTES, MAX_AUDIO_FILE_BASE64_BYTES, MAX_KANBAN_STATUSES, MAX_FOLLOWUPS_PER_STATUS, MAX_LANES, MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES, RESERVED_TEMPLATE_DUMP_NAME, kanbanStatusSlugSchema, followupTypeSchema, EVENT_RELATIVE_FOLLOWUP_TYPES, followupTimeUnitSchema, followupIdSchema, SELECTABLE_FOLLOWUP_TYPES, MAX_LINKED_FOLLOWUP_TARGETS_PER_STATUS, followupSchema, MAX_OUTCOMES_PER_STATUS, kanbanOutcomeSchema, EXCLUSIVE_FLAG_PAIRS, kanbanStatusSchema, kanbanStatusesArraySchema, laneSchema, lanesArraySchema, toolIdParam, listToolsQuery, toolAgentQuery, deleteToolQuery, toolConnectionsQuery, nativeToolIdSchema, CONTEXT_BOUNDARIES, contextBoundarySchema, addNativeToolBody, addMcpToolBody, createCustomToolBody, updateCustomToolBody, updateToolExecutionConfigBody, primaryRegionSchema, placementSourceSchema, orgIdParam, orgAdminIdParam, createOrganizationBody, updateOrganizationBody, addOrgAdminBody, HUB_DISPLAY_NAME_MAX_CHARS, HUB_WELCOME_MESSAGE_MAX_CHARS, HUB_STARTER_QUESTIONS_MAX, HUB_STARTER_QUESTION_MAX_CHARS, displayName, welcomeMessage, starterQuestions, hubDisplayNamesSchema, hubWelcomeMessagesSchema, hubStarterQuestionsSchema, hubDisplayNamesField, hubWelcomeMessagesField, hubStarterQuestionsField, HUB_PRESENTATION_FIELDS, HUB_PRESENTATION_SCHEMAS, hubIdParam, hubAdminIdParam, hubUserIdParam, hubIdentityIdParam, hubTeamIdParam, hubTeamUserDeleteParam, hubSchemaQuery, HUB_USERS_PAGE_SIZE_MAX, HUB_USERS_SEARCH_MAX, HUB_USERS_CHANNEL_TYPES, getHubUsersQuery, PREVIEW_LABEL_MAX_LENGTH, MAX_ENDED_INDEX_RETENTION_DAYS, MAX_EVAL_RETENTION_DAYS, MAX_END_USER_DAILY_MESSAGE_LIMIT, endUserDailyMessageLimitField, previewLabelField, hubTagsField, createHubBody, updateHubBody, HUB_TAG_CHANGE_REFUSED, hubTagChangeRefusalSchema, addHubAdminBody, addHubIdentityAuthorizationBody, contactDecisionBody, approveContactBody, CONTACT_ACCESS_PAGE_SIZE_MAX, listContactAccessQuery, createHubTeamBody, updateHubTeamBody, addHubTeamUserBody, reassignHubUserBody, replicatePreviewBody, HUB_DIFF_SECTION_SET, HUB_DIFF_SECTIONS, updateChannelTestIdentitiesBody, claimCodeChannelParam, claimCodeDeleteParam, PREVIOUS_CONVERSATIONS_MAX, 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, evalIdParam, sessionIdParam, scenarioSetIdParam, hubIdQuery, evalDateContextSchema, 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, EVAL_ATTACHMENT_HASH_REGEX, evalAttachmentRef, turnMayCarryAttachments, ATTACHMENTS_USER_ONLY_MESSAGE, journeyIdParam, journeyToolCallSchema, journeyTurnSchema, journeyStepOverrideSchema, fixtureField, createJourneyBody, updateJourneyBody, evalSessionConfigResponseSchema, evalSessionResponseSchema, evalSessionListConfigSchema, evalSessionListItemSchema, seedReleaseStatusSchema, EVAL_SESSION_NOT_QUIESCENT, MAX_RESOURCE_FILE_SIZE, CALL_OPENING_LANGUAGES, callOpeningLanguage, CALL_OPENING_MAX_DURATION_MS, CALL_OPENING_MAX_BYTES, CALL_OPENING_CAPTION_MAX_CHARS, CALL_OPENING_CONTENT_TYPES, callOpeningContentType, CALL_OPENING_HASH_REGEX, callOpeningHash, callOpeningCaption, storedCallOpening, MAX_CALL_OPENING_ENCODED_BYTES, MAX_CALL_OPENING_BODY_BYTES, agentCallOpeningParams, putAgentCallOpeningBody, deleteAgentCallOpeningQuery, callOpeningParam, callOpeningQuery, 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;
8117
- var init_chunk_6O3TITL5 = __esm({
8118
- "../../packages/core/dist/chunk-6O3TITL5.js"() {
8240
+ var init_chunk_2745FTNX = __esm({
8241
+ "../../packages/core/dist/chunk-2745FTNX.js"() {
8119
8242
  "use strict";
8120
- init_chunk_SNA2DXAC();
8243
+ init_chunk_QT7NKKPO();
8121
8244
  init_chunk_MIWZOSPI();
8122
8245
  init_chunk_IBL7FANV();
8123
8246
  init_chunk_2ISUBJG7();
@@ -9610,7 +9733,7 @@ var init_chunk_6O3TITL5 = __esm({
9610
9733
  }
9611
9734
  });
9612
9735
 
9613
- // ../../packages/core/dist/chunk-RBKQBA3D.js
9736
+ // ../../packages/core/dist/chunk-XJIPLYNP.js
9614
9737
  function cacheReconcileIdCount(body) {
9615
9738
  return body.conversations.length + body.histories.reduce((n, history) => n + history.conversation_ids.length, 0) + body.threads.length;
9616
9739
  }
@@ -9656,16 +9779,16 @@ function parseCommunityLessonVideoUrl(url) {
9656
9779
  const parts = /^https?:\/\/([^/?#]+)([^?#]*)(?:\?([^#]*))?(?:#.*)?$/i.exec(url.trim());
9657
9780
  if (!parts) return null;
9658
9781
  const host = parts[1].toLowerCase();
9659
- const path41 = parts[2] ?? "";
9782
+ const path42 = parts[2] ?? "";
9660
9783
  const query = parts[3] ?? "";
9661
9784
  let id;
9662
9785
  if (host === YOUTU_BE) {
9663
- id = /^\/([A-Za-z0-9_-]{11})\/?$/.exec(path41)?.[1];
9786
+ id = /^\/([A-Za-z0-9_-]{11})\/?$/.exec(path42)?.[1];
9664
9787
  } else if (YOUTUBE_HOSTS.has(host)) {
9665
- if (path41 === "/watch" || path41 === "/watch/") {
9788
+ if (path42 === "/watch" || path42 === "/watch/") {
9666
9789
  id = query.split("&").find((param) => param.startsWith("v="))?.slice(2);
9667
9790
  } else {
9668
- id = YOUTUBE_ID_PATH.exec(path41)?.[1];
9791
+ id = YOUTUBE_ID_PATH.exec(path42)?.[1];
9669
9792
  }
9670
9793
  }
9671
9794
  return id !== void 0 && YOUTUBE_ID.test(id) ? { provider: "youtube", id } : null;
@@ -9677,12 +9800,12 @@ function communityLessonVideoWatchUrl(video) {
9677
9800
  }
9678
9801
  }
9679
9802
  var connectionIdParam, connectorIdParam, listConnectionsQuery, deleteConnectionQuery, addConnectionBody, editConnectionBody, PRODUCTION_DIRECT_FIELDS, setProductionCredentialBody, registerWhatsappQuery, registerWhatsappBody, retryProvisioningQuery, resendDomainStatusQuery, initialValueCreateSchema, initialValueUpdateSchema, stateIdParam, listStatesQuery, stateNameSchema, createStateBody, updateStateBody, reorderStatesBody, variantAiModeSchema, experimentStatusSchema, overlayUpdateSchema, experimentIdParam, variantIdParam, listExperimentsQuery, listVariantsQuery, listOverridesQuery, deleteOverrideQuery, createExperimentBody, updateExperimentBody, setExperimentStatusBody, createVariantBody, updateVariantBody, upsertOverrideBody, orgTagIdParam, listOrgTagsQuery, ORG_TAG_NAME_REGEX, ORG_TAG_NAME_MAX_LENGTH, createOrgTagBody, updateOrgTagBody, orgCredentialIdParam, listOrgCredentialsQuery, createOrgCredentialBody, updateOrgCredentialBody, BASE_CREDENTIAL_MANAGED_BY, BASE_CREDENTIAL_NAME_MAX, baseCredentialNameSchema, createBaseCredentialLinkBody, baseCredentialLinkParams, baseCredentialLinkQuery, orgResourceIdParam, orgResourceFileIdParam, orgResourceFolderIdParam, hubOrgResourceParam, listOrgResourcesQuery, orgIdQuery, createOrgResourceBody, updateOrgResourceBody, createOrgResourceFolderBody, updateOrgResourceFolderBody, uploadOrgResourceFileBody, updateOrgResourceFileBody, uploadOrgSkillZipBody, linkOrgResourceBody, resourceIdParam, listResourcesQuery, createResourceBody, updateResourceBody, syncSkillsBody, resourceFileIdParam, listResourceFilesQuery, createResourceFileBody, updateResourceFileBody, uploadResourceFileBody, uploadSkillZipBody, resourceFolderIdParam, listResourceFoldersQuery, createResourceFolderBody, updateResourceFolderBody, agentResourceQuery, hubResourceQuery, linkAgentResourceBody, updateAgentResourceBody, unlinkAgentResourceQuery, navItemSchema, hubCountResetBody, navItemCountResetBody, typingBody, analyticsHubIdParam, analyticsVariableIdParam, updateVariablePinBody, updateAnalyticsViewBody, NUMERIC_FILTER_OPS, TEXT_FILTER_OPS, CATEGORICAL_FILTER_OPS, VARIABLE_FILTER_OPS, STRUCTURED_QUERY_OPS, STRUCTURED_QUERY_AGGREGATIONS, filterValueSchema, conversationsBody, analyticsConversationIdParam, messagesQuery, conversationDetailDataQuery, analyticsDataBody, structuredQueryBody, analyticsSqlBody, analyticsSqlTable, analyticsSqlSchemaQuery, getConversationsQuery, getMessagesQuery, appMessageSenderType, appMessageReceiverType, apiChannelMessage, apiChannelMessageBody, appMessageBody, appMessageResponse, CALL_STATUSES, callStatus, CALL_END_REASONS, callEndReason, CALL_TRANSPORTS, callTransport, CALL_PARTICIPANT_TYPES, callParticipantType, callInstant, MAX_SDP_OFFER_LENGTH, sdpDescription, sdpOffer, MAX_CALL_REQUEST_BODY_BYTES, hubScoped, callSummaryFields, callSummary, callIdParam, createCallBody, createCallResponse, callReadyBody, callHangupBody, callStatusQuery, MAX_REPORTED_DELEGATION_IDS, callDelegationId, callDelegationsBody, callResponse, MAX_CALL_RECORDING_GAPS, callRecordingGap, callRecordingNoteMetadata, 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, updateUserBody, updateProfileBody, pathnameRegex, updatePreferencesBody, registerPushTokenBody, deletePushTokenQuery, recordAiDisclosureAcceptanceBody, activityQuery, deletionModeSchema, deletionRequestBody, CACHE_RECONCILE_MAX_IDS, CACHE_RECONCILE_MAX_HUBS, cacheReconcileScopeSchema, cachedConversationPageSchema, cachedHistoryThreadSchema, cachedPeopleThreadSchema, cacheReconcileBody, archiveHubIdParam, archiveConversationParams, archiveListQuery, archiveMessageObservabilityParams, conversationIdParam, conversationHubQuery, claimBody, releaseBody, transferBody, closeBody, additionalContextPayloadSchema, kanbanUpdateBody, annotateConversationBody, observabilityParams, observabilityListParams, deleteUserConversationsBody, deleteUserConversationsResponse, sendMessageBody, listConversationsQuery, flagSourceSchema, getConversationsResponse, getConversationDetailParams, getConversationDetailQuery, getConversationDetailResponse, listWhatsAppTemplatesQuery, sendWhatsAppTemplateBody, copilotSuggestBody, copilotSuggestResponse, CONSULT_THREAD_STATUSES, consultThreadStatus, CONSULT_THREAD_TITLE_MAX, consultThreadTitle, consultThreadSummary, listConsultThreadsQuery, listConsultThreadsResponse, createConsultThreadBody, createConsultThreadResponse, consultThreadIdParam, updateConsultThreadBody, updateConsultThreadResponse, CONSULT_AWAIT_TIMEOUT_MS, billingOrgIdParam, subscriptionItemParams, planKeySchema, billingStatusSchema, paidTierSchema, spendCapBody, growthPacksBody, portalSessionBody, checkoutSessionBody, changeTierBody, updateBillingCurrencyBody, invoicesQuery, billingPlanTypeSchema, dataUsageCountersSchema, REKOR_ENTITLEMENT_CONTRACT_VERSION, entitlementProjectionSchema, rekorEntitlementRefreshMessageSchema, downloadBody, uploadQuery, SIGN_URL_MAX_EXPIRES_IN_SECONDS, signUrlBody, templateIdParam, listTemplatesQuery, deleteTemplateQuery, templateStatusQuery, createTemplateBody, updateTemplateBody, submitTemplateBody, testTemplateBody, 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, CONTACT_BOOK_EMAIL_UNSUBSCRIBE_PATH, contactBookEmailUnsubscribeTokenSchema, contactBookEmailUnsubscribeQuery, orgListReferenceSchema, hubListNameSchema, HUB_LIST_FILTER_REQUIRED, hubContactListFilterSchema, hubContactListIdParam, hubContactListHubQuery, description, createHubContactListBody, updateHubContactListBody, 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, AUTOMATION_WEBHOOK_MOUNT, 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, VERSION_PART, MOBILE_APP_VERSION_RE, mobileAppVersionSchema, MOBILE_PLATFORMS, mobilePlatformSchema, mobileVersionPolicyQuery, mobileVersionPolicySchema, mobileVersionPolicyResponse, adminOrgIdParam, adminOrgAdminIdParam, adminUserIdParam, PRICING_PLAN_ID_RE, adminPlanIdParam, adminOrganizationsQuery, adminUserSearchQuery, kanbanSlugMigrationQuery, adjustQuotaBody, updatePlanBody, addAdminUserBody, MAX_VOICE_CALL_MINUTE_OPS, voiceCallMinuteOps, AUTOMATION_GATE_EVALUATIONS_PER_OPERATION_BOUND, automationGateEvaluationsPerOperation, AUTOMATION_RUN_RETENTION_DAYS_MAX, automationRunRetentionDays, TURN_DEADLINE_SECONDS_FLOOR, TURN_DEADLINE_SECONDS_MAX, turnDeadlineSeconds, updatePlatformConfigBody, updateFreeOrgLimitBody, adminScopedTargetShape, adminScopedTargetBody, BRANCHING_ORPHAN_ENTITY_TYPES, BRANCHING_ORPHAN_MAX_TARGETS, adminRepairBranchingOrphansBody, adminRepairLegacyOrgGrantsBody, adminRepairCompedPlansBody, updatePricingPlanBody, dataExplorerSearchQuery, dataExplorerOrgIdParam, dataExplorerHubIdParam, dataExplorerConvIdParam, dataExplorerDoInstancesQuery, dataExplorerNsIdParam, dataExplorerKvKeysBody, dataExplorerKvKeyBody, uuidOrHexId, dataExplorerDeleteOrgParam, dataExplorerDeleteHubParam, dataExplorerDeleteConvParam, dataExplorerDeleteUserParam, dataExplorerDeleteQuery, dataExplorerKvDeleteBody, pitrDoNamespace, pitrBookmarkParam, pitrRestoreBody, healthSamplingTriggerBody, dataExplorerDebugDoType, DEBUG_READ_MAX_LIMIT, DEBUG_READ_DEFAULT_LIMIT, DEBUG_DO_HEX_PREFIX, debugDoEntityId, debugTableName, dataExplorerDebugTablesParam, dataExplorerDebugRowsParam, dataExplorerDebugRowsQuery, dataExplorerDebugAnalyticsTable, debugUuid, dataExplorerDebugAnalyticsRowsParam, dataExplorerDebugAnalyticsRowsQuery, debugHubConvParam, debugMessageIdQuery, META_ENTITY_ID_PATTERN, metaEntityId, whatsappCallbackBody, authMeResponse, wsTicketResponse, sessionCheckResponse, logoutResponse, magicCodeSendBody, magicCodeSendResponse, magicCodeVerifyBody, magicCodeVerifyResponse, passwordLoginBody, normalizeEmail, REVIEW_ACCOUNT_EMAILS, stateOperationBody, conversationListResourcesQuery, conversationReadResourceQuery, listPendingSchedulesQuery, listHubAggregateSchedulesQuery, reportSourceSchema, intakeReportSourceSchema, reportClassificationSchema, reportStatusSchema, reportLocaleSchema, reportMessageAuthorRoleSchema, reportMessageSchema, sentryRefStatusSchema, createReportBody, editReportBody, reporterReportSummarySchema, reporterListResponseSchema, getReportResponseSchema, reporterTransitionResponseSchema, contestReportBody, reporterListQuery, listReportsQuery, GITHUB_ISSUE_URL_REGEX, githubIssueUrlSchema, transitionReportBody, groupReportsBody, holdReportBody, clickhouseReadyResponse, bootstrapQuery, MAX_NAME_LENGTH, MAX_VALUE_LENGTH, MAX_TAGS, MAX_TAG_LENGTH, MAX_SCOPE_HUBS, MAX_SCOPE_TAGS, vaultSecretScopeSchema, vaultCreateBody, vaultUpdateBody, MAX_NAME_LENGTH2, MAX_HUBS_PER_GRANT, MAX_HUB_TAGS_PER_GRANT, MAX_GRANTS, permissionEnum, grantScopeSchema, grantSchema, createTokenBody, tokenOrgIdParam, invitePreviewQuery, inviteRolePreviewResponse, inviteContactPreviewResponse, invitePreviewResponse, inviteUnsubscribeBody, jsonSchemaSchema, hubUserIdentity, stateValueEntry, getHubUserContextResponse, updateHubUserBody, updateHubUserResponse, unlockHubUserNameResponse, stateResetParams, stateResetResponse, hubAlertsParam, hubAlertSeverity, hubAlert, hubAlertsListResponse, noticeSeveritySchema, noticeStatusSchema, NOTICE_SCOPE_REGEX, noticeScopeSchema, noticeLinkSchema, createNoticeBody, updateNoticeBody, listNoticesQuery, noticeIdParamSchema, ADMIN_SKILL_NAME_REGEX, adminSkillNameParam, 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, DATA_PROXY_MOUNT, DATA_PROXY_PREFIX, REKOR_V1_PREFIX, DATA_PROXY_ORG_QUERY_PARAM, MAX_PROVISIONING_BODY_BYTES, dataProxyQuery, rekorAttestation, REQUIRED_REKOR_ATTESTATION_HEADERS, BASE_DESTRUCTION_MOUNT, BASE_DESTRUCTION_PREFIX, BASE_DESTRUCTION_CONFIRM_PATH, baseDestructionConfirmBody, BASE_DESTRUCTION_GRACE_MS, BASE_DESTRUCTION_CONFIRM_TTL_MS, BASE_DESTRUCTION_ORG_QUERY_PARAM, baseDestructionQuery, baseDestructionParam, baseDestructionInitiateBody, baseDestructionStatus, baseDestructionRequest, baseDestructionListResponse, baseDestructionInitiateResponse, baseDestructionConfirmResponse, baseDestructionCancelResponse, rekorBaseChangeMessageSchema, baseEnvironmentSchema, toolsetSurfaceSchema, toolsetConnectionBindingSchema, rekorToolsetToolsSchema, rekorResolvedToolsetSchema, PEOPLE_CONTACT_PAGE_MAX, PEOPLE_CONTACT_PAGE_DEFAULT, PEOPLE_CONTACT_EMAIL_MAX_LENGTH, peopleUserIdSchema, peopleInviteEmailSchema, peopleContactInviteBody, peopleContactInviteIdParam, peopleContactUserIdParam, peopleContactBlockBody, peopleContactPageQuery, peopleOutgoingInviteSchema, peopleContactPersonSchema, peopleContactSchema, peopleIncomingInviteSchema, peopleBlockedUserSchema, PEOPLE_THREAD_MESSAGE_MAX_LENGTH, PEOPLE_THREAD_MESSAGES_PAGE_MAX, PEOPLE_THREAD_PAGE_MAX, PEOPLE_THREAD_PAGE_DEFAULT, PEOPLE_GROUP_NAME_MAX_LENGTH, PEOPLE_GROUP_AVATAR_URL_MAX_LENGTH, PEOPLE_THREAD_ATTACHMENT_MAX_BYTES, PEOPLE_THREAD_ATTACHMENT_NAME_MAX_LENGTH, PEOPLE_ATTACHMENT_STORAGE_PER_USER_BYTES, PEOPLE_THREAD_ATTACHMENT_MAX_MB, PEOPLE_THREAD_ATTACHMENT_URL_TTL_SECONDS, PEOPLE_THREAD_ATTACHMENT_URLS_MAX, peopleThreadIdParam, peopleThreadMessageIdParam, peopleThreadListQuery, peopleThreadMessagesQuery, peopleThreadAttachmentUploadSchema, peopleThreadSendBody, peopleThreadAttachmentUrlsBody, peopleThreadReadBody, peopleThreadSettingsBody, peopleGroupNameSchema, peopleGroupAvatarUrlSchema, peopleGroupCreateBody, peopleOrgDirectBody, peopleGroupUpdateBody, peopleGroupInviteBody, peopleOrgErasureBody, peopleGroupLeaveBody, peopleGroupInviteIdParam, peopleGroupIncomingInviteIdParam, peopleGroupMemberParam, peopleThreadKindSchema, peopleThreadMemberSchema, peopleThreadLastMessageSchema, peopleGroupRoleSchema, peopleGroupSummarySchema, peopleThreadSummarySchema, peopleThreadAttachmentSchema, peopleThreadMessageSchema, peopleGroupMemberSchema, peopleGroupSentInviteSchema, peopleGroupIncomingInviteSchema, PEOPLE_REPORT_DETAILS_MAX_LENGTH, peopleReportReasonSchema, reportDetailsSchema, reportFields, peopleReportBody, PEOPLE_MODERATION_NOTE_MAX_LENGTH, ADMIN_PEOPLE_REPORTS_PAGE_MAX, ADMIN_PEOPLE_REPORTS_PAGE_DEFAULT, PEOPLE_SUSPENDED_REASON, peopleModerationActionSchema, moderationNoteSchema, adminPeopleReportListQuery, adminPeopleReportIdParam, adminPeopleMessageRemovalBody, adminPeopleSuspendBody, adminPeopleNoteBody, 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, COMMUNITY_EMAIL_UNSUBSCRIBE_PATH, communityEmailUnsubscribeQuery, 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, COMMUNITY_LESSON_TREE_MAX_BYTES, COMMUNITY_LESSON_LINK_PROTOCOLS, COMMUNITY_LESSON_TREE_TOO_LARGE_REASON, COMMUNITY_LESSON_TREE_TOO_DEEP_REASON, COMMUNITY_LESSON_LINE_PREFIX_TOO_WIDE_REASON, LINK_SCHEME, adminSetGuideHubBody, GUIDE_HUB_INELIGIBLE_REASON;
9680
- var init_chunk_RBKQBA3D = __esm({
9681
- "../../packages/core/dist/chunk-RBKQBA3D.js"() {
9803
+ var init_chunk_XJIPLYNP = __esm({
9804
+ "../../packages/core/dist/chunk-XJIPLYNP.js"() {
9682
9805
  "use strict";
9683
9806
  init_chunk_VORPHGDT();
9684
- init_chunk_2TNXNKRP();
9685
- init_chunk_6O3TITL5();
9807
+ init_chunk_MXDUKZPW();
9808
+ init_chunk_2745FTNX();
9686
9809
  init_chunk_MIWZOSPI();
9687
9810
  init_chunk_3NS3HULK();
9688
9811
  init_chunk_DHPUPI4Y();
@@ -13213,11 +13336,11 @@ var init_chunk_BPDC67ML = __esm({
13213
13336
  var init_contracts = __esm({
13214
13337
  "../../packages/core/dist/contracts/index.js"() {
13215
13338
  "use strict";
13216
- init_chunk_RBKQBA3D();
13339
+ init_chunk_XJIPLYNP();
13217
13340
  init_chunk_VORPHGDT();
13218
- init_chunk_2TNXNKRP();
13219
- init_chunk_6O3TITL5();
13220
- init_chunk_SNA2DXAC();
13341
+ init_chunk_MXDUKZPW();
13342
+ init_chunk_2745FTNX();
13343
+ init_chunk_QT7NKKPO();
13221
13344
  init_chunk_MIWZOSPI();
13222
13345
  init_chunk_LKBSHANA();
13223
13346
  init_chunk_IBL7FANV();
@@ -13255,10 +13378,10 @@ function toDataProxyPath(v1Path) {
13255
13378
  }
13256
13379
  return `${DATA_PROXY_PREFIX}${v1Path.slice(REKOR_V1_PREFIX.length)}`;
13257
13380
  }
13258
- function withOrgSelector(path41, orgId) {
13259
- if (!orgId) return path41;
13260
- const separator = path41.includes("?") ? "&" : "?";
13261
- return `${path41}${separator}${DATA_PROXY_ORG_QUERY_PARAM}=${encodeURIComponent(orgId)}`;
13381
+ function withOrgSelector(path42, orgId) {
13382
+ if (!orgId) return path42;
13383
+ const separator = path42.includes("?") ? "&" : "?";
13384
+ return `${path42}${separator}${DATA_PROXY_ORG_QUERY_PARAM}=${encodeURIComponent(orgId)}`;
13262
13385
  }
13263
13386
  function dataErrorMessage(err) {
13264
13387
  if (!(err instanceof ApiError)) return null;
@@ -13282,7 +13405,7 @@ var init_api_client = __esm({
13282
13405
  init_sentry();
13283
13406
  init_mask_secrets();
13284
13407
  RETRYABLE_BACKOFF_MS = [500, 1e3, 2e3];
13285
- delay = (ms) => new Promise((resolve12) => setTimeout(resolve12, ms));
13408
+ delay = (ms) => new Promise((resolve13) => setTimeout(resolve13, ms));
13286
13409
  courseAuthoring = (communityId, courseId) => `/api/communities/${encodeURIComponent(communityId)}/authoring/courses${courseId === void 0 ? "" : `/${encodeURIComponent(courseId)}`}`;
13287
13410
  ApiError = class extends Error {
13288
13411
  status;
@@ -13293,13 +13416,13 @@ var init_api_client = __esm({
13293
13416
  * telling them apart by body shape misreads one for the other.
13294
13417
  */
13295
13418
  path;
13296
- constructor(method, path41, status, body) {
13419
+ constructor(method, path42, status, body) {
13297
13420
  const safeBody = maskSecretsInMessage(body);
13298
- super(`API request failed: ${method} ${path41} (${status}): ${safeBody}`);
13421
+ super(`API request failed: ${method} ${path42} (${status}): ${safeBody}`);
13299
13422
  this.name = "ApiError";
13300
13423
  this.status = status;
13301
13424
  this.body = safeBody;
13302
- this.path = path41;
13425
+ this.path = path42;
13303
13426
  }
13304
13427
  /** True when the status code is a 4xx client error (expected user-facing condition, not a bug). */
13305
13428
  get isExpected() {
@@ -13508,8 +13631,8 @@ var init_api_client = __esm({
13508
13631
  ...opts?.check && { check: true }
13509
13632
  });
13510
13633
  }
13511
- async lookup(path41, opts) {
13512
- const params = new URLSearchParams({ path: path41 });
13634
+ async lookup(path42, opts) {
13635
+ const params = new URLSearchParams({ path: path42 });
13513
13636
  if (opts?.organizationId) params.set("organization_id", opts.organizationId);
13514
13637
  return this.request("GET", `/api/ci/lookup?${params.toString()}`);
13515
13638
  }
@@ -14050,9 +14173,9 @@ var init_api_client = __esm({
14050
14173
  `/api/admin/data-explorer/debug/observability/${encodeURIComponent(hubId)}/conversations/${encodeURIComponent(conversationId)}${qs}`
14051
14174
  );
14052
14175
  }
14053
- async request(method, path41, body, extraHeaders, contentType) {
14054
- addApiBreadcrumb(method, path41);
14055
- const url = `${this.apiUrl}${path41}`;
14176
+ async request(method, path42, body, extraHeaders, contentType) {
14177
+ addApiBreadcrumb(method, path42);
14178
+ const url = `${this.apiUrl}${path42}`;
14056
14179
  let refreshedOn401 = false;
14057
14180
  for (let retry = 0; ; retry++) {
14058
14181
  let response = await this.send(url, method, body, extraHeaders, contentType);
@@ -14077,7 +14200,7 @@ var init_api_client = __esm({
14077
14200
  await delay(RETRYABLE_BACKOFF_MS[retry]);
14078
14201
  continue;
14079
14202
  }
14080
- throw new ApiError(method, path41, response.status, errorBody);
14203
+ throw new ApiError(method, path42, response.status, errorBody);
14081
14204
  }
14082
14205
  }
14083
14206
  /**
@@ -14104,12 +14227,17 @@ var init_api_client = __esm({
14104
14227
  * It travels as the proxy's own query param, whose name is imported rather
14105
14228
  * than spelled — the handler validates it and strips it before forwarding,
14106
14229
  * since it is WayAI's selector and not an input Rekor sees.
14230
+ *
14231
+ * `extraHeaders` carries the surface's own request headers — a file delete's
14232
+ * `If-Match` — under the same rule as `dataUpload`'s: caller-supplied, so
14233
+ * nothing `send` pins can be displaced by them.
14107
14234
  */
14108
- async dataRequest(method, v1Path, body, orgId) {
14235
+ async dataRequest(method, v1Path, body, orgId, extraHeaders) {
14109
14236
  const envelope = await this.request(
14110
14237
  method,
14111
14238
  withOrgSelector(toDataProxyPath(v1Path), orgId),
14112
- body
14239
+ body,
14240
+ extraHeaders
14113
14241
  );
14114
14242
  return envelope ?? {};
14115
14243
  }
@@ -14139,9 +14267,9 @@ var init_api_client = __esm({
14139
14267
  * transient-retry loop — re-streaming a blob is not worth a cold-start probe.
14140
14268
  */
14141
14269
  async dataDownload(v1Path, orgId) {
14142
- const path41 = withOrgSelector(toDataProxyPath(v1Path), orgId);
14143
- addApiBreadcrumb("GET", path41);
14144
- const url = `${this.apiUrl}${path41}`;
14270
+ const path42 = withOrgSelector(toDataProxyPath(v1Path), orgId);
14271
+ addApiBreadcrumb("GET", path42);
14272
+ const url = `${this.apiUrl}${path42}`;
14145
14273
  let response = await this.send(url, "GET");
14146
14274
  if (response.status === 401 && this.onUnauthorized) {
14147
14275
  let refreshed;
@@ -14155,7 +14283,7 @@ var init_api_client = __esm({
14155
14283
  }
14156
14284
  }
14157
14285
  if (!response.ok) {
14158
- throw new ApiError("GET", path41, response.status, await response.text());
14286
+ throw new ApiError("GET", path42, response.status, await response.text());
14159
14287
  }
14160
14288
  return {
14161
14289
  bytes: new Uint8Array(await response.arrayBuffer()),
@@ -14349,6 +14477,32 @@ var init_chunk_BF4WRSOQ = __esm({
14349
14477
  });
14350
14478
 
14351
14479
  // ../../packages/core/dist/index.js
14480
+ function matchPath(pattern, path42) {
14481
+ const normalizedPath = path42.replace(/\/$/, "");
14482
+ if (pattern.endsWith("/*")) {
14483
+ const prefix = pattern.slice(0, -2);
14484
+ return normalizedPath === prefix || normalizedPath.startsWith(prefix + "/");
14485
+ }
14486
+ return pattern === normalizedPath;
14487
+ }
14488
+ function getEndpointConfig(path42) {
14489
+ for (const excluded of EXCLUDED_PATHS) {
14490
+ if (matchPath(excluded, path42)) {
14491
+ return null;
14492
+ }
14493
+ }
14494
+ const normalizedPath = path42.replace(/\/$/, "");
14495
+ if (!normalizedPath.endsWith("/*") && Object.prototype.hasOwnProperty.call(ENDPOINT_CONFIGS, normalizedPath)) {
14496
+ return ENDPOINT_CONFIGS[normalizedPath];
14497
+ }
14498
+ const sortedPatterns = Object.keys(ENDPOINT_CONFIGS).sort((a, b) => b.length - a.length);
14499
+ for (const pattern of sortedPatterns) {
14500
+ if (matchPath(pattern, path42)) {
14501
+ return ENDPOINT_CONFIGS[pattern];
14502
+ }
14503
+ }
14504
+ return { tier: "STANDARD" };
14505
+ }
14352
14506
  function bytesToUuid(bytes) {
14353
14507
  const hex = [];
14354
14508
  for (let i = 0; i < 16; i++) hex.push(bytes[i].toString(16).padStart(2, "0"));
@@ -14396,16 +14550,16 @@ function markdownToPlainText(text) {
14396
14550
  result = result.replace(/^[-*_]{3,}$/gm, "");
14397
14551
  return result;
14398
14552
  }
14399
- var ENDPOINT_CONFIGS, UUID_RE2, WAYAI_WORKSPACE_LAYOUT;
14553
+ var ENDPOINT_CONFIGS, EXCLUDED_PATHS, UUID_RE2, WAYAI_WORKSPACE_LAYOUT;
14400
14554
  var init_dist = __esm({
14401
14555
  "../../packages/core/dist/index.js"() {
14402
14556
  "use strict";
14403
14557
  init_chunk_P3AWZG3N();
14404
- init_chunk_RBKQBA3D();
14558
+ init_chunk_XJIPLYNP();
14405
14559
  init_chunk_VORPHGDT();
14406
- init_chunk_2TNXNKRP();
14407
- init_chunk_6O3TITL5();
14408
- init_chunk_SNA2DXAC();
14560
+ init_chunk_MXDUKZPW();
14561
+ init_chunk_2745FTNX();
14562
+ init_chunk_QT7NKKPO();
14409
14563
  init_chunk_MIWZOSPI();
14410
14564
  init_chunk_LKBSHANA();
14411
14565
  init_chunk_IBL7FANV();
@@ -14879,6 +15033,7 @@ var init_dist = __esm({
14879
15033
  "/api/auth/session-check": { tier: "STANDARD", userLimit: 120, skipAuthenticatedUsers: true },
14880
15034
  "/api/auth/logout": { tier: "MODERATE", userLimit: 10, failClosed: true, skipAuthenticatedUsers: true }
14881
15035
  };
15036
+ EXCLUDED_PATHS = /* @__PURE__ */ new Set(["/health"]);
14882
15037
  UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
14883
15038
  WAYAI_WORKSPACE_LAYOUT = {
14884
15039
  /** Product-namespaced root dir at the git root. */
@@ -15660,13 +15815,13 @@ function resolve3(gitRoot) {
15660
15815
  }
15661
15816
  return { kind: "none" };
15662
15817
  }
15663
- function conflictMessage(manifestOrg, rootOrg, remedy = RECONCILE_REMEDY) {
15818
+ function conflictMessage(manifestOrg, rootOrg, remedy2 = RECONCILE_REMEDY) {
15664
15819
  return [
15665
15820
  "Refusing to guess the organization: two files in this repo name different ones.",
15666
15821
  ` ${WORKSPACE_MANIFEST_LABEL} -> ${manifestOrg} (the workspace manifest)`,
15667
15822
  ` ${ROOT_CONFIG_FILE} -> ${rootOrg} (deprecated fallback)`,
15668
15823
  "",
15669
- ...remedy
15824
+ ...remedy2
15670
15825
  ].join("\n");
15671
15826
  }
15672
15827
  function rebindRefusal(requestedOrg, rootOrg) {
@@ -15848,24 +16003,24 @@ import * as path6 from "path";
15848
16003
  import * as readline from "readline";
15849
16004
  function prompt(question) {
15850
16005
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
15851
- return new Promise((resolve12) => {
16006
+ return new Promise((resolve13) => {
15852
16007
  rl.question(question, (answer) => {
15853
16008
  rl.close();
15854
- resolve12(answer.trim());
16009
+ resolve13(answer.trim());
15855
16010
  });
15856
16011
  });
15857
16012
  }
15858
16013
  function confirm(question) {
15859
16014
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
15860
- return new Promise((resolve12) => {
16015
+ return new Promise((resolve13) => {
15861
16016
  rl.question(`${question} [y/N]: `, (answer) => {
15862
16017
  rl.close();
15863
- resolve12(answer.trim().toLowerCase() === "y");
16018
+ resolve13(answer.trim().toLowerCase() === "y");
15864
16019
  });
15865
16020
  });
15866
16021
  }
15867
16022
  function promptSecret(question) {
15868
- return new Promise((resolve12) => {
16023
+ return new Promise((resolve13) => {
15869
16024
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
15870
16025
  const originalWrite = rl._writeToOutput;
15871
16026
  let firstWrite = true;
@@ -15881,18 +16036,18 @@ function promptSecret(question) {
15881
16036
  rl._writeToOutput = originalWrite;
15882
16037
  process.stdout.write("\n");
15883
16038
  rl.close();
15884
- resolve12(answer);
16039
+ resolve13(answer);
15885
16040
  });
15886
16041
  });
15887
16042
  }
15888
16043
  function readStdin() {
15889
- return new Promise((resolve12, reject) => {
16044
+ return new Promise((resolve13, reject) => {
15890
16045
  let data = "";
15891
16046
  process.stdin.setEncoding("utf-8");
15892
16047
  process.stdin.on("data", (chunk) => {
15893
16048
  data += chunk;
15894
16049
  });
15895
- process.stdin.on("end", () => resolve12(data.trim()));
16050
+ process.stdin.on("end", () => resolve13(data.trim()));
15896
16051
  process.stdin.on("error", reject);
15897
16052
  });
15898
16053
  }
@@ -16607,9 +16762,9 @@ function getVersionCachePath(filename = CLI_CACHE_FILE) {
16607
16762
  }
16608
16763
  function readVersionCache(filename = CLI_CACHE_FILE) {
16609
16764
  try {
16610
- const path41 = getVersionCachePath(filename);
16611
- if (!existsSync3(path41)) return null;
16612
- const parsed = JSON.parse(readFileSync5(path41, "utf-8"));
16765
+ const path42 = getVersionCachePath(filename);
16766
+ if (!existsSync3(path42)) return null;
16767
+ const parsed = JSON.parse(readFileSync5(path42, "utf-8"));
16613
16768
  if (typeof parsed.lastCheck !== "number") return null;
16614
16769
  if (parsed.latest !== null && typeof parsed.latest !== "string") return null;
16615
16770
  return parsed;
@@ -16629,10 +16784,10 @@ function isVersionCacheStale(filename = CLI_CACHE_FILE, maxAgeMs = MAX_AGE_24H_M
16629
16784
  return Date.now() - cache.lastCheck > maxAgeMs;
16630
16785
  }
16631
16786
  function writeVersionCache(filename, cache) {
16632
- const path41 = getVersionCachePath(filename);
16633
- const dir = dirname6(path41);
16787
+ const path42 = getVersionCachePath(filename);
16788
+ const dir = dirname6(path42);
16634
16789
  if (!existsSync3(dir)) mkdirSync2(dir, { recursive: true });
16635
- writeFileSync2(path41, JSON.stringify(cache));
16790
+ writeFileSync2(path42, JSON.stringify(cache));
16636
16791
  }
16637
16792
  function touchVersionCache(filename) {
16638
16793
  writeVersionCache(filename, { lastCheck: Date.now(), latest: readVersionCache(filename)?.latest ?? null });
@@ -16671,14 +16826,14 @@ function parseFrontmatterVersion(content) {
16671
16826
  function findInstalledSkills(projectRoot, paths = SKILL_INSTALL_PATHS) {
16672
16827
  const found = [];
16673
16828
  for (const rel of paths) {
16674
- const path41 = join8(projectRoot, rel);
16675
- if (!existsSync4(path41)) continue;
16829
+ const path42 = join8(projectRoot, rel);
16830
+ if (!existsSync4(path42)) continue;
16676
16831
  let version = null;
16677
16832
  try {
16678
- version = parseFrontmatterVersion(readFileSync6(path41, "utf-8"));
16833
+ version = parseFrontmatterVersion(readFileSync6(path42, "utf-8"));
16679
16834
  } catch {
16680
16835
  }
16681
- found.push({ path: path41, version });
16836
+ found.push({ path: path42, version });
16682
16837
  }
16683
16838
  return found;
16684
16839
  }
@@ -17132,7 +17287,7 @@ async function validateToken(apiUrl, token) {
17132
17287
  }
17133
17288
  }
17134
17289
  function startCallbackServer(port, expectedState, timeoutMs = 12e4) {
17135
- return new Promise((resolve12, reject) => {
17290
+ return new Promise((resolve13, reject) => {
17136
17291
  const server = http.createServer((req, res) => {
17137
17292
  const url = new URL(req.url || "/", `http://127.0.0.1:${port}`);
17138
17293
  if (url.pathname === "/callback") {
@@ -17158,7 +17313,7 @@ function startCallbackServer(port, expectedState, timeoutMs = 12e4) {
17158
17313
  res.writeHead(200, { "Content-Type": "text/html" });
17159
17314
  res.end("<html><body><h2>Login successful!</h2><p>You can close this tab and return to your terminal.</p></body></html>");
17160
17315
  server.close();
17161
- resolve12({ code, port });
17316
+ resolve13({ code, port });
17162
17317
  } else {
17163
17318
  res.writeHead(400, { "Content-Type": "text/html" });
17164
17319
  res.end("<html><body><h2>Login failed</h2><p>No authorization code received</p></body></html>");
@@ -17370,10 +17525,10 @@ import * as readline2 from "readline";
17370
17525
  function prompt2(question, defaultValue) {
17371
17526
  const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
17372
17527
  const display = defaultValue ? `${question} [${defaultValue}]: ` : `${question}: `;
17373
- return new Promise((resolve12) => {
17528
+ return new Promise((resolve13) => {
17374
17529
  rl.question(display, (answer) => {
17375
17530
  rl.close();
17376
- resolve12(answer.trim() || defaultValue || "");
17531
+ resolve13(answer.trim() || defaultValue || "");
17377
17532
  });
17378
17533
  });
17379
17534
  }
@@ -17501,8 +17656,8 @@ async function tryOpenBrowser(url) {
17501
17656
  cmd = "xdg-open";
17502
17657
  args2 = [url];
17503
17658
  }
17504
- return new Promise((resolve12) => {
17505
- execFile(cmd, args2, (err) => resolve12(!err));
17659
+ return new Promise((resolve13) => {
17660
+ execFile(cmd, args2, (err) => resolve13(!err));
17506
17661
  });
17507
17662
  } catch {
17508
17663
  return false;
@@ -18452,17 +18607,17 @@ function writeResourceFileTree(resDir, files, root, log) {
18452
18607
  }
18453
18608
  const writtenPaths = /* @__PURE__ */ new Set();
18454
18609
  for (const file of files) {
18455
- const filePath = path12.join(resDir, file.path);
18456
- if (!filePath.startsWith(resDir + path12.sep) && filePath !== resDir) {
18610
+ const filePath2 = path12.join(resDir, file.path);
18611
+ if (!filePath2.startsWith(resDir + path12.sep) && filePath2 !== resDir) {
18457
18612
  console.warn(` Warning: skipping ${file.path} (path traversal detected)`);
18458
18613
  continue;
18459
18614
  }
18460
18615
  writtenPaths.add(file.path);
18461
18616
  const buf = file.content !== void 0 ? Buffer.from(file.content, "utf-8") : file.content_base64 ? Buffer.from(file.content_base64, "base64") : void 0;
18462
18617
  if (buf === void 0) continue;
18463
- if (fileHasBytes(filePath, buf)) continue;
18464
- if (writeFileNoFollow(resDir, filePath, buf)) {
18465
- log?.changed.push(path12.relative(root, filePath));
18618
+ if (fileHasBytes(filePath2, buf)) continue;
18619
+ if (writeFileNoFollow(resDir, filePath2, buf)) {
18620
+ log?.changed.push(path12.relative(root, filePath2));
18466
18621
  } else {
18467
18622
  console.warn(` Warning: skipping ${file.path} (destination escapes the resource folder via a symlink)`);
18468
18623
  writtenPaths.delete(file.path);
@@ -18493,15 +18648,15 @@ async function downloadBinaryFiles(resDir, files, root, log) {
18493
18648
  for (const file of files) {
18494
18649
  if (!file.download_url || file.content !== void 0) continue;
18495
18650
  try {
18496
- const filePath = path12.join(resDir, file.path);
18497
- if (!filePath.startsWith(resDir + path12.sep) && filePath !== resDir) {
18651
+ const filePath2 = path12.join(resDir, file.path);
18652
+ if (!filePath2.startsWith(resDir + path12.sep) && filePath2 !== resDir) {
18498
18653
  console.warn(` Warning: skipping ${file.path} (path traversal detected)`);
18499
18654
  continue;
18500
18655
  }
18501
18656
  if (file.hash) {
18502
18657
  try {
18503
- const st = fs10.lstatSync(filePath);
18504
- if (st.isFile() && !st.isSymbolicLink() && computeHash(fs10.readFileSync(filePath)) === file.hash) continue;
18658
+ const st = fs10.lstatSync(filePath2);
18659
+ if (st.isFile() && !st.isSymbolicLink() && computeHash(fs10.readFileSync(filePath2)) === file.hash) continue;
18505
18660
  } catch {
18506
18661
  }
18507
18662
  }
@@ -18511,10 +18666,10 @@ async function downloadBinaryFiles(resDir, files, root, log) {
18511
18666
  continue;
18512
18667
  }
18513
18668
  const buffer = Buffer.from(await response.arrayBuffer());
18514
- if (fileHasBytes(filePath, buffer)) continue;
18515
- if (writeFileNoFollow(resDir, filePath, buffer)) {
18669
+ if (fileHasBytes(filePath2, buffer)) continue;
18670
+ if (writeFileNoFollow(resDir, filePath2, buffer)) {
18516
18671
  count++;
18517
- log?.changed.push(path12.relative(root, filePath));
18672
+ log?.changed.push(path12.relative(root, filePath2));
18518
18673
  } else {
18519
18674
  console.warn(` Warning: skipping ${file.path} (destination escapes the resource folder via a symlink)`);
18520
18675
  }
@@ -19016,8 +19171,8 @@ function scanEvalYamlFiles(hubFolder, bytesByHash, unreadable) {
19016
19171
  }
19017
19172
  return evals;
19018
19173
  }
19019
- function collectEval(evals, seen, filePath, relPath, setName, hubFolder, bytesByHash, unreadable) {
19020
- const evalEntry = parseEvalYaml(filePath, relPath, setName, hubFolder, bytesByHash);
19174
+ function collectEval(evals, seen, filePath2, relPath, setName, hubFolder, bytesByHash, unreadable) {
19175
+ const evalEntry = parseEvalYaml(filePath2, relPath, setName, hubFolder, bytesByHash);
19021
19176
  if (!evalEntry) {
19022
19177
  unreadable(relPath, NOT_A_YAML_OBJECT);
19023
19178
  return;
@@ -19026,14 +19181,14 @@ function collectEval(evals, seen, filePath, relPath, setName, hubFolder, bytesBy
19026
19181
  if (seen.has(key)) {
19027
19182
  const where = setName ? `scenario set "${setName}"` : "root";
19028
19183
  throw expected(
19029
- `Duplicate eval at ${where}: "${evalEntry.name}" (in ${path15.basename(filePath)}). Each (name, scenario set) pair must be unique.`
19184
+ `Duplicate eval at ${where}: "${evalEntry.name}" (in ${path15.basename(filePath2)}). Each (name, scenario set) pair must be unique.`
19030
19185
  );
19031
19186
  }
19032
19187
  seen.add(key);
19033
19188
  evals.push(evalEntry);
19034
19189
  }
19035
- function parseEvalYaml(filePath, relPath, setName, hubFolder, bytesByHash) {
19036
- const content = fs13.readFileSync(filePath, "utf-8");
19190
+ function parseEvalYaml(filePath2, relPath, setName, hubFolder, bytesByHash) {
19191
+ const content = fs13.readFileSync(filePath2, "utf-8");
19037
19192
  let raw;
19038
19193
  try {
19039
19194
  raw = yaml7.load(content);
@@ -19045,7 +19200,7 @@ function parseEvalYaml(filePath, relPath, setName, hubFolder, bytesByHash) {
19045
19200
  }
19046
19201
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
19047
19202
  const data = raw;
19048
- const fileSlug = path15.basename(filePath, ".yaml");
19203
+ const fileSlug = path15.basename(filePath2, ".yaml");
19049
19204
  const evalName = typeof data.name === "string" && data.name.trim().length > 0 ? data.name : fileSlug;
19050
19205
  if (typeof data.agent !== "string" || data.agent.trim().length === 0) {
19051
19206
  throw expected(`Eval "${evalName}" in ${relPath}: missing required field "agent" (string).`);
@@ -19160,8 +19315,8 @@ function scanJourneyYamlFiles(hubFolder, bytesByHash, unreadable) {
19160
19315
  }
19161
19316
  return journeys;
19162
19317
  }
19163
- function parseJourneyYaml(filePath, relPath, hubFolder, bytesByHash) {
19164
- const content = fs13.readFileSync(filePath, "utf-8");
19318
+ function parseJourneyYaml(filePath2, relPath, hubFolder, bytesByHash) {
19319
+ const content = fs13.readFileSync(filePath2, "utf-8");
19165
19320
  let raw;
19166
19321
  try {
19167
19322
  raw = yaml7.load(content);
@@ -19173,7 +19328,7 @@ function parseJourneyYaml(filePath, relPath, hubFolder, bytesByHash) {
19173
19328
  }
19174
19329
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
19175
19330
  const data = raw;
19176
- const fileSlug = path15.basename(filePath, ".yaml");
19331
+ const fileSlug = path15.basename(filePath2, ".yaml");
19177
19332
  const journeyName = typeof data.name === "string" && data.name.trim().length > 0 ? data.name : fileSlug;
19178
19333
  if (typeof data.agent !== "string" || data.agent.trim().length === 0) {
19179
19334
  throw expected(`Journey "${journeyName}" in ${relPath}: missing required field "agent" (string).`);
@@ -19219,8 +19374,8 @@ function scanAgentYamlFiles(hubFolder, unreadable) {
19219
19374
  if (yamlFiles.length === 0) return [];
19220
19375
  const agents = [];
19221
19376
  for (const file of yamlFiles) {
19222
- const filePath = path15.join(agentsDir, file);
19223
- const content = readRealFileOrThrow(hubFolder, filePath) ?? "";
19377
+ const filePath2 = path15.join(agentsDir, file);
19378
+ const content = readRealFileOrThrow(hubFolder, filePath2) ?? "";
19224
19379
  let agent;
19225
19380
  try {
19226
19381
  agent = yaml7.load(content);
@@ -19325,8 +19480,8 @@ function perHubAgentsMd(hubFolderName) {
19325
19480
  ""
19326
19481
  ].join("\n");
19327
19482
  }
19328
- function writeIfAbsent(root, filePath, content) {
19329
- return createFileNoFollow(root, filePath, Buffer.from(content, "utf-8")) === "created" ? path16.basename(filePath) : null;
19483
+ function writeIfAbsent(root, filePath2, content) {
19484
+ return createFileNoFollow(root, filePath2, Buffer.from(content, "utf-8")) === "created" ? path16.basename(filePath2) : null;
19330
19485
  }
19331
19486
  var init_workspace_files = __esm({
19332
19487
  "src/lib/workspace-files.ts"() {
@@ -20156,12 +20311,12 @@ async function createDataClient(orgId) {
20156
20311
  return orgId2;
20157
20312
  }
20158
20313
  return {
20159
- async request(method, path41, body) {
20160
- const envelope = await api.dataRequest(method, path41, body, org);
20314
+ async request(method, path42, body, headers) {
20315
+ const envelope = await api.dataRequest(method, path42, body, org, headers);
20161
20316
  return envelope.data;
20162
20317
  },
20163
- async requestRaw(method, path41, body) {
20164
- const body_ = await api.dataRequest(method, path41, body, org);
20318
+ async requestRaw(method, path42, body) {
20319
+ const body_ = await api.dataRequest(method, path42, body, org);
20165
20320
  return body_;
20166
20321
  },
20167
20322
  async collectPages(makePath) {
@@ -21060,8 +21215,8 @@ function installEvalSignalHandlers(input) {
21060
21215
  let signalCount = 0;
21061
21216
  let disposed = false;
21062
21217
  let settle;
21063
- const settled = new Promise((resolve12) => {
21064
- settle = resolve12;
21218
+ const settled = new Promise((resolve13) => {
21219
+ settle = resolve13;
21065
21220
  });
21066
21221
  const listeners = /* @__PURE__ */ new Map();
21067
21222
  const dispose = () => {
@@ -21199,7 +21354,7 @@ var init_pacer = __esm({
21199
21354
  WINDOW_MS = 6e4;
21200
21355
  DEFAULT_RETRY_AFTER_SECONDS = 60;
21201
21356
  MAX_RATE_LIMITED_RETRIES = 5;
21202
- realSleep = (ms) => new Promise((resolve12) => setTimeout(resolve12, ms));
21357
+ realSleep = (ms) => new Promise((resolve13) => setTimeout(resolve13, ms));
21203
21358
  Pacer = class {
21204
21359
  perMinute;
21205
21360
  now;
@@ -21313,11 +21468,11 @@ function classify(base, file, server) {
21313
21468
  if (known === void 0) return file === server ? "converged" : "conflict";
21314
21469
  return threeWay(file !== known, server !== known, file === server);
21315
21470
  }
21316
- function threeWay(fileChanged, serverChanged, agree) {
21471
+ function threeWay(fileChanged, serverChanged, agree2) {
21317
21472
  if (!fileChanged && !serverChanged) return "in_sync";
21318
21473
  if (!serverChanged) return "local";
21319
21474
  if (!fileChanged) return "remote";
21320
- return agree ? "converged" : "conflict";
21475
+ return agree2 ? "converged" : "conflict";
21321
21476
  }
21322
21477
  function createClientId(communityId, kind, localName2) {
21323
21478
  return uuidV5(communityId, `${kind}:${localName2}`);
@@ -21943,8 +22098,12 @@ var init_files = __esm({
21943
22098
 
21944
22099
  // src/communities/listing.ts
21945
22100
  function lineDiff(from, to) {
21946
- const a = from ? sanitizeTerminalText(from).split("\n") : [];
21947
- const b = to ? sanitizeTerminalText(to).split("\n") : [];
22101
+ return lineDiffOf(
22102
+ from ? sanitizeTerminalText(from).split("\n") : [],
22103
+ to ? sanitizeTerminalText(to).split("\n") : []
22104
+ );
22105
+ }
22106
+ function lineDiffOf(a, b) {
21948
22107
  if (a.length * b.length > 25e4) return [...a.map((l) => `- ${l}`), ...b.map((l) => `+ ${l}`)];
21949
22108
  const lcs = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
21950
22109
  for (let i2 = a.length - 1; i2 >= 0; i2--) {
@@ -25540,26 +25699,26 @@ __export(send_message_exports, {
25540
25699
  });
25541
25700
  import * as fs25 from "fs";
25542
25701
  import * as path36 from "path";
25543
- function statAttachment(filePath) {
25702
+ function statAttachment(filePath2) {
25544
25703
  let stat2;
25545
25704
  try {
25546
- stat2 = fs25.statSync(filePath);
25705
+ stat2 = fs25.statSync(filePath2);
25547
25706
  } catch {
25548
- console.error(`Error: file not found: ${filePath}`);
25707
+ console.error(`Error: file not found: ${filePath2}`);
25549
25708
  process.exit(1);
25550
25709
  }
25551
25710
  if (stat2.isDirectory()) {
25552
- console.error(`Error: not a file: ${filePath}`);
25711
+ console.error(`Error: not a file: ${filePath2}`);
25553
25712
  process.exit(1);
25554
25713
  }
25555
- return { filePath, size: stat2.size };
25714
+ return { filePath: filePath2, size: stat2.size };
25556
25715
  }
25557
- function readAttachment(filePath, size) {
25558
- const fileName = path36.basename(filePath);
25716
+ function readAttachment(filePath2, size) {
25717
+ const fileName = path36.basename(filePath2);
25559
25718
  const ext = path36.extname(fileName).replace(/^\./, "");
25560
25719
  return {
25561
25720
  file_name: fileName,
25562
- file_binary: fs25.readFileSync(filePath).toString("base64"),
25721
+ file_binary: fs25.readFileSync(filePath2).toString("base64"),
25563
25722
  file_size: size,
25564
25723
  ...ext && { file_extension: ext }
25565
25724
  };
@@ -25589,12 +25748,12 @@ async function sendMessageCommand(args2) {
25589
25748
  if (arg === "-c" || arg === "--conversation") {
25590
25749
  conversationId = args2[++i];
25591
25750
  } else if (arg === "-f" || arg === "--file") {
25592
- const filePath = args2[++i];
25593
- if (!filePath) {
25751
+ const filePath2 = args2[++i];
25752
+ if (!filePath2) {
25594
25753
  console.error("Error: --file requires a path");
25595
25754
  process.exit(1);
25596
25755
  }
25597
- filePaths.push(filePath);
25756
+ filePaths.push(filePath2);
25598
25757
  } else if (!arg.startsWith("-")) {
25599
25758
  message = arg;
25600
25759
  }
@@ -27384,7 +27543,7 @@ Timeout after ${timeoutSeconds}s${queuedSeconds > 0 ? ` (${queuedSeconds}s of it
27384
27543
  process.exit(1);
27385
27544
  }
27386
27545
  function sleep(ms) {
27387
- return new Promise((resolve12) => setTimeout(resolve12, ms));
27546
+ return new Promise((resolve13) => setTimeout(resolve13, ms));
27388
27547
  }
27389
27548
  function parseRunNumbers(raw) {
27390
27549
  if (!raw || raw.startsWith("--")) {
@@ -27741,15 +27900,15 @@ var init_caller_audio = __esm({
27741
27900
  }
27742
27901
  describe;
27743
27902
  async clipFor(line) {
27744
- const path41 = line.clip ? isAbsolute2(line.clip) ? line.clip : resolve10(this.planDir, line.clip) : this.dir ? join31(this.dir, `${line.n}.wav`) : null;
27745
- if (!path41) throw new Error(`Line ${line.n} has no clip: give --clips <dir>, or a "clip" for it in the plan.`);
27903
+ const path42 = line.clip ? isAbsolute2(line.clip) ? line.clip : resolve10(this.planDir, line.clip) : this.dir ? join31(this.dir, `${line.n}.wav`) : null;
27904
+ if (!path42) throw new Error(`Line ${line.n} has no clip: give --clips <dir>, or a "clip" for it in the plan.`);
27746
27905
  let buf;
27747
27906
  try {
27748
- buf = readFileSync17(path41);
27907
+ buf = readFileSync17(path42);
27749
27908
  } catch {
27750
- throw new Error(`Line ${line.n}'s clip ${path41} cannot be read.`);
27909
+ throw new Error(`Line ${line.n}'s clip ${path42} cannot be read.`);
27751
27910
  }
27752
- return parseWav(buf, path41);
27911
+ return parseWav(buf, path42);
27753
27912
  }
27754
27913
  };
27755
27914
  OPENAI_PCM_SAMPLE_RATE = 24e3;
@@ -27779,17 +27938,17 @@ ${text}`).digest("hex");
27779
27938
  return join31(this.cacheDir, `${key}.pcm`);
27780
27939
  }
27781
27940
  clipFor(line) {
27782
- const path41 = this.cachePath(line.say);
27783
- let pending = this.inFlight.get(path41);
27941
+ const path42 = this.cachePath(line.say);
27942
+ let pending = this.inFlight.get(path42);
27784
27943
  if (!pending) {
27785
- pending = this.readOrSynthesize(line, path41);
27786
- this.inFlight.set(path41, pending);
27944
+ pending = this.readOrSynthesize(line, path42);
27945
+ this.inFlight.set(path42, pending);
27787
27946
  }
27788
27947
  return pending;
27789
27948
  }
27790
- async readOrSynthesize(line, path41) {
27949
+ async readOrSynthesize(line, path42) {
27791
27950
  try {
27792
- return pcmClip(readFileSync17(path41));
27951
+ return pcmClip(readFileSync17(path42));
27793
27952
  } catch {
27794
27953
  }
27795
27954
  const res = await this.doFetch("https://api.openai.com/v1/audio/speech", {
@@ -27803,10 +27962,10 @@ ${text}`).digest("hex");
27803
27962
  }
27804
27963
  const buf = Buffer.from(await res.arrayBuffer());
27805
27964
  if (buf.length < 2) throw new Error(`OpenAI speech synthesis returned no audio for line ${line.n}.`);
27806
- mkdirSync12(dirname12(path41), { recursive: true });
27807
- const tmp = `${path41}.${process.pid}.tmp`;
27965
+ mkdirSync12(dirname12(path42), { recursive: true });
27966
+ const tmp = `${path42}.${process.pid}.tmp`;
27808
27967
  writeFileSync7(tmp, buf);
27809
- renameSync5(tmp, path41);
27968
+ renameSync5(tmp, path42);
27810
27969
  return pcmClip(buf);
27811
27970
  }
27812
27971
  };
@@ -27833,14 +27992,14 @@ async function loadWrtcRuntime(importPackage = () => import(WRTC_PACKAGE)) {
27833
27992
  function waitFor(ready, timeoutMs, clock = systemClock) {
27834
27993
  if (ready()) return Promise.resolve(true);
27835
27994
  const deadline = clock.now() + timeoutMs;
27836
- return new Promise((resolve12) => {
27995
+ return new Promise((resolve13) => {
27837
27996
  const timer = setInterval(() => {
27838
27997
  if (ready()) {
27839
27998
  clearInterval(timer);
27840
- resolve12(true);
27999
+ resolve13(true);
27841
28000
  } else if (clock.now() >= deadline) {
27842
28001
  clearInterval(timer);
27843
- resolve12(false);
28002
+ resolve13(false);
27844
28003
  }
27845
28004
  }, WAIT_POLL_MS);
27846
28005
  });
@@ -27955,8 +28114,8 @@ var init_call_media = __esm({
27955
28114
  * asked before every frame, answers true — the rest of the clip is then dropped.
27956
28115
  */
27957
28116
  play(clip, abort = () => false) {
27958
- return new Promise((resolve12) => {
27959
- this.queue.push({ samples: resample(clip, PUMP_SAMPLE_RATE), offset: 0, startedAtMs: null, abort, resolve: resolve12 });
28117
+ return new Promise((resolve13) => {
28118
+ this.queue.push({ samples: resample(clip, PUMP_SAMPLE_RATE), offset: 0, startedAtMs: null, abort, resolve: resolve13 });
27960
28119
  });
27961
28120
  }
27962
28121
  /** Send every frame the wall clock says is due. */
@@ -29168,7 +29327,7 @@ var init_runner = __esm({
29168
29327
  init_score();
29169
29328
  systemRunnerClock = {
29170
29329
  now: () => Date.now(),
29171
- sleep: (ms) => new Promise((resolve12) => setTimeout(resolve12, ms))
29330
+ sleep: (ms) => new Promise((resolve13) => setTimeout(resolve13, ms))
29172
29331
  };
29173
29332
  LONGEST_SPOKEN_LINE_MS = Math.ceil(EVAL_CALL_SPOKEN_LINE_MAX_CHARS / 15) * 1e3;
29174
29333
  DEFAULT_RUNNER_TIMINGS = {
@@ -29371,15 +29530,15 @@ function parseEvalCallArgs(args2) {
29371
29530
  if (parsed.jsonPath) checkReportPath(parsed.jsonPath);
29372
29531
  return parsed;
29373
29532
  }
29374
- function checkReportPath(path41) {
29375
- const target = resolve11(path41);
29533
+ function checkReportPath(path42) {
29534
+ const target = resolve11(path42);
29376
29535
  const dir = dirname13(target);
29377
- if (!existsSync16(dir) || !statSync8(dir).isDirectory()) fail(`--json ${path41}: the folder ${dir} does not exist.`);
29378
- if (existsSync16(target) && statSync8(target).isDirectory()) fail(`--json ${path41} is a folder; name a file.`);
29536
+ if (!existsSync16(dir) || !statSync8(dir).isDirectory()) fail(`--json ${path42}: the folder ${dir} does not exist.`);
29537
+ if (existsSync16(target) && statSync8(target).isDirectory()) fail(`--json ${path42} is a folder; name a file.`);
29379
29538
  try {
29380
29539
  accessSync(existsSync16(target) ? target : dir, fsConstants.W_OK);
29381
29540
  } catch {
29382
- fail(`--json ${path41} cannot be written here.`);
29541
+ fail(`--json ${path42} cannot be written here.`);
29383
29542
  }
29384
29543
  }
29385
29544
  function suiteExitCode(report2, runs, reportWritten) {
@@ -35454,16 +35613,16 @@ MCP URL: ${toolsetMcpUrl(slug)}`);
35454
35613
  ).option("--force", "Revoke even if the token appears to be in live use").action(async function(tokenId, opts) {
35455
35614
  const client = await createDataClient();
35456
35615
  const id = pathSegment(tokenId, "token id");
35457
- const path41 = (force) => `/v1/tokens/${id}${force ? "?force=true" : ""}`;
35616
+ const path42 = (force) => `/v1/tokens/${id}${force ? "?force=true" : ""}`;
35458
35617
  const format = outputFormat(this);
35459
35618
  const revoked = (forced) => printOutput({ token_id: tokenId, revoked: true, forced }, format);
35460
35619
  if (opts.force) {
35461
- await client.request("DELETE", path41(true));
35620
+ await client.request("DELETE", path42(true));
35462
35621
  revoked(true);
35463
35622
  return;
35464
35623
  }
35465
35624
  try {
35466
- await client.request("DELETE", path41(false));
35625
+ await client.request("DELETE", path42(false));
35467
35626
  revoked(false);
35468
35627
  } catch (err) {
35469
35628
  if (!(err instanceof ApiError) || err.status !== 409 || dataErrorDetails(err)?.requires_force !== true) {
@@ -35478,7 +35637,7 @@ MCP URL: ${toolsetMcpUrl(slug)}`);
35478
35637
  console.error("Aborted.");
35479
35638
  return process.exit(1);
35480
35639
  }
35481
- await client.request("DELETE", path41(true));
35640
+ await client.request("DELETE", path42(true));
35482
35641
  revoked(true);
35483
35642
  }
35484
35643
  });
@@ -35626,9 +35785,9 @@ var init_base_tags = __esm({
35626
35785
 
35627
35786
  // src/data/commands/bases.ts
35628
35787
  import { Command as Command10 } from "commander";
35629
- function pageOf(path41, cursor) {
35630
- if (!cursor) return path41;
35631
- return `${path41}${path41.includes("?") ? "&" : "?"}cursor=${encodeURIComponent(cursor)}`;
35788
+ function pageOf(path42, cursor) {
35789
+ if (!cursor) return path42;
35790
+ return `${path42}${path42.includes("?") ? "&" : "?"}cursor=${encodeURIComponent(cursor)}`;
35632
35791
  }
35633
35792
  function parseEnum(flag, value, allowed) {
35634
35793
  if (value === void 0) return void 0;
@@ -35785,20 +35944,21 @@ function buildBasesCommand() {
35785
35944
  });
35786
35945
  bases.command("list-previews <origin-id>").description("List preview bases cloned from a base (production or preview)").action(async function(originId) {
35787
35946
  const client = await createDataClient();
35788
- const path41 = `/v1/${pathSegment(originId, "origin base id")}/previews`;
35947
+ const path42 = `/v1/${pathSegment(originId, "origin base id")}/previews`;
35789
35948
  printOutput(
35790
- await client.collectPages((cursor) => pageOf(path41, cursor)),
35949
+ await client.collectPages((cursor) => pageOf(path42, cursor)),
35791
35950
  outputFormat(this)
35792
35951
  );
35793
35952
  });
35794
- bases.command("promote <production-id>").description("Promote config from a preview base to production (human-only)").requiredOption("--from <preview-id>", "Source preview base id").option("--dry-run", "Show what would change without applying").option("--record-types <ids>", "Comma-separated record type ids to promote", splitList).option("--triggers <ids>", "Comma-separated trigger ids to promote", splitList).option("--inbound-webhooks <ids>", "Comma-separated inbound webhook ids to promote", splitList).action(async function(productionId, opts) {
35953
+ bases.command("promote <production-id>").description("Promote config from a preview base to production (human-only)").requiredOption("--from <preview-id>", "Source preview base id").option("--dry-run", "Show what would change without applying").option("--record-types <ids>", "Comma-separated record type ids to promote", splitList).option("--triggers <ids>", "Comma-separated trigger ids to promote", splitList).option("--inbound-webhooks <ids>", "Comma-separated inbound webhook ids to promote", splitList).option("--file-types <ids>", "Comma-separated file type ids to promote", splitList).action(async function(productionId, opts) {
35795
35954
  const client = await createDataClient();
35796
35955
  const data = await client.request("POST", `/v1/${pathSegment(productionId, "production base id")}/promote`, {
35797
35956
  source_base_id: opts.from,
35798
35957
  dry_run: opts.dryRun ?? false,
35799
35958
  record_types: opts.recordTypes,
35800
35959
  triggers: opts.triggers,
35801
- inbound_webhooks: opts.inboundWebhooks
35960
+ inbound_webhooks: opts.inboundWebhooks,
35961
+ file_types: opts.fileTypes
35802
35962
  });
35803
35963
  printOutput(data, outputFormat(this));
35804
35964
  const warnings = data?.source_credential_warnings ?? [];
@@ -35834,9 +35994,9 @@ function buildBasesCommand() {
35834
35994
  });
35835
35995
  bases.command("promotions <production-id>").description("List promotion history for a production base").action(async function(productionId) {
35836
35996
  const client = await createDataClient();
35837
- const path41 = `/v1/${pathSegment(productionId, "production base id")}/promotions`;
35997
+ const path42 = `/v1/${pathSegment(productionId, "production base id")}/promotions`;
35838
35998
  printOutput(
35839
- await client.collectPages((cursor) => pageOf(path41, cursor)),
35999
+ await client.collectPages((cursor) => pageOf(path42, cursor)),
35840
36000
  outputFormat(this)
35841
36001
  );
35842
36002
  });
@@ -35972,12 +36132,879 @@ var init_file_types = __esm({
35972
36132
  }
35973
36133
  });
35974
36134
 
36135
+ // src/data/files-sync/headers.ts
36136
+ function ifMatchValue(raw) {
36137
+ const hash = raw.trim().replace(/^W\//, "").replace(/^"(.*)"$/, "$1");
36138
+ if (!/^[\x21\x23-\x7e]+$/.test(hash)) {
36139
+ throw expected(
36140
+ `--if-match must be the file's content hash (its ETag, or content_sha256 from \`wayai files get --meta\`), got ${JSON.stringify(raw)}.`
36141
+ );
36142
+ }
36143
+ return `"${hash}"`;
36144
+ }
36145
+ function labelValue(raw) {
36146
+ if (raw.length === 0 || !/^[\x20-\x7e]+$/.test(raw)) {
36147
+ throw expected(
36148
+ `--label must be printable ASCII text (a request header cannot carry other characters intact), got ${JSON.stringify(raw)}.`
36149
+ );
36150
+ }
36151
+ return raw;
36152
+ }
36153
+ function metadataValue(value) {
36154
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
36155
+ throw expected("--metadata must be a JSON object.");
36156
+ }
36157
+ return JSON.stringify(value).replace(
36158
+ /[\u007f-￿]/g,
36159
+ (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`
36160
+ );
36161
+ }
36162
+ function fileWriteHeaders(opts) {
36163
+ const headers = {};
36164
+ if (opts.ifMatch !== void 0) headers["If-Match"] = ifMatchValue(opts.ifMatch);
36165
+ if (opts.label !== void 0) headers["X-Data-Label"] = labelValue(opts.label);
36166
+ if (opts.metadata !== void 0) headers["X-Data-Metadata"] = metadataValue(opts.metadata);
36167
+ return headers;
36168
+ }
36169
+ var init_headers = __esm({
36170
+ "src/data/files-sync/headers.ts"() {
36171
+ "use strict";
36172
+ init_expected();
36173
+ }
36174
+ });
36175
+
36176
+ // src/data/files-sync/local.ts
36177
+ import * as fs30 from "fs";
36178
+ import * as path41 from "path";
36179
+ function foldSegment(segment) {
36180
+ return segment.normalize("NFC").toLowerCase().replace(/[. ]+$/, "");
36181
+ }
36182
+ function foldPath(rel) {
36183
+ return rel.split("/").map(foldSegment).join("/");
36184
+ }
36185
+ function isOutsideSync(rel) {
36186
+ return rel.split("/").some((segment) => OUTSIDE_SYNC_FOLDED.has(foldSegment(segment)));
36187
+ }
36188
+ function isCleanPath(segments) {
36189
+ return segments.every((s) => s !== "" && s !== "." && s !== ".." && !/[\\\0]/.test(s));
36190
+ }
36191
+ function normalizeFolder(raw) {
36192
+ if (raw === void 0) return "";
36193
+ const folder = raw.replace(/\/+$/, "");
36194
+ if (folder === "") return "";
36195
+ if (folder.startsWith("/") || !isCleanPath(folder.split("/"))) {
36196
+ throw expected(
36197
+ `--folder must be a folder path inside the file type (e.g. hr or hr/benefits), got ${JSON.stringify(raw)}.`
36198
+ );
36199
+ }
36200
+ return folder;
36201
+ }
36202
+ function remotePath(folder, rel) {
36203
+ return folder ? `${folder}/${rel}` : rel;
36204
+ }
36205
+ function defaultDir(fileType, folder) {
36206
+ return path41.join(fileType, ...folder ? folder.split("/") : []);
36207
+ }
36208
+ function describeSync(r) {
36209
+ const where = r.folder ? `folder "${r.folder}"` : "the whole file type";
36210
+ return sanitizeTerminalText(`base "${r.base}", file type "${r.file_type}", ${where}`);
36211
+ }
36212
+ function isWindowsAlias(segment) {
36213
+ if (segment.includes(":")) return true;
36214
+ const dot = segment.lastIndexOf(".");
36215
+ const [stem, ext] = dot > 0 ? [segment.slice(0, dot), segment.slice(dot + 1)] : [segment, ""];
36216
+ return stem.length <= 8 && /~\d+$/.test(stem) && ext.length <= 3;
36217
+ }
36218
+ function assertRepresentable(rels, platform2 = process.platform) {
36219
+ const problems2 = [];
36220
+ const index = new CaseIndex();
36221
+ const all = new Set(rels);
36222
+ for (const rel of rels) {
36223
+ if (!isCleanPath(rel.split("/"))) {
36224
+ problems2.push(`"${rel}" cannot be a local file name`);
36225
+ continue;
36226
+ }
36227
+ if (platform2 === "win32" && rel.split("/").some(isWindowsAlias)) {
36228
+ problems2.push(`"${rel}" cannot be a local file name on Windows`);
36229
+ continue;
36230
+ }
36231
+ const twin = index.twinOf(rel);
36232
+ if (twin !== void 0) problems2.push(`"${twin}" and "${rel}" differ only in case, so they would share one name locally`);
36233
+ index.add(rel);
36234
+ const segments = rel.split("/");
36235
+ for (let i = 1; i < segments.length; i++) {
36236
+ const parent = segments.slice(0, i).join("/");
36237
+ if (all.has(parent)) problems2.push(`"${parent}" is both a file and a folder`);
36238
+ }
36239
+ }
36240
+ if (problems2.length > 0) {
36241
+ throw expected(
36242
+ sanitizeTerminalText(
36243
+ `The base holds paths this folder cannot hold as files, so nothing was pulled:
36244
+ ${problems2.join("\n ")}`
36245
+ )
36246
+ );
36247
+ }
36248
+ }
36249
+ function assertPushable(folder, rels, platform2 = process.platform) {
36250
+ const problems2 = [];
36251
+ for (const rel of rels) {
36252
+ const full = remotePath(folder, rel);
36253
+ if (full !== full.trim()) problems2.push(`"${rel}" starts or ends with a space`);
36254
+ else if (full.length > MAX_REMOTE_PATH) problems2.push(`"${rel}" makes a path longer than ${MAX_REMOTE_PATH} characters`);
36255
+ else if (!isCleanPath(rel.split("/"))) problems2.push(`"${rel}" cannot be a file path on the base`);
36256
+ else if (platform2 === "win32" && rel.split("/").some(isWindowsAlias)) {
36257
+ problems2.push(`"${rel}" cannot be a file name on Windows, where it can stand for another file`);
36258
+ }
36259
+ }
36260
+ if (problems2.length > 0) {
36261
+ throw expected(
36262
+ sanitizeTerminalText(`Rename these local files, so nothing was pushed:
36263
+ ${problems2.join("\n ")}`)
36264
+ );
36265
+ }
36266
+ }
36267
+ function syncDirExists(dir) {
36268
+ try {
36269
+ fs30.lstatSync(dir);
36270
+ return true;
36271
+ } catch {
36272
+ return false;
36273
+ }
36274
+ }
36275
+ function ensureSyncDir(dir) {
36276
+ if (!syncDirExists(dir)) {
36277
+ fs30.mkdirSync(dir, { recursive: true });
36278
+ return;
36279
+ }
36280
+ if (!fs30.lstatSync(dir).isDirectory()) throw symlinkRefusal(dir, "directory");
36281
+ }
36282
+ function readRecord(dir) {
36283
+ const text = readRealFileOrThrow(dir, path41.join(dir, RECORD_FILE));
36284
+ if (text === null) return null;
36285
+ let parsed;
36286
+ try {
36287
+ parsed = JSON.parse(text);
36288
+ } catch {
36289
+ parsed = void 0;
36290
+ }
36291
+ if (!isRecord3(parsed)) {
36292
+ throw expected(
36293
+ `${path41.join(dir, RECORD_FILE)} is not a record \`wayai files pull\` wrote. Restore it from version control, or move the folder aside and pull again.`
36294
+ );
36295
+ }
36296
+ return parsed;
36297
+ }
36298
+ function isRecord3(v) {
36299
+ if (typeof v !== "object" || v === null) return false;
36300
+ const r = v;
36301
+ if (typeof r.base !== "string" || typeof r.file_type !== "string" || typeof r.folder !== "string") return false;
36302
+ if (typeof r.files !== "object" || r.files === null || Array.isArray(r.files)) return false;
36303
+ return Object.values(r.files).every((f) => {
36304
+ const e = f;
36305
+ return typeof e === "object" && e !== null && typeof e.version === "number" && typeof e.content_sha256 === "string";
36306
+ });
36307
+ }
36308
+ function writeRecord(dir, record) {
36309
+ const files = {};
36310
+ for (const rel of Object.keys(record.files).sort()) files[rel] = syncedFile(record.files[rel]);
36311
+ const body = `${JSON.stringify({ base: record.base, file_type: record.file_type, folder: record.folder, files }, null, 2)}
36312
+ `;
36313
+ const tmp = path41.join(dir, `${RECORD_FILE}.tmp`);
36314
+ if (!writeFileNoFollow(dir, tmp, Buffer.from(body, "utf-8"))) throw symlinkRefusal(tmp, "file");
36315
+ fs30.renameSync(tmp, path41.join(dir, RECORD_FILE));
36316
+ }
36317
+ function syncedFile(f) {
36318
+ return { version: f.version, content_sha256: f.content_sha256 };
36319
+ }
36320
+ function readLocal(dir, rel) {
36321
+ const bytes = readFileNoFollow(dir, path41.join(dir, ...rel.split("/")));
36322
+ if (!bytes) throw symlinkRefusal(path41.join(dir, rel), "file");
36323
+ return bytes;
36324
+ }
36325
+ function scanLocal(dir) {
36326
+ const out = /* @__PURE__ */ new Map();
36327
+ if (!syncDirExists(dir)) return out;
36328
+ ensureSyncDir(dir);
36329
+ const walk = (absDir, relDir) => {
36330
+ for (const name of fs30.readdirSync(absDir).sort()) {
36331
+ const rel = relDir ? `${relDir}/${name}` : name;
36332
+ if (foldSegment(name) === ".git") {
36333
+ throw expected(
36334
+ `${sanitizeTerminalText(path41.join(dir, rel))} is a git repository inside the synced folder, which files pull and push do not sync into. Sync into a folder of its own \u2014 a folder inside a repository is fine; a repository's root, or a folder holding one, is not.`
36335
+ );
36336
+ }
36337
+ if (isOutsideSync(rel)) continue;
36338
+ const st = fs30.lstatSync(path41.join(absDir, name));
36339
+ if (st.isDirectory()) {
36340
+ walk(path41.join(absDir, name), rel);
36341
+ } else if (st.isFile()) {
36342
+ const bytes = readLocal(dir, rel);
36343
+ out.set(rel, { rel, content_sha256: computeHash(bytes), size: bytes.length });
36344
+ } else {
36345
+ throw symlinkRefusal(path41.join(dir, rel), "file or folder");
36346
+ }
36347
+ }
36348
+ };
36349
+ walk(dir, "");
36350
+ return out;
36351
+ }
36352
+ function matchesScan(dir, rel, scanned) {
36353
+ const abs = path41.join(dir, ...rel.split("/"));
36354
+ if (!syncDirExists(abs)) return scanned === void 0;
36355
+ if (scanned === void 0) return false;
36356
+ const bytes = readFileNoFollow(dir, abs);
36357
+ return bytes !== null && computeHash(bytes) === scanned.content_sha256;
36358
+ }
36359
+ function writeLocal(dir, rel, bytes) {
36360
+ const data = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);
36361
+ if (!writeFileNoFollow(dir, path41.join(dir, ...rel.split("/")), data)) {
36362
+ throw symlinkRefusal(path41.join(dir, rel), "file");
36363
+ }
36364
+ }
36365
+ function removeLocal(dir, rel) {
36366
+ const abs = path41.join(dir, ...rel.split("/"));
36367
+ requireRealSubdirNoSymlink(dir, path41.dirname(abs), false);
36368
+ let st;
36369
+ try {
36370
+ st = fs30.lstatSync(abs);
36371
+ } catch {
36372
+ return;
36373
+ }
36374
+ if (!st.isFile()) throw symlinkRefusal(path41.join(dir, rel), "file");
36375
+ fs30.rmSync(abs);
36376
+ const root = path41.resolve(dir);
36377
+ for (let parent = path41.dirname(path41.resolve(abs)); parent !== root && isUnder(root, parent); parent = path41.dirname(parent)) {
36378
+ const names = fs30.readdirSync(parent);
36379
+ if (names.some((n) => n !== ".DS_Store")) break;
36380
+ for (const n of names) fs30.rmSync(path41.join(parent, n));
36381
+ fs30.rmdirSync(parent);
36382
+ }
36383
+ }
36384
+ function diskClash(dir, rel) {
36385
+ const segments = rel.split("/");
36386
+ let abs = dir;
36387
+ for (let i = 0; i < segments.length; i++) {
36388
+ let names;
36389
+ try {
36390
+ names = fs30.readdirSync(abs);
36391
+ } catch {
36392
+ return void 0;
36393
+ }
36394
+ const want = foldSegment(segments[i]);
36395
+ const twin = names.find((n) => n !== segments[i] && foldSegment(n) === want);
36396
+ if (twin !== void 0) return { reason: "case_twin", other: [...segments.slice(0, i), twin].join("/") };
36397
+ if (!names.includes(segments[i])) return void 0;
36398
+ abs = path41.join(abs, segments[i]);
36399
+ const isDir = fs30.lstatSync(abs).isDirectory();
36400
+ const here2 = segments.slice(0, i + 1).join("/");
36401
+ if (i < segments.length - 1 && !isDir) return { reason: "file_folder", other: here2 };
36402
+ if (i === segments.length - 1 && isDir) return { reason: "file_folder", other: `${here2}/` };
36403
+ }
36404
+ return void 0;
36405
+ }
36406
+ var RECORD_FILE, OUTSIDE_SYNC, OUTSIDE_SYNC_FOLDED, CaseIndex, MAX_REMOTE_PATH;
36407
+ var init_local = __esm({
36408
+ "src/data/files-sync/local.ts"() {
36409
+ "use strict";
36410
+ init_expected();
36411
+ init_resource_files();
36412
+ init_fs_safety();
36413
+ init_terminal_output();
36414
+ RECORD_FILE = ".wayai-files.json";
36415
+ OUTSIDE_SYNC = [RECORD_FILE, `${RECORD_FILE}.tmp`, ".git", ".DS_Store"];
36416
+ OUTSIDE_SYNC_FOLDED = new Set(OUTSIDE_SYNC.map((n) => foldSegment(n)));
36417
+ CaseIndex = class {
36418
+ bySpelling = /* @__PURE__ */ new Map();
36419
+ constructor(rels = []) {
36420
+ for (const rel of rels) this.add(rel);
36421
+ }
36422
+ add(rel) {
36423
+ const segments = rel.split("/");
36424
+ for (let i = 1; i <= segments.length; i++) {
36425
+ const prefix = segments.slice(0, i).join("/");
36426
+ const key = foldPath(prefix);
36427
+ if (!this.bySpelling.has(key)) this.bySpelling.set(key, prefix);
36428
+ }
36429
+ }
36430
+ /**
36431
+ * The spelling already indexed for a folder or file of `rel` that differs from `rel`'s own only
36432
+ * by case or normalization — the entry `rel` would land in on a case-insensitive filesystem.
36433
+ */
36434
+ twinOf(rel) {
36435
+ const segments = rel.split("/");
36436
+ for (let i = 1; i <= segments.length; i++) {
36437
+ const prefix = segments.slice(0, i).join("/");
36438
+ const known = this.bySpelling.get(foldPath(prefix));
36439
+ if (known !== void 0 && known !== prefix) return known;
36440
+ }
36441
+ return void 0;
36442
+ }
36443
+ };
36444
+ MAX_REMOTE_PATH = 1024;
36445
+ }
36446
+ });
36447
+
36448
+ // src/data/files-sync/plan.ts
36449
+ function inStep(b, r) {
36450
+ return b !== void 0 && b.content_sha256 === r.content_sha256 && b.version === r.version;
36451
+ }
36452
+ function allPaths({ synced: synced2, local, remote }) {
36453
+ return [.../* @__PURE__ */ new Set([...Object.keys(synced2), ...local.keys(), ...remote.keys()])].sort();
36454
+ }
36455
+ function planPush(input) {
36456
+ const plan = {
36457
+ steps: [],
36458
+ adopt: [],
36459
+ forget: [],
36460
+ conflicts: [],
36461
+ changedOnBase: [],
36462
+ deletedOnBase: [],
36463
+ onlyOnBase: [],
36464
+ keptOnBase: []
36465
+ };
36466
+ const deletes = [];
36467
+ const writes = [];
36468
+ for (const rel of allPaths(input)) {
36469
+ const b = input.synced[rel];
36470
+ const l = input.local.get(rel);
36471
+ const r = input.remote.get(rel);
36472
+ if (l && r && l.content_sha256 === r.content_sha256) {
36473
+ if (!inStep(b, r)) plan.adopt.push(r);
36474
+ continue;
36475
+ }
36476
+ if (b) {
36477
+ if (l) {
36478
+ if (l.content_sha256 === b.content_sha256) {
36479
+ if (!r) plan.deletedOnBase.push(rel);
36480
+ else if (r.content_sha256 !== b.content_sha256) plan.changedOnBase.push(rel);
36481
+ } else if (!r) {
36482
+ plan.conflicts.push({ rel, reason: "deleted_on_base" });
36483
+ } else if (r.content_sha256 !== b.content_sha256) {
36484
+ plan.conflicts.push({ rel, reason: "changed_on_base" });
36485
+ } else {
36486
+ writes.push({ op: "update", rel, local: l, remote: r, ifMatch: b.content_sha256 });
36487
+ }
36488
+ } else if (!r) {
36489
+ plan.forget.push(rel);
36490
+ } else if (!input.prune) {
36491
+ plan.keptOnBase.push(rel);
36492
+ } else if (r.content_sha256 !== b.content_sha256) {
36493
+ plan.conflicts.push({ rel, reason: "changed_on_base" });
36494
+ } else {
36495
+ deletes.push({ op: "delete", rel, remote: r, ifMatch: b.content_sha256 });
36496
+ }
36497
+ } else if (l) {
36498
+ if (r) plan.conflicts.push({ rel, reason: "exists_on_base" });
36499
+ else writes.push({ op: "create", rel, local: l });
36500
+ } else if (r) {
36501
+ plan.onlyOnBase.push(rel);
36502
+ }
36503
+ }
36504
+ const full = (rel) => remotePath(input.folder ?? "", rel);
36505
+ const deleted = new Set(deletes.map((d) => d.rel));
36506
+ const onBase = new BaseNames([
36507
+ ...[...input.remote.keys()].filter((rel) => !deleted.has(rel)).map(full),
36508
+ ...input.elsewhere ?? []
36509
+ ]);
36510
+ const freed = new BaseNames([...deleted].map(full));
36511
+ const kept = [];
36512
+ for (const step of writes) {
36513
+ if (step.op === "create") {
36514
+ const clash = onBase.clash(full(step.rel));
36515
+ if (clash !== void 0) {
36516
+ plan.conflicts.push({ rel: step.rel, ...clash });
36517
+ continue;
36518
+ }
36519
+ const after = freed.clash(full(step.rel)) === void 0 ? [] : [...deleted].flatMap((d) => {
36520
+ const held = new BaseNames([full(d)]).clash(full(step.rel));
36521
+ return held === void 0 ? [] : [{ rel: d, reason: held.reason }];
36522
+ });
36523
+ kept.push(after.length === 0 ? step : { ...step, after });
36524
+ } else {
36525
+ kept.push(step);
36526
+ }
36527
+ onBase.add(full(step.rel));
36528
+ }
36529
+ plan.steps = [...deletes, ...kept];
36530
+ return plan;
36531
+ }
36532
+ function planPull(input) {
36533
+ const plan = { writes: [], removes: [], adopt: [], forget: [], kept: [], conflicts: [], replacedLocal: [] };
36534
+ const { overwrite } = input;
36535
+ const take = (rel, r, replacesLocal) => {
36536
+ plan.writes.push({ rel, remote: r });
36537
+ if (replacesLocal) plan.replacedLocal.push(rel);
36538
+ };
36539
+ for (const rel of allPaths(input)) {
36540
+ const b = input.synced[rel];
36541
+ const l = input.local.get(rel);
36542
+ const r = input.remote.get(rel);
36543
+ if (r) {
36544
+ if (l && l.content_sha256 === r.content_sha256) {
36545
+ if (!inStep(b, r)) plan.adopt.push(r);
36546
+ continue;
36547
+ }
36548
+ const localUnchanged = b !== void 0 && l !== void 0 && l.content_sha256 === b.content_sha256;
36549
+ if (localUnchanged || !b && !l) {
36550
+ take(rel, r, false);
36551
+ continue;
36552
+ }
36553
+ if (overwrite) {
36554
+ take(rel, r, true);
36555
+ } else if (!b) {
36556
+ plan.conflicts.push({ rel, reason: "exists_locally" });
36557
+ } else if (r.content_sha256 === b.content_sha256) {
36558
+ plan.kept.push({ rel, reason: l ? "edited" : "deleted" });
36559
+ } else {
36560
+ plan.conflicts.push({ rel, reason: l ? "both_changed" : "deleted_locally" });
36561
+ }
36562
+ } else if (b) {
36563
+ if (!l) {
36564
+ plan.forget.push(rel);
36565
+ } else if (l.content_sha256 === b.content_sha256 || overwrite) {
36566
+ plan.removes.push(rel);
36567
+ if (l.content_sha256 !== b.content_sha256) plan.replacedLocal.push(rel);
36568
+ } else {
36569
+ plan.conflicts.push({ rel, reason: "deleted_on_base" });
36570
+ }
36571
+ }
36572
+ }
36573
+ return plan;
36574
+ }
36575
+ var BaseNames;
36576
+ var init_plan = __esm({
36577
+ "src/data/files-sync/plan.ts"() {
36578
+ "use strict";
36579
+ init_local();
36580
+ BaseNames = class {
36581
+ cases = new CaseIndex();
36582
+ files = /* @__PURE__ */ new Set();
36583
+ /** Each folder a path sits in, with one path in it to name. */
36584
+ folders = /* @__PURE__ */ new Map();
36585
+ constructor(paths = []) {
36586
+ for (const p of paths) this.add(p);
36587
+ }
36588
+ add(path42) {
36589
+ this.cases.add(path42);
36590
+ this.files.add(path42);
36591
+ const segments = path42.split("/");
36592
+ for (let i = 1; i < segments.length; i++) {
36593
+ const folder = segments.slice(0, i).join("/");
36594
+ if (!this.folders.has(folder)) this.folders.set(folder, path42);
36595
+ }
36596
+ }
36597
+ /** The path `path` would collide with, and how; undefined when it collides with none. */
36598
+ clash(path42) {
36599
+ const twin = this.cases.twinOf(path42);
36600
+ if (twin !== void 0) return { reason: "case_twin", other: twin };
36601
+ const segments = path42.split("/");
36602
+ for (let i = 1; i < segments.length; i++) {
36603
+ const folder = segments.slice(0, i).join("/");
36604
+ if (this.files.has(folder)) return { reason: "file_folder", other: folder };
36605
+ }
36606
+ const inside = this.folders.get(path42);
36607
+ return inside === void 0 ? void 0 : { reason: "file_folder", other: inside };
36608
+ }
36609
+ };
36610
+ }
36611
+ });
36612
+
36613
+ // src/data/files-sync/sync.ts
36614
+ function filesSyncRequestsPerMinute() {
36615
+ const budget = getEndpointConfig(`${DATA_PROXY_PREFIX}/files`)?.userLimit;
36616
+ return budget ? Math.max(1, Math.floor(budget * 4 / 5)) : 60;
36617
+ }
36618
+ async function openRemote2() {
36619
+ const client = await createDataClient();
36620
+ const perMinute = filesSyncRequestsPerMinute();
36621
+ const pacer = new Pacer({
36622
+ perMinute,
36623
+ onWait: (ms, reason) => console.error(
36624
+ reason === "paced" ? ` Pacing at ${perMinute} requests a minute: waiting ${Math.ceil(ms / 1e3)} s.` : ` The data request budget is spent (your other commands and the web console share it): waiting ${Math.ceil(ms / 1e3)} s.`
36625
+ )
36626
+ });
36627
+ return {
36628
+ request: (method, path42, body, headers) => pacer.run(() => client.request(method, path42, body, headers)),
36629
+ upload: (path42, bytes, contentType, headers) => pacer.run(() => client.upload(path42, bytes, contentType, headers)),
36630
+ download: (path42) => pacer.run(() => client.download(path42))
36631
+ };
36632
+ }
36633
+ function filesRoot(t) {
36634
+ return `/v1/${pathSegment(t.base, "--base")}/files/${pathSegment(t.file_type, "file_type")}`;
36635
+ }
36636
+ function filePath(t, rel) {
36637
+ return `${filesRoot(t)}/${pathSegments(remotePath(t.folder, rel))}`;
36638
+ }
36639
+ function pullCommand2(t, dir, overwrite = false) {
36640
+ const folder = t.folder ? ` --folder ${t.folder}` : "";
36641
+ const dirFlag = dir === void 0 ? "" : ` --dir ${dir}`;
36642
+ return sanitizeTerminalText(`wayai files pull ${t.file_type} --base ${t.base}${folder}${dirFlag}${overwrite ? " --overwrite" : ""}`);
36643
+ }
36644
+ function resolveSync(opts) {
36645
+ pathSegment(opts.base, "--base");
36646
+ pathSegment(opts.fileType, "file_type");
36647
+ const target = { base: opts.base, file_type: opts.fileType, folder: normalizeFolder(opts.folder) };
36648
+ const dir = opts.dir ?? defaultDir(target.file_type, target.folder);
36649
+ const existing = syncDirExists(dir) ? readRecord(dir) : null;
36650
+ if (existing && (existing.base !== target.base || existing.file_type !== target.file_type || existing.folder !== target.folder)) {
36651
+ throw expected(
36652
+ `${sanitizeTerminalText(dir)} was pulled from ${describeSync(existing)}, not ${describeSync(target)}. Its recorded versions are that base's, so they cannot check writes to another: name that sync, or use another --dir.`
36653
+ );
36654
+ }
36655
+ return { target, dir, existing };
36656
+ }
36657
+ async function listFiles(client, t, prefix) {
36658
+ const rows = [];
36659
+ for (let page = 0; ; page++) {
36660
+ if (page === MAX_LIST_PAGES) {
36661
+ throw expected(`The listing of ${describeSync(t)} did not end after ${MAX_LIST_PAGES} pages. Sync a narrower --folder.`);
36662
+ }
36663
+ const qs = new URLSearchParams({ limit: String(LIST_PAGE), offset: String(page * LIST_PAGE) });
36664
+ if (prefix) qs.set("prefix", prefix);
36665
+ const pageRows = await client.request("GET", `${filesRoot(t)}?${qs}`) ?? [];
36666
+ for (const row of pageRows) if (row.path.startsWith(prefix)) rows.push(row);
36667
+ if (pageRows.length < LIST_PAGE) return rows;
36668
+ }
36669
+ }
36670
+ async function readBase(t) {
36671
+ const client = await openRemote2();
36672
+ try {
36673
+ await client.request("GET", `/v1/${pathSegment(t.base, "--base")}/file-types/${pathSegment(t.file_type, "file_type")}`);
36674
+ } catch (err) {
36675
+ if (err instanceof ApiError && err.status === 404) {
36676
+ throw expected(sanitizeTerminalText(`Base "${t.base}" has no file type "${t.file_type}".`));
36677
+ }
36678
+ throw err;
36679
+ }
36680
+ const remote = /* @__PURE__ */ new Map();
36681
+ const excluded = [];
36682
+ const prefix = t.folder ? `${t.folder}/` : "";
36683
+ for (const row of await listFiles(client, t, prefix)) {
36684
+ const rel = row.path.slice(prefix.length);
36685
+ if (isOutsideSync(rel)) {
36686
+ excluded.push(rel);
36687
+ continue;
36688
+ }
36689
+ remote.set(rel, {
36690
+ rel,
36691
+ version: row.version,
36692
+ content_sha256: row.content_sha256,
36693
+ content_type: row.content_type || "application/octet-stream",
36694
+ size: row.size ?? 0
36695
+ });
36696
+ }
36697
+ return { client, remote, excluded };
36698
+ }
36699
+ function isNotFound(err) {
36700
+ return err instanceof ApiError && err.status === 404;
36701
+ }
36702
+ async function agree(question, yes) {
36703
+ if (yes) return true;
36704
+ if (!isInteractive()) {
36705
+ throw expected(`${question.trim().replace(/\?$/, "")}: there is no terminal to ask, so pass -y to go ahead.`);
36706
+ }
36707
+ return confirm(question);
36708
+ }
36709
+ function isConflict(err) {
36710
+ return err instanceof ApiError && (err.status === 409 || err.status === 412);
36711
+ }
36712
+ function conflictLine(c, texts) {
36713
+ return `${safe(c.rel)}: ${texts[c.reason]}${c.other === void 0 ? "" : ` "${safe(c.other)}"`}`;
36714
+ }
36715
+ function remedy(conflicts, overwriteCommand) {
36716
+ const isClash = (c) => c.reason === "case_twin" || c.reason === "file_folder";
36717
+ const parts = [];
36718
+ if (conflicts.some((c) => !isClash(c))) {
36719
+ parts.push(`take the base's copies with \`${overwriteCommand}\` (commit yours first to merge them)`);
36720
+ }
36721
+ if (conflicts.some(isClash)) {
36722
+ parts.push("rename or remove one path of each pair that differs only in case or is both a file and a folder (--overwrite cannot settle those)");
36723
+ }
36724
+ return parts.join("; ");
36725
+ }
36726
+ async function pullFiles(opts) {
36727
+ const { target, dir, existing } = resolveSync(opts);
36728
+ const { client, remote, excluded } = await readBase(target);
36729
+ assertRepresentable([...remote.keys()]);
36730
+ const local = scanLocal(dir);
36731
+ const plan = planPull({ synced: existing?.files ?? {}, local, remote, overwrite: opts.overwrite });
36732
+ if (plan.replacedLocal.length > 0) {
36733
+ console.log("These local changes would be replaced with the base's copies:");
36734
+ for (const rel of plan.replacedLocal) console.log(` ${safe(rel)}`);
36735
+ if (!await agree(`Replace ${plan.replacedLocal.length} locally changed file(s)?`, opts.yes)) {
36736
+ console.log("Cancelled.");
36737
+ return;
36738
+ }
36739
+ }
36740
+ ensureSyncDir(dir);
36741
+ const record = { ...target, files: { ...existing?.files ?? {} } };
36742
+ for (const rel of plan.forget) delete record.files[rel];
36743
+ for (const r of plan.adopt) record.files[r.rel] = syncedFile(r);
36744
+ const conflicts = [...plan.conflicts];
36745
+ const changes = [];
36746
+ const changedWhilePulling = [];
36747
+ try {
36748
+ for (const rel of plan.removes) {
36749
+ if (!matchesScan(dir, rel, local.get(rel))) {
36750
+ conflicts.push({ rel, reason: "edited_while_pulling" });
36751
+ continue;
36752
+ }
36753
+ removeLocal(dir, rel);
36754
+ delete record.files[rel];
36755
+ changes.push(`${MARK.delete} ${safe(rel)}`);
36756
+ }
36757
+ for (const w of plan.writes) {
36758
+ const clash = diskClash(dir, w.rel);
36759
+ if (clash !== void 0) {
36760
+ conflicts.push({ rel: w.rel, ...clash });
36761
+ continue;
36762
+ }
36763
+ const path42 = filePath(target, w.rel);
36764
+ let bytes;
36765
+ let version = w.remote.version;
36766
+ try {
36767
+ bytes = (await client.download(path42)).bytes;
36768
+ if (computeHash(bytes) !== w.remote.content_sha256) {
36769
+ const meta = await client.request("GET", `${path42}?meta=1`);
36770
+ if (meta?.content_sha256 !== computeHash(bytes)) {
36771
+ changedWhilePulling.push(w.rel);
36772
+ continue;
36773
+ }
36774
+ version = meta.version;
36775
+ }
36776
+ } catch (err) {
36777
+ if (!isNotFound(err)) throw err;
36778
+ changedWhilePulling.push(w.rel);
36779
+ continue;
36780
+ }
36781
+ if (!matchesScan(dir, w.rel, local.get(w.rel))) {
36782
+ conflicts.push({ rel: w.rel, reason: "edited_while_pulling" });
36783
+ continue;
36784
+ }
36785
+ const hash = computeHash(bytes);
36786
+ writeLocal(dir, w.rel, bytes);
36787
+ record.files[w.rel] = { version, content_sha256: hash };
36788
+ changes.push(`${local.has(w.rel) ? MARK.update : MARK.create} ${safe(w.rel)}`);
36789
+ }
36790
+ } finally {
36791
+ writeRecord(dir, record);
36792
+ }
36793
+ const count = Object.keys(record.files).length;
36794
+ console.log(sanitizeTerminalText(`Pulled ${describeSync(target)} \u2192 ${dir} (${count} file${count === 1 ? "" : "s"}).`));
36795
+ printSection("Changes:", changes);
36796
+ printSection("Kept \u2014 your local changes:", plan.kept.map((k) => `${safe(k.rel)}: ${PULL_KEPT[k.reason]}`));
36797
+ printSection(
36798
+ `Conflicts \u2014 your copy is kept; to settle them, ${remedy(conflicts, pullCommand2(target, opts.dir, true))}:`,
36799
+ conflicts.map((c) => conflictLine(c, PULL_CONFLICT))
36800
+ );
36801
+ printSection("Changed or deleted on the base while pulling \u2014 left as is; pull again to take it:", changedWhilePulling.map(safe));
36802
+ printSection(`Not synced \u2014 names a synced folder leaves out (${OUTSIDE_SYNC.join(", ")}):`, excluded.map(safe));
36803
+ }
36804
+ function isTextType(contentType) {
36805
+ const ct = contentType.split(";")[0].trim().toLowerCase();
36806
+ return ct.startsWith("text/") || /^application\/(json|xml|yaml|x-yaml|javascript|x-ndjson)$/.test(ct) || /\+(json|xml)$/.test(ct);
36807
+ }
36808
+ function changedLines(before, after) {
36809
+ const a = sanitizeTerminalText(before).split("\n");
36810
+ const b = sanitizeTerminalText(after).split("\n");
36811
+ let start = 0;
36812
+ while (start < a.length && start < b.length && a[start] === b[start]) start++;
36813
+ let end = 0;
36814
+ while (end < a.length - start && end < b.length - start && a[a.length - 1 - end] === b[b.length - 1 - end]) end++;
36815
+ return lineDiffOf(a.slice(start, a.length - end), b.slice(start, b.length - end));
36816
+ }
36817
+ async function describeSteps(client, t, dir, steps) {
36818
+ const lines = [];
36819
+ for (const step of steps) {
36820
+ const rel = safe(step.rel);
36821
+ if (step.op === "create") {
36822
+ lines.push(`${MARK.create} ${rel} (new, ${step.local.size} bytes)`);
36823
+ } else if (step.op === "delete") {
36824
+ lines.push(`${MARK.delete} ${rel} (delete)`);
36825
+ } else {
36826
+ lines.push(`${MARK.update} ${rel}`);
36827
+ if (!isTextType(step.remote.content_type) || step.remote.size > MAX_DIFF_BYTES || step.local.size > MAX_DIFF_BYTES) {
36828
+ lines.push(` (content changed: ${step.remote.size} \u2192 ${step.local.size} bytes)`);
36829
+ continue;
36830
+ }
36831
+ let bytes;
36832
+ try {
36833
+ bytes = (await client.download(filePath(t, step.rel))).bytes;
36834
+ } catch (err) {
36835
+ if (!isNotFound(err)) throw err;
36836
+ lines.push(" (deleted on the base since it was listed)");
36837
+ continue;
36838
+ }
36839
+ const before = Buffer.from(bytes).toString("utf-8");
36840
+ const after = readLocal(dir, step.rel).toString("utf-8");
36841
+ for (const line of changedLines(before, after)) lines.push(` ${line}`);
36842
+ }
36843
+ }
36844
+ return lines;
36845
+ }
36846
+ function printPushNotes(plan) {
36847
+ printSection("Changed on the base since your last pull \u2014 left as is; pull to take it:", plan.changedOnBase.map(safe));
36848
+ printSection("Deleted on the base since your last pull \u2014 left as is; pull to remove your copy:", plan.deletedOnBase.map(safe));
36849
+ printSection("On the base, not in your files \u2014 left as is; pull to fetch it:", plan.onlyOnBase.map(safe));
36850
+ printSection("Deleted in your files \u2014 kept on the base; push with --prune to delete it:", plan.keptOnBase.map(safe));
36851
+ }
36852
+ async function pushFiles(opts) {
36853
+ const label = opts.label === void 0 ? void 0 : labelValue(opts.label);
36854
+ const { target, dir, existing } = resolveSync(opts);
36855
+ if (!existing) {
36856
+ throw expected(
36857
+ `${sanitizeTerminalText(dir)} has no record of a pull (${RECORD_FILE}), so there is nothing to check a push against. Run \`${pullCommand2(target, opts.dir)}\` first; a file type with no files pulls an empty record.`
36858
+ );
36859
+ }
36860
+ const local = scanLocal(dir);
36861
+ assertPushable(target.folder, [...local.keys()]);
36862
+ const { client, remote } = await readBase(target);
36863
+ let plan = planPush({ synced: existing.files, local, remote, prune: opts.prune });
36864
+ if (target.folder && plan.steps.some((s) => s.op === "create")) {
36865
+ const prefix = `${target.folder}/`;
36866
+ const elsewhere = (await listFiles(client, target, "")).map((r) => r.path).filter((p) => !p.startsWith(prefix));
36867
+ plan = planPush({ synced: existing.files, local, remote, prune: opts.prune, folder: target.folder, elsewhere });
36868
+ }
36869
+ const conflicts = [...plan.conflicts];
36870
+ console.log(sanitizeTerminalText(`Push ${dir} \u2192 ${describeSync(target)}`));
36871
+ printSection("Changes:", await describeSteps(client, target, dir, plan.steps));
36872
+ printPushNotes(plan);
36873
+ printSection("Conflicts \u2014 not pushed:", conflicts.map((c) => conflictLine(c, PUSH_CONFLICT)));
36874
+ if (opts.dryRun) {
36875
+ console.log("\nDry run \u2014 nothing pushed.");
36876
+ finishWithConflicts(target, opts.dir, conflicts);
36877
+ return;
36878
+ }
36879
+ const record = { ...existing, files: { ...existing.files } };
36880
+ for (const r of plan.adopt) record.files[r.rel] = syncedFile(r);
36881
+ for (const rel of plan.forget) delete record.files[rel];
36882
+ if (plan.adopt.length > 0 || plan.forget.length > 0) writeRecord(dir, record);
36883
+ if (plan.steps.length === 0) {
36884
+ if (conflicts.length === 0) console.log(`
36885
+ Nothing to push \u2014 the base already has every change in ${sanitizeTerminalText(dir)}.`);
36886
+ finishWithConflicts(target, opts.dir, conflicts);
36887
+ return;
36888
+ }
36889
+ const n = plan.steps.length;
36890
+ if (!await agree(`
36891
+ Push ${n} change${n === 1 ? "" : "s"} to ${describeSync(target)}?`, opts.yes)) {
36892
+ console.log("Cancelled.");
36893
+ return;
36894
+ }
36895
+ let pushed = 0;
36896
+ const refusedDeletes = /* @__PURE__ */ new Set();
36897
+ for (const step of plan.steps) {
36898
+ const path42 = filePath(target, step.rel);
36899
+ const blockedBy = step.op === "create" ? step.after?.find((d) => refusedDeletes.has(d.rel)) : void 0;
36900
+ if (blockedBy !== void 0) {
36901
+ const conflict = { rel: step.rel, reason: blockedBy.reason, other: blockedBy.rel };
36902
+ conflicts.push(conflict);
36903
+ console.log(` ! ${conflictLine(conflict, PUSH_CONFLICT)}`);
36904
+ continue;
36905
+ }
36906
+ try {
36907
+ if (step.op === "delete") {
36908
+ await client.request("DELETE", path42, void 0, fileWriteHeaders({ ifMatch: step.ifMatch }));
36909
+ delete record.files[step.rel];
36910
+ } else {
36911
+ const bytes = readLocal(dir, step.rel);
36912
+ if (computeHash(bytes) !== step.local.content_sha256) {
36913
+ throw expected(`${safe(step.rel)} changed while the push ran. Nothing more was pushed; run the push again.`);
36914
+ }
36915
+ const contentType = step.op === "update" ? step.remote.content_type : guessMimeType(step.rel) ?? "application/octet-stream";
36916
+ const row = await client.upload(
36917
+ path42,
36918
+ bytes,
36919
+ contentType,
36920
+ fileWriteHeaders({ ifMatch: step.op === "update" ? step.ifMatch : void 0, label })
36921
+ );
36922
+ record.files[step.rel] = {
36923
+ version: typeof row?.version === "number" ? row.version : 0,
36924
+ content_sha256: row?.content_sha256 ?? step.local.content_sha256
36925
+ };
36926
+ }
36927
+ pushed++;
36928
+ console.log(` ${MARK[step.op]} ${safe(step.rel)}`);
36929
+ } catch (err) {
36930
+ if (step.op === "delete" && err instanceof ApiError && err.status === 404) {
36931
+ delete record.files[step.rel];
36932
+ } else if (isConflict(err)) {
36933
+ if (step.op === "delete") refusedDeletes.add(step.rel);
36934
+ const conflict = { rel: step.rel, reason: "changed_while_pushing" };
36935
+ conflicts.push(conflict);
36936
+ console.log(` ! ${conflictLine(conflict, PUSH_CONFLICT)}`);
36937
+ continue;
36938
+ } else {
36939
+ throw err;
36940
+ }
36941
+ }
36942
+ writeRecord(dir, record);
36943
+ }
36944
+ console.log(sanitizeTerminalText(`
36945
+ Pushed ${pushed} change${pushed === 1 ? "" : "s"} to ${describeSync(target)}.`));
36946
+ finishWithConflicts(target, opts.dir, conflicts);
36947
+ }
36948
+ function finishWithConflicts(t, dir, conflicts) {
36949
+ const count = conflicts.length;
36950
+ if (count === 0) return;
36951
+ throw expected(
36952
+ `${count} conflict${count === 1 ? "" : "s"} not pushed \u2014 the base's copies of those files were left as they are. To settle them, ${remedy(conflicts, pullCommand2(t, dir, true))}, then push again.`
36953
+ );
36954
+ }
36955
+ var LIST_PAGE, MAX_LIST_PAGES, MAX_DIFF_BYTES, MARK, safe, PULL_KEPT, PULL_CONFLICT, PUSH_CONFLICT;
36956
+ var init_sync3 = __esm({
36957
+ "src/data/files-sync/sync.ts"() {
36958
+ "use strict";
36959
+ init_dist();
36960
+ init_contracts();
36961
+ init_api_client();
36962
+ init_expected();
36963
+ init_resource_files();
36964
+ init_terminal_output();
36965
+ init_utils();
36966
+ init_listing();
36967
+ init_pacer();
36968
+ init_client();
36969
+ init_helpers();
36970
+ init_headers();
36971
+ init_local();
36972
+ init_plan();
36973
+ LIST_PAGE = 1e3;
36974
+ MAX_LIST_PAGES = 1e3;
36975
+ MAX_DIFF_BYTES = 256 * 1024;
36976
+ MARK = { create: "+", update: "~", delete: "-" };
36977
+ safe = (rel) => sanitizeTerminalText(rel);
36978
+ PULL_KEPT = {
36979
+ edited: "edited in your files, not pushed yet",
36980
+ deleted: "deleted in your files, not pushed yet (push --prune deletes it from the base)"
36981
+ };
36982
+ PULL_CONFLICT = {
36983
+ both_changed: "changed in your files and on the base",
36984
+ deleted_on_base: "edited in your files, deleted on the base",
36985
+ deleted_locally: "deleted in your files, changed on the base",
36986
+ exists_locally: "in your files and on the base, with different content",
36987
+ case_twin: "differs only in case from your local",
36988
+ file_folder: "would be both a file and a folder with your local",
36989
+ edited_while_pulling: "changed in your files while pulling \u2014 kept; pull again"
36990
+ };
36991
+ PUSH_CONFLICT = {
36992
+ changed_on_base: "changed on the base since your last pull",
36993
+ deleted_on_base: "deleted on the base since your last pull",
36994
+ exists_on_base: "created on the base since your last pull",
36995
+ case_twin: "differs only in case from the base's",
36996
+ file_folder: "would make one path both a file and a folder with the base's",
36997
+ changed_while_pushing: "changed on the base while pushing \u2014 not written"
36998
+ };
36999
+ }
37000
+ });
37001
+
35975
37002
  // src/data/commands/files.ts
35976
37003
  import { Command as Command12 } from "commander";
35977
37004
  import { readFileSync as readFileSync23, writeFileSync as writeFileSync11 } from "fs";
35978
37005
  import { basename as basename25 } from "path";
35979
- function renderFileDiff(fileType, filePath, from, to, d) {
35980
- console.log(sanitizeTerminalText(`${fileType}/${filePath}: v${from} \u2192 v${to}`));
37006
+ function renderFileDiff(fileType, filePath2, from, to, d) {
37007
+ console.log(sanitizeTerminalText(`${fileType}/${filePath2}: v${from} \u2192 v${to}`));
35981
37008
  const md = d.metadata_delta;
35982
37009
  if (md) {
35983
37010
  for (const f of ["path", "size", "content_type", "label"]) {
@@ -36005,12 +37032,12 @@ function renderFileDiff(fileType, filePath, from, to, d) {
36005
37032
  console.log(sanitizeTerminalText(` content: changed (${content.kind})`));
36006
37033
  }
36007
37034
  }
36008
- function downloadTarget(remotePath, to) {
37035
+ function downloadTarget(remotePath2, to) {
36009
37036
  if (to) return to;
36010
- const derived = basename25(remotePath);
37037
+ const derived = basename25(remotePath2);
36011
37038
  if (derived === "" || derived === "." || derived === "..") {
36012
37039
  throw expected(
36013
- `Cannot derive a local filename from "${remotePath}" \u2014 pass --to <local> to name it.`
37040
+ `Cannot derive a local filename from "${remotePath2}" \u2014 pass --to <local> to name it.`
36014
37041
  );
36015
37042
  }
36016
37043
  return derived;
@@ -36021,23 +37048,32 @@ function buildFilesCommand() {
36021
37048
  );
36022
37049
  files.command("put <file_type> <path>").description(
36023
37050
  "Upload a local file to a path (e.g. wayai files put reports q3/summary.pdf --file ./summary.pdf)"
36024
- ).requiredOption("--file <local>", "Local file to upload").option("--content-type <type>", "MIME type", "application/octet-stream").action(async function(fileType, filePath, opts) {
37051
+ ).requiredOption("--file <local>", "Local file to upload").option("--content-type <type>", "MIME type", "application/octet-stream").option(
37052
+ "--if-match <hash>",
37053
+ "Write only if the file's content hash is still this one (its ETag, or content_sha256 from get --meta); refused with a conflict otherwise"
37054
+ ).option("--label <text>", "Label for the content version this upload creates (printable ASCII)").option("--metadata <json>", "The file's metadata, a JSON object (inline or @filename)").action(async function(fileType, filePath2, opts) {
36025
37055
  const base = pathSegment(requireBase(this), "--base");
37056
+ const headers = fileWriteHeaders({
37057
+ ifMatch: opts.ifMatch,
37058
+ label: opts.label,
37059
+ metadata: opts.metadata === void 0 ? void 0 : parseData(opts.metadata, "--metadata")
37060
+ });
36026
37061
  const body = readFileSync23(opts.file);
36027
37062
  const client = await createDataClient();
36028
37063
  printOutput(
36029
37064
  await client.upload(
36030
- `/v1/${base}/files/${pathSegment(fileType, "file_type")}/${pathSegments(filePath)}`,
37065
+ `/v1/${base}/files/${pathSegment(fileType, "file_type")}/${pathSegments(filePath2)}`,
36031
37066
  body,
36032
- opts.contentType
37067
+ opts.contentType,
37068
+ headers
36033
37069
  ),
36034
37070
  outputFormat(this)
36035
37071
  );
36036
37072
  });
36037
37073
  files.command("get <file_type> <path>").description(
36038
37074
  "Download a file (or --meta for metadata only). --version N reads a specific retained content version."
36039
- ).option("--to <local>", "Local file to save to (defaults to the file basename)").option("--meta", "Print metadata JSON instead of downloading the content").option("--version <n>", "Read a specific content version (default: latest)").action(async function(fileType, filePath, opts) {
36040
- const encoded = pathSegments(filePath);
37075
+ ).option("--to <local>", "Local file to save to (defaults to the file basename)").option("--meta", "Print metadata JSON instead of downloading the content").option("--version <n>", "Read a specific content version (default: latest)").action(async function(fileType, filePath2, opts) {
37076
+ const encoded = pathSegments(filePath2);
36041
37077
  const versionQs = opts.version !== void 0 ? `version=${encodeURIComponent(opts.version)}` : "";
36042
37078
  const base = pathSegment(requireBase(this), "--base");
36043
37079
  if (opts.meta) {
@@ -36049,7 +37085,7 @@ function buildFilesCommand() {
36049
37085
  );
36050
37086
  return;
36051
37087
  }
36052
- const out = downloadTarget(filePath, opts.to);
37088
+ const out = downloadTarget(filePath2, opts.to);
36053
37089
  const client = await createDataClient();
36054
37090
  const { bytes } = await client.download(
36055
37091
  `/v1/${base}/files/${pathSegment(fileType, "file_type")}/${encoded}${versionQs ? `?${versionQs}` : ""}`
@@ -36057,7 +37093,7 @@ function buildFilesCommand() {
36057
37093
  writeFileSync11(out, bytes);
36058
37094
  console.log(`Downloaded to ${out}`);
36059
37095
  });
36060
- files.command("history <file_type> <path>").description("List the content versions of a file (newest first)").option("--limit <n>", "Max versions to return").option("--offset <n>", "Pagination offset").action(async function(fileType, filePath, opts) {
37096
+ files.command("history <file_type> <path>").description("List the content versions of a file (newest first)").option("--limit <n>", "Max versions to return").option("--offset <n>", "Pagination offset").action(async function(fileType, filePath2, opts) {
36061
37097
  const base = pathSegment(requireBase(this), "--base");
36062
37098
  const client = await createDataClient();
36063
37099
  const qs = new URLSearchParams({ history: "1" });
@@ -36066,24 +37102,24 @@ function buildFilesCommand() {
36066
37102
  printOutput(
36067
37103
  await client.request(
36068
37104
  "GET",
36069
- `/v1/${base}/files/${pathSegment(fileType, "file_type")}/${pathSegments(filePath)}?${qs}`
37105
+ `/v1/${base}/files/${pathSegment(fileType, "file_type")}/${pathSegments(filePath2)}?${qs}`
36070
37106
  ),
36071
37107
  outputFormat(this)
36072
37108
  );
36073
37109
  });
36074
- files.command("diff <file_type> <path>").description("Diff two content versions of a file \u2014 metadata delta plus a text content diff").requiredOption("--from <n>", "Base version number").requiredOption("--to <n>", "Target version number").action(async function(fileType, filePath, opts) {
37110
+ files.command("diff <file_type> <path>").description("Diff two content versions of a file \u2014 metadata delta plus a text content diff").requiredOption("--from <n>", "Base version number").requiredOption("--to <n>", "Target version number").action(async function(fileType, filePath2, opts) {
36075
37111
  const base = pathSegment(requireBase(this), "--base");
36076
37112
  const client = await createDataClient();
36077
37113
  const qs = new URLSearchParams({ diff: "1", from: opts.from, to: opts.to });
36078
37114
  const data = await client.request(
36079
37115
  "GET",
36080
- `/v1/${base}/files/${pathSegment(fileType, "file_type")}/${pathSegments(filePath)}?${qs}`
37116
+ `/v1/${base}/files/${pathSegment(fileType, "file_type")}/${pathSegments(filePath2)}?${qs}`
36081
37117
  );
36082
37118
  if (outputFormat(this) === "json") {
36083
37119
  printOutput(data, "json");
36084
37120
  return;
36085
37121
  }
36086
- renderFileDiff(fileType, filePath, opts.from, opts.to, data);
37122
+ renderFileDiff(fileType, filePath2, opts.from, opts.to, data);
36087
37123
  });
36088
37124
  files.command("list <file_type>").description("List files by path prefix").option("--prefix <path>", "Path prefix filter (e.g. q3/)").option("--depth <n>", "Max folder depth below the prefix (1 = immediate children)").option("--limit <n>", "Max results").option("--offset <n>", "Pagination offset").action(async function(fileType, opts) {
36089
37125
  const base = pathSegment(requireBase(this), "--base");
@@ -36109,16 +37145,53 @@ function buildFilesCommand() {
36109
37145
  outputFormat(this)
36110
37146
  );
36111
37147
  });
36112
- files.command("rm <file_type> <path>").description("Delete a file").option("-y, --yes", "Skip confirmation prompt").action(async function(fileType, filePath, opts) {
36113
- if (!opts.yes && !await confirm(`Delete file "${fileType}/${filePath}"? This cannot be undone.`)) {
37148
+ files.command("rm <file_type> <path>").description("Delete a file").option("-y, --yes", "Skip confirmation prompt").option(
37149
+ "--if-match <hash>",
37150
+ "Delete only if the file's content hash is still this one; refused with a conflict otherwise"
37151
+ ).action(async function(fileType, filePath2, opts) {
37152
+ const headers = fileWriteHeaders({ ifMatch: opts.ifMatch });
37153
+ if (!opts.yes && !await confirm(`Delete file "${fileType}/${filePath2}"? This cannot be undone.`)) {
36114
37154
  console.log("Aborted");
36115
37155
  return;
36116
37156
  }
36117
37157
  const base = pathSegment(requireBase(this), "--base");
36118
37158
  const client = await createDataClient();
36119
- await client.request("DELETE", `/v1/${base}/files/${pathSegment(fileType, "file_type")}/${pathSegments(filePath)}`);
37159
+ await client.request(
37160
+ "DELETE",
37161
+ `/v1/${base}/files/${pathSegment(fileType, "file_type")}/${pathSegments(filePath2)}`,
37162
+ void 0,
37163
+ headers
37164
+ );
36120
37165
  console.log("Deleted");
36121
37166
  });
37167
+ files.command("pull <file_type>").description(
37168
+ "Pull a file type, or one --folder of it, into a local folder (default ./<file_type>[/<folder>]), recording each file's version for push. Local changes are kept; --overwrite replaces them"
37169
+ ).option("--folder <path>", "Sync one folder of the file type (e.g. hr), not all of it").option("--dir <local>", "Local folder to sync into (default ./<file_type>, or ./<file_type>/<folder>)").option("--overwrite", "Replace local changes with the base's copies").option("-y, --yes", "Skip the confirmation --overwrite asks for").action(async function(fileType, opts) {
37170
+ const base = requireBase(this);
37171
+ await pullFiles({
37172
+ base,
37173
+ fileType,
37174
+ folder: opts.folder,
37175
+ dir: opts.dir,
37176
+ overwrite: opts.overwrite ?? false,
37177
+ yes: opts.yes ?? false
37178
+ });
37179
+ });
37180
+ files.command("push <file_type>").description(
37181
+ "Push the local changes of a folder pulled with `files pull` to the base, after showing the diff. A file changed, deleted or created on the base since your pull is a conflict, not written; an update or delete also carries the version pulled, so the base refuses it if the file changed meanwhile"
37182
+ ).option("--folder <path>", "The folder of the file type the local folder was pulled from").option("--dir <local>", "Local folder to push (default ./<file_type>, or ./<file_type>/<folder>)").option("--dry-run", "Show the diff and push nothing").option("--prune", "Also delete files you deleted locally \u2014 only those unchanged on the base since your pull").option("--label <text>", "Label for every content version the push creates (printable ASCII)").option("-y, --yes", "Push without asking").action(async function(fileType, opts) {
37183
+ const base = requireBase(this);
37184
+ await pushFiles({
37185
+ base,
37186
+ fileType,
37187
+ folder: opts.folder,
37188
+ dir: opts.dir,
37189
+ dryRun: opts.dryRun ?? false,
37190
+ prune: opts.prune ?? false,
37191
+ label: opts.label,
37192
+ yes: opts.yes ?? false
37193
+ });
37194
+ });
36122
37195
  files.command("mount <file_type>").description(
36123
37196
  "Mint an S3 credential so any harness can mount this file type as a filesystem (s3fs, cloud mount SDKs). Read-only by default; the secret is shown once."
36124
37197
  ).option("--expires-in <seconds>", "Credential lifetime in seconds (default 30 days, max 90)").option(
@@ -36171,6 +37244,8 @@ var init_files2 = __esm({
36171
37244
  init_helpers();
36172
37245
  init_utils();
36173
37246
  init_terminal_output();
37247
+ init_headers();
37248
+ init_sync3();
36174
37249
  }
36175
37250
  });
36176
37251
 
@@ -36383,8 +37458,8 @@ function buildRecordsCommand() {
36383
37458
  const body = { data: parseData(opts.data) };
36384
37459
  if (opts.externalId) body.external_id = opts.externalId;
36385
37460
  if (opts.externalSource) body.external_source = opts.externalSource;
36386
- const path41 = opts.id ? `/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${pathSegment(opts.id, "--id")}` : `/v1/${base}/records/${pathSegment(recordType2, "record_type")}`;
36387
- printOutput(await client.request("PUT", path41, body), outputFormat(this));
37461
+ const path42 = opts.id ? `/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${pathSegment(opts.id, "--id")}` : `/v1/${base}/records/${pathSegment(recordType2, "record_type")}`;
37462
+ printOutput(await client.request("PUT", path42, body), outputFormat(this));
36388
37463
  });
36389
37464
  records.command("query <record_type>").description("List/search records: exact filters + fuzzy `search`, sorting, pagination").option(
36390
37465
  "--external-source <source>",
@@ -36419,9 +37494,9 @@ function buildRecordsCommand() {
36419
37494
  ).action(async function(recordType2, id, opts) {
36420
37495
  const base = pathSegment(requireBase(this), "--base");
36421
37496
  const client = await createDataClient();
36422
- let path41 = `/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${recordKey(id, opts.externalSource)}`;
36423
- if (opts.externalSource) path41 += `?external_source=${encodeURIComponent(opts.externalSource)}`;
36424
- printOutput(await client.request("GET", path41), outputFormat(this));
37497
+ let path42 = `/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${recordKey(id, opts.externalSource)}`;
37498
+ if (opts.externalSource) path42 += `?external_source=${encodeURIComponent(opts.externalSource)}`;
37499
+ printOutput(await client.request("GET", path42), outputFormat(this));
36425
37500
  });
36426
37501
  records.command("delete <record_type> <id>").description(
36427
37502
  "Delete a record by internal ID, or by external_id (pass --external-source to scope it)"
@@ -36435,11 +37510,11 @@ function buildRecordsCommand() {
36435
37510
  }
36436
37511
  const base = pathSegment(requireBase(this), "--base");
36437
37512
  const client = await createDataClient();
36438
- let path41 = `/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${recordKey(id, opts.externalSource)}`;
37513
+ let path42 = `/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${recordKey(id, opts.externalSource)}`;
36439
37514
  if (opts.externalSource) {
36440
- path41 += `?external_source=${encodeURIComponent(opts.externalSource)}&external_id=${encodeURIComponent(id)}`;
37515
+ path42 += `?external_source=${encodeURIComponent(opts.externalSource)}&external_id=${encodeURIComponent(id)}`;
36441
37516
  }
36442
- await client.request("DELETE", path41);
37517
+ await client.request("DELETE", path42);
36443
37518
  console.log("Deleted");
36444
37519
  });
36445
37520
  records.command("history <id>").description(
@@ -36604,8 +37679,8 @@ function buildRelationshipsCommand() {
36604
37679
  if (opts.data) body.data = parseData(opts.data);
36605
37680
  const base = pathSegment(requireBase(this), "--base");
36606
37681
  const client = await createDataClient();
36607
- const path41 = opts.id ? `/v1/${base}/relationships/${pathSegment(opts.id, "--id")}` : `/v1/${base}/relationships`;
36608
- printOutput(await client.request("PUT", path41, body), outputFormat(this));
37682
+ const path42 = opts.id ? `/v1/${base}/relationships/${pathSegment(opts.id, "--id")}` : `/v1/${base}/relationships`;
37683
+ printOutput(await client.request("PUT", path42, body), outputFormat(this));
36609
37684
  });
36610
37685
  relationships.command("get <id>").description(
36611
37686
  "Get a relationship by ID (or by its external key: pass the external_id with --rel-type)"
@@ -36838,8 +37913,8 @@ function buildToolsetsCommand() {
36838
37913
  toolsets.command("get <slug>").description("Get a toolset").option("--resolved", "Include resolved record_type schemas").action(async function(slug, opts) {
36839
37914
  const base = pathSegment(requireBase(this), "--base");
36840
37915
  const client = await createDataClient();
36841
- const path41 = opts.resolved ? `/v1/${base}/toolsets/${pathSegment(slug, "toolset slug")}/resolved` : `/v1/${base}/toolsets/${pathSegment(slug, "toolset slug")}`;
36842
- printOutput(await client.request("GET", path41), outputFormat(this));
37916
+ const path42 = opts.resolved ? `/v1/${base}/toolsets/${pathSegment(slug, "toolset slug")}/resolved` : `/v1/${base}/toolsets/${pathSegment(slug, "toolset slug")}`;
37917
+ printOutput(await client.request("GET", path42), outputFormat(this));
36843
37918
  });
36844
37919
  toolsets.command("list").description("List all toolsets").action(async function() {
36845
37920
  const base = pathSegment(requireBase(this), "--base");
@@ -37074,7 +38149,7 @@ init_utils();
37074
38149
  init_registry();
37075
38150
  import { readFileSync as readFileSync24 } from "fs";
37076
38151
  import { fileURLToPath as fileURLToPath3 } from "url";
37077
- import { dirname as dirname16, join as join37 } from "path";
38152
+ import { dirname as dirname17, join as join38 } from "path";
37078
38153
 
37079
38154
  // src/lib/version-refresh.ts
37080
38155
  init_version_cache();
@@ -37082,7 +38157,7 @@ init_skill_version();
37082
38157
  import { exec } from "child_process";
37083
38158
  var REFRESH_TIMEOUT_MS = 1e4;
37084
38159
  function refreshCliCache() {
37085
- return new Promise((resolve12) => {
38160
+ return new Promise((resolve13) => {
37086
38161
  exec("npm view @wayai/cli version", { timeout: REFRESH_TIMEOUT_MS }, (err, stdout) => {
37087
38162
  if (!err) {
37088
38163
  const latest = stdout.trim();
@@ -37093,7 +38168,7 @@ function refreshCliCache() {
37093
38168
  }
37094
38169
  }
37095
38170
  }
37096
- resolve12();
38171
+ resolve13();
37097
38172
  });
37098
38173
  });
37099
38174
  }
@@ -37119,8 +38194,8 @@ async function refreshSkillCache() {
37119
38194
  }
37120
38195
  async function refreshAdminSkillCache() {
37121
38196
  let timer;
37122
- const deadline = new Promise((resolve12) => {
37123
- timer = setTimeout(resolve12, REFRESH_TIMEOUT_MS);
38197
+ const deadline = new Promise((resolve13) => {
38198
+ timer = setTimeout(resolve13, REFRESH_TIMEOUT_MS);
37124
38199
  });
37125
38200
  await Promise.race([deadline, fetchAndCacheAdminSkillVersion().catch(() => {
37126
38201
  })]);
@@ -37229,8 +38304,8 @@ Run \`wayai admin skill install\` to update.`);
37229
38304
  }
37230
38305
 
37231
38306
  // src/index.ts
37232
- var __dirname = dirname16(fileURLToPath3(import.meta.url));
37233
- var pkg = JSON.parse(readFileSync24(join37(__dirname, "..", "package.json"), "utf-8"));
38307
+ var __dirname = dirname17(fileURLToPath3(import.meta.url));
38308
+ var pkg = JSON.parse(readFileSync24(join38(__dirname, "..", "package.json"), "utf-8"));
37234
38309
  var [, , command, ...args] = process.argv;
37235
38310
  var isBackgroundRefresh = command === REFRESH_COMMAND;
37236
38311
  if (!isBackgroundRefresh) initSentry(command, pkg.version);
@@ -37280,8 +38355,8 @@ async function main() {
37280
38355
  break;
37281
38356
  }
37282
38357
  case "pull": {
37283
- const { pullCommand: pullCommand2 } = await Promise.resolve().then(() => (init_pull(), pull_exports));
37284
- await pullCommand2(args);
38358
+ const { pullCommand: pullCommand3 } = await Promise.resolve().then(() => (init_pull(), pull_exports));
38359
+ await pullCommand3(args);
37285
38360
  break;
37286
38361
  }
37287
38362
  case "push": {