@wayai/cli 0.3.97 → 0.3.99

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -15,21 +15,58 @@ var __export = (target, all) => {
15
15
  __defProp(target, name, { get: all[name], enumerable: true });
16
16
  };
17
17
 
18
- // src/lib/redact.ts
19
- function redactSecrets(text) {
18
+ // src/lib/mask-secrets.ts
19
+ function valueEnd(text, from, isEnd) {
20
+ for (let i = from; i < text.length; i++) {
21
+ if (text[i] === "\\") {
22
+ i++;
23
+ continue;
24
+ }
25
+ if (isEnd(text[i])) return i;
26
+ }
27
+ return text.length;
28
+ }
29
+ function maskCredentialValues(text, keyRe, isValueEnd) {
30
+ keyRe.lastIndex = 0;
31
+ let out = "";
32
+ let copied = 0;
33
+ let match;
34
+ while ((match = keyRe.exec(text)) !== null) {
35
+ const valueStart = match.index + match[0].length;
36
+ keyRe.lastIndex = valueStart;
37
+ if (!isCredentialKey(match[1])) continue;
38
+ const end = valueEnd(text, valueStart, isValueEnd);
39
+ const value = text.slice(valueStart, end);
40
+ if (value.length === 0 || FULLY_MASKED_VALUE_RE.test(value)) continue;
41
+ out += text.slice(copied, valueStart) + "[REDACTED]";
42
+ copied = end;
43
+ keyRe.lastIndex = end;
44
+ }
45
+ return out + text.slice(copied);
46
+ }
47
+ function maskSecretsInMessage(text) {
20
48
  let out = text;
21
- for (const [pattern, replacement] of PATTERNS) {
22
- out = out.replace(pattern, replacement);
23
- }
24
- return out;
25
- }
26
- var PATTERNS;
27
- var init_redact = __esm({
28
- "src/lib/redact.ts"() {
49
+ for (const [pattern, replacement] of SHAPE_PATTERNS) out = out.replace(pattern, replacement);
50
+ out = maskCredentialValues(out, JSON_KEY_RE, isJsonValueEnd);
51
+ out = maskCredentialValues(out, QUERY_KEY_RE, isQueryValueEnd);
52
+ return out.replace(BASE64_RE, maskBase64);
53
+ }
54
+ var CREDENTIAL_KEY_RE, FULLY_MASKED_VALUE_RE, isCredentialKey, SHAPE_PATTERNS, JSON_KEY_RE, isJsonValueEnd, QUERY_KEY_RE, isQueryValueEnd, BASE64_RE, maskBase64;
55
+ var init_mask_secrets = __esm({
56
+ "src/lib/mask-secrets.ts"() {
29
57
  "use strict";
30
- PATTERNS = [
58
+ CREDENTIAL_KEY_RE = /token|secret|credential|password|passwd|api[_-]?key|authorization|private[_-]?key|session[_-]?id|cookie|jwt/i;
59
+ FULLY_MASKED_VALUE_RE = /^(?:Bearer\s+)?(?:way_|wst_)?\[REDACTED(?:_JWT|_BASE64)?\]$/;
60
+ isCredentialKey = (key) => CREDENTIAL_KEY_RE.test(key);
61
+ SHAPE_PATTERNS = [
31
62
  // JWTs (header.payload.signature) — WorkOS access/refresh tokens, OAuth JWTs.
32
63
  // Run first so a `Bearer <jwt>` collapses to the JWT placeholder.
64
+ //
65
+ // Deliberately NOT anchored with the lookbehind the base64 rule uses. It would
66
+ // make this linear (this rule is quadratic on a pathological `eyJeyJeyJ…` run),
67
+ // but it also NARROWS masking: `refresh-<jwt>` and `way_<jwt>` would stop
68
+ // matching and leak the token whole. Correctness of a redaction rule outranks
69
+ // its worst case on a body that has to be adversarial to hurt.
33
70
  [/eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, "[REDACTED_JWT]"],
34
71
  // way_ scoped API tokens (keyring/CI credentials). Leading \b avoids
35
72
  // over-redacting benign substrings (e.g. `gateway_config`); the charset is
@@ -40,6 +77,42 @@ var init_redact = __esm({
40
77
  // Authorization: Bearer <opaque token> (anything not already masked above).
41
78
  [/(Bearer\s+)[A-Za-z0-9._~+/=-]{8,}/gi, "$1[REDACTED]"]
42
79
  ];
80
+ JSON_KEY_RE = /"([A-Za-z0-9_.-]+)"\s*:\s*"/g;
81
+ isJsonValueEnd = (char) => char === '"';
82
+ QUERY_KEY_RE = /(?:^|[?#&;,\s"'])([A-Za-z0-9_.-]+)=/g;
83
+ isQueryValueEnd = (char) => char === "&" || char === ";" || char === '"' || /\s/.test(char);
84
+ BASE64_RE = // Padded base64 bodies (wrapped DEKs, HMAC secrets, service-account material)
85
+ // appearing outside any credential-named key — the shape the rules above miss.
86
+ //
87
+ // Base64 has no distinguishing charset: a bare `[A-Za-z0-9+/]{20,}` run also
88
+ // matches slash-separated paths (`hubs/production/agents/support`), 64-char DO
89
+ // hex ids, and ordinary long words — all debugging context, not secrets. Three
90
+ // constraints buy the precision instead:
91
+ // 1. Terminal `=` padding, which prose and paths don't carry.
92
+ // 2. Nothing base64-ish after the padding, so `?param=value` (where `=` is a
93
+ // separator, not padding) is excluded.
94
+ // 3. Not sitting immediately after `?` or `&`, where a run followed by `=` is
95
+ // a query parameter NAME. Constraints 2 and 3 are separate cases: `=value`
96
+ // vs. an empty value (`?someLongParamName=&next=1`), which 2 lets through.
97
+ // 4. The quad-length check below, for a run reached by neither 2 nor 3
98
+ // (`bad xxxxxxxxxxxxxxxxxxxxxx= here`).
99
+ // Runs last so `Bearer <base64>` still collapses to the Bearer placeholder.
100
+ //
101
+ // The trade: unpadded base64 (any input whose byte length is a multiple of 3)
102
+ // is NOT matched here — no marker distinguishes it from prose. It stays covered
103
+ // by the credential-key rules above, which is where such a value realistically
104
+ // reaches this module.
105
+ //
106
+ // The leading lookbehind (NOT \b) is what keeps this linear. `/` and `+` are
107
+ // non-word characters, so \b also fires *inside* a base64 run: on a body like
108
+ // `aaaa/aaaa/aaaa/…` every slash would start a fresh greedy scan of the rest of
109
+ // the string, which is quadratic (~5.5s on a 100KB body, vs ~1.3ms now). "No
110
+ // base64 char precedes this" is both the correct notion of a run's start and
111
+ // O(1) starts per run — and, unlike the JWT rule above, it narrows nothing:
112
+ // base64 embedded mid-run isn't decodable base64 anyway.
113
+ // {22,} + 1-2 pad chars => a 24-char floor, i.e. a 16-byte secret.
114
+ /(?<![A-Za-z0-9+/])(?<![?&])[A-Za-z0-9+/]{22,}={1,2}(?![A-Za-z0-9+/=])/g;
115
+ maskBase64 = (match) => match.length % 4 === 0 ? "[REDACTED_BASE64]" : match;
43
116
  }
44
117
  });
45
118
 
@@ -119,17 +192,17 @@ function initSentry(command2, version) {
119
192
  }
120
193
  }
121
194
  }
122
- if (value.value) value.value = redactSecrets(value.value);
195
+ if (value.value) value.value = maskSecretsInMessage(value.value);
123
196
  }
124
197
  }
125
198
  if (event.breadcrumbs) {
126
199
  for (const crumb of event.breadcrumbs) {
127
- if (crumb.message) crumb.message = redactSecrets(crumb.message);
200
+ if (crumb.message) crumb.message = maskSecretsInMessage(crumb.message);
128
201
  }
129
202
  }
130
203
  if (event.extra) {
131
204
  for (const [key, val] of Object.entries(event.extra)) {
132
- if (typeof val === "string") event.extra[key] = redactSecrets(val);
205
+ if (typeof val === "string") event.extra[key] = maskSecretsInMessage(val);
133
206
  }
134
207
  }
135
208
  return event;
@@ -165,11 +238,11 @@ function captureException2(error, context) {
165
238
  Sentry.captureException(error);
166
239
  });
167
240
  }
168
- function addApiBreadcrumb(method, path27) {
241
+ function addApiBreadcrumb(method, path28) {
169
242
  if (!initialized) return;
170
243
  Sentry.addBreadcrumb({
171
244
  category: "http",
172
- message: `${method} ${path27}`,
245
+ message: `${method} ${path28}`,
173
246
  level: "info"
174
247
  });
175
248
  }
@@ -199,7 +272,7 @@ var HARDCODED_DSN, initialized;
199
272
  var init_sentry = __esm({
200
273
  "src/lib/sentry.ts"() {
201
274
  "use strict";
202
- init_redact();
275
+ init_mask_secrets();
203
276
  init_network_error();
204
277
  HARDCODED_DSN = "https://ffe500121277babcabf32e5868f00f9e@o4510669417807872.ingest.us.sentry.io/4510960145465344";
205
278
  initialized = false;
@@ -225,15 +298,15 @@ var init_api_client = __esm({
225
298
  "src/lib/api-client.ts"() {
226
299
  "use strict";
227
300
  init_sentry();
228
- init_redact();
301
+ init_mask_secrets();
229
302
  RETRYABLE_BACKOFF_MS = [500, 1e3, 2e3];
230
303
  delay = (ms) => new Promise((resolve4) => setTimeout(resolve4, ms));
231
304
  ApiError = class extends Error {
232
305
  status;
233
306
  body;
234
- constructor(method, path27, status, body) {
235
- const safeBody = redactSecrets(body);
236
- super(`API request failed: ${method} ${path27} (${status}): ${safeBody}`);
307
+ constructor(method, path28, status, body) {
308
+ const safeBody = maskSecretsInMessage(body);
309
+ super(`API request failed: ${method} ${path28} (${status}): ${safeBody}`);
237
310
  this.name = "ApiError";
238
311
  this.status = status;
239
312
  this.body = safeBody;
@@ -381,8 +454,8 @@ var init_api_client = __esm({
381
454
  ...organizationId && { organization_id: organizationId }
382
455
  });
383
456
  }
384
- async lookup(path27, opts) {
385
- const params = new URLSearchParams({ path: path27 });
457
+ async lookup(path28, opts) {
458
+ const params = new URLSearchParams({ path: path28 });
386
459
  if (opts?.organizationId) params.set("organization_id", opts.organizationId);
387
460
  return this.request("GET", `/api/ci/lookup?${params.toString()}`);
388
461
  }
@@ -429,8 +502,11 @@ var init_api_client = __esm({
429
502
  async sendMessage(hubId, message, opts) {
430
503
  return this.request("POST", "/api/conversations/send-message", {
431
504
  hub_id: hubId,
432
- message,
433
- ...opts?.conversationId && { conversation_id: opts.conversationId }
505
+ // Omitted entirely when absent: the contract allows an attachment-only send,
506
+ // but `message: undefined` would still fail its `.min(1)` if serialized.
507
+ ...message && { message },
508
+ ...opts?.conversationId && { conversation_id: opts.conversationId },
509
+ ...opts?.attachments?.length && { attachments: opts.attachments }
434
510
  });
435
511
  }
436
512
  async deleteHistory(hubId, opts) {
@@ -779,9 +855,9 @@ var init_api_client = __esm({
779
855
  * sandbox for this conversation, or the blob was purged).
780
856
  */
781
857
  async downloadArchiveSandboxFs(hubId, conversationId) {
782
- const path27 = `/api/archive/${encodeURIComponent(hubId)}/conversations/${encodeURIComponent(conversationId)}/sandbox`;
783
- addApiBreadcrumb("GET", path27);
784
- const url = `${this.apiUrl}${path27}`;
858
+ const path28 = `/api/archive/${encodeURIComponent(hubId)}/conversations/${encodeURIComponent(conversationId)}/sandbox`;
859
+ addApiBreadcrumb("GET", path28);
860
+ const url = `${this.apiUrl}${path28}`;
785
861
  let response = await this.send(url, "GET");
786
862
  if (response.status === 401 && this.onUnauthorized) {
787
863
  let refreshed;
@@ -795,7 +871,7 @@ var init_api_client = __esm({
795
871
  }
796
872
  }
797
873
  if (!response.ok) {
798
- throw new ApiError("GET", path27, response.status, await response.text());
874
+ throw new ApiError("GET", path28, response.status, await response.text());
799
875
  }
800
876
  return new Uint8Array(await response.arrayBuffer());
801
877
  }
@@ -835,9 +911,9 @@ var init_api_client = __esm({
835
911
  `/api/admin/data-explorer/debug/observability/${encodeURIComponent(hubId)}/conversations/${encodeURIComponent(conversationId)}${qs}`
836
912
  );
837
913
  }
838
- async request(method, path27, body) {
839
- addApiBreadcrumb(method, path27);
840
- const url = `${this.apiUrl}${path27}`;
914
+ async request(method, path28, body) {
915
+ addApiBreadcrumb(method, path28);
916
+ const url = `${this.apiUrl}${path28}`;
841
917
  let refreshedOn401 = false;
842
918
  for (let retry = 0; ; retry++) {
843
919
  let response = await this.send(url, method, body);
@@ -861,7 +937,7 @@ var init_api_client = __esm({
861
937
  await delay(RETRYABLE_BACKOFF_MS[retry]);
862
938
  continue;
863
939
  }
864
- throw new ApiError(method, path27, response.status, errorBody);
940
+ throw new ApiError(method, path28, response.status, errorBody);
865
941
  }
866
942
  }
867
943
  /** Issue a single authenticated request with the client's current token. */
@@ -1296,8 +1372,8 @@ var init_parseUtil = __esm({
1296
1372
  init_errors();
1297
1373
  init_en();
1298
1374
  makeIssue = (params) => {
1299
- const { data, path: path27, errorMaps, issueData } = params;
1300
- const fullPath = [...path27, ...issueData.path || []];
1375
+ const { data, path: path28, errorMaps, issueData } = params;
1376
+ const fullPath = [...path28, ...issueData.path || []];
1301
1377
  const fullIssue = {
1302
1378
  ...issueData,
1303
1379
  path: fullPath
@@ -1608,11 +1684,11 @@ var init_types = __esm({
1608
1684
  init_parseUtil();
1609
1685
  init_util();
1610
1686
  ParseInputLazyPath = class {
1611
- constructor(parent, value, path27, key) {
1687
+ constructor(parent, value, path28, key) {
1612
1688
  this._cachedPath = [];
1613
1689
  this.parent = parent;
1614
1690
  this.data = value;
1615
- this._path = path27;
1691
+ this._path = path28;
1616
1692
  this._key = key;
1617
1693
  }
1618
1694
  get path() {
@@ -4996,10 +5072,40 @@ var init_zod = __esm({
4996
5072
  });
4997
5073
 
4998
5074
  // ../../packages/core/dist/index.js
5075
+ function isPublicIdentifier(value) {
5076
+ return UUID_RE.test(value) || HEX_RE.test(value) || WORKOS_ID_RE.test(value);
5077
+ }
5078
+ function redactTokenShapes(input) {
5079
+ return input.replace(TOKEN_RE, REDACTED).replace(PROVIDER_TOKEN_RE, `$1${REDACTED}`).replace(JSON_CREDENTIAL_RE, `$1"${REDACTED}"`).replace(QUERY_CREDENTIAL_RE, `$1${REDACTED}`);
5080
+ }
5081
+ function redactSecrets(value) {
5082
+ if (isPublicIdentifier(value)) {
5083
+ return value;
5084
+ }
5085
+ if (OPAQUE_SECRET_RE.test(value)) {
5086
+ return REDACTED;
5087
+ }
5088
+ if (BASE64_SECRET_RE.test(value) && BASE64_MARKER_RE.test(value)) {
5089
+ return REDACTED;
5090
+ }
5091
+ return redactTokenShapes(value);
5092
+ }
4999
5093
  function normalizeAuthType(raw) {
5000
5094
  if (VALID_AUTH_TYPES.has(raw)) return raw;
5001
5095
  return LEGACY_AUTH_TYPE_MAP[raw] ?? raw;
5002
5096
  }
5097
+ function jsonLengthOrNull(value) {
5098
+ try {
5099
+ const json = JSON.stringify(value);
5100
+ return typeof json === "string" ? json.length : null;
5101
+ } catch {
5102
+ return null;
5103
+ }
5104
+ }
5105
+ function withinJsonLength(value, max) {
5106
+ const length = jsonLengthOrNull(value);
5107
+ return length !== null && length <= max;
5108
+ }
5003
5109
  function visibleLength(s) {
5004
5110
  return s.replace(INVISIBLE_NAME_CHARS, "").length;
5005
5111
  }
@@ -5066,12 +5172,12 @@ function typeMatches(typeField, allowed) {
5066
5172
  if (Array.isArray(typeField)) return typeField.every((t) => typeof t === "string" && allowed.has(t));
5067
5173
  return false;
5068
5174
  }
5069
- function validateSchema(schema, path27, errors, opts = {}) {
5175
+ function validateSchema(schema, path28, errors, opts = {}) {
5070
5176
  if (typeof schema === "boolean") return;
5071
5177
  const depth = opts.depth ?? 0;
5072
5178
  if (depth > MAX_SCHEMA_DEPTH) {
5073
5179
  errors.push({
5074
- path: path27 || "<root>",
5180
+ path: path28 || "<root>",
5075
5181
  message: `schema nesting exceeds ${MAX_SCHEMA_DEPTH} levels`,
5076
5182
  suggestion: "Flatten the schema; LLM providers reject deeply nested tool input_schemas."
5077
5183
  });
@@ -5079,7 +5185,7 @@ function validateSchema(schema, path27, errors, opts = {}) {
5079
5185
  }
5080
5186
  if (!isRecord(schema)) {
5081
5187
  errors.push({
5082
- path: path27,
5188
+ path: path28,
5083
5189
  message: `expected object, got ${schema === null ? "null" : typeof schema}`
5084
5190
  });
5085
5191
  return;
@@ -5087,14 +5193,14 @@ function validateSchema(schema, path27, errors, opts = {}) {
5087
5193
  if (opts.isRoot) {
5088
5194
  if ("type" in schema && schema.type !== "object") {
5089
5195
  errors.push({
5090
- path: path27 ? `${path27}.type` : "type",
5196
+ path: path28 ? `${path28}.type` : "type",
5091
5197
  message: `root type must be 'object', got ${JSON.stringify(schema.type)}`,
5092
5198
  suggestion: "Tool parameters at the root must be an object: `{ type: 'object', properties: { ... } }`."
5093
5199
  });
5094
5200
  }
5095
5201
  } else if ("type" in schema && !typeMatches(schema.type, ALLOWED_TYPES)) {
5096
5202
  errors.push({
5097
- path: `${path27}.type`,
5203
+ path: `${path28}.type`,
5098
5204
  message: `type must be one of ${[...ALLOWED_TYPES].join("/")} or an array of those, got ${JSON.stringify(schema.type)}`
5099
5205
  });
5100
5206
  }
@@ -5103,25 +5209,25 @@ function validateSchema(schema, path27, errors, opts = {}) {
5103
5209
  if (typeof e === "string") {
5104
5210
  const isPlaceholder = PLACEHOLDER_TOKENS.includes(e);
5105
5211
  errors.push({
5106
- path: `${path27}.enum`,
5212
+ path: `${path28}.enum`,
5107
5213
  message: `enum must be a non-empty array of primitives, got string ${JSON.stringify(e)}`,
5108
5214
  suggestion: 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"]`.'
5109
5215
  });
5110
5216
  } else if (!Array.isArray(e)) {
5111
5217
  errors.push({
5112
- path: `${path27}.enum`,
5218
+ path: `${path28}.enum`,
5113
5219
  message: `enum must be a non-empty array of primitives, got ${typeof e}`
5114
5220
  });
5115
5221
  } else if (e.length === 0) {
5116
5222
  errors.push({
5117
- path: `${path27}.enum`,
5223
+ path: `${path28}.enum`,
5118
5224
  message: "enum must not be empty"
5119
5225
  });
5120
5226
  } else {
5121
5227
  for (let i = 0; i < e.length; i++) {
5122
5228
  if (!isPrimitive(e[i])) {
5123
5229
  errors.push({
5124
- path: `${path27}.enum[${i}]`,
5230
+ path: `${path28}.enum[${i}]`,
5125
5231
  message: `enum entry must be a primitive (string/number/boolean/null), got ${typeof e[i]}`
5126
5232
  });
5127
5233
  }
@@ -5131,7 +5237,7 @@ function validateSchema(schema, path27, errors, opts = {}) {
5131
5237
  for (const key of ["exclusiveMinimum", "exclusiveMaximum"]) {
5132
5238
  if (key in schema && typeof schema[key] === "boolean") {
5133
5239
  errors.push({
5134
- path: `${path27}.${key}`,
5240
+ path: `${path28}.${key}`,
5135
5241
  message: `${key} as boolean is draft-04 syntax; draft 2020-12 requires a numeric value`,
5136
5242
  suggestion: `Replace with the numeric bound, e.g. \`${key}: 0\`.`
5137
5243
  });
@@ -5140,45 +5246,45 @@ function validateSchema(schema, path27, errors, opts = {}) {
5140
5246
  if ("properties" in schema) {
5141
5247
  if (!isRecord(schema.properties)) {
5142
5248
  errors.push({
5143
- path: `${path27}.properties`,
5249
+ path: `${path28}.properties`,
5144
5250
  message: `properties must be an object, got ${Array.isArray(schema.properties) ? "array" : typeof schema.properties}`
5145
5251
  });
5146
5252
  } else {
5147
5253
  for (const [propName, propSchema] of Object.entries(schema.properties)) {
5148
- validateSchema(propSchema, `${path27}.properties.${propName}`, errors, { depth: depth + 1 });
5254
+ validateSchema(propSchema, `${path28}.properties.${propName}`, errors, { depth: depth + 1 });
5149
5255
  }
5150
5256
  }
5151
5257
  }
5152
5258
  if (schemaTypeIncludes(schema, "array") && "items" in schema) {
5153
5259
  if (Array.isArray(schema.items)) {
5154
- schema.items.forEach((sub, i) => validateSchema(sub, `${path27}.items[${i}]`, errors, { depth: depth + 1 }));
5260
+ schema.items.forEach((sub, i) => validateSchema(sub, `${path28}.items[${i}]`, errors, { depth: depth + 1 }));
5155
5261
  } else {
5156
- validateSchema(schema.items, `${path27}.items`, errors, { depth: depth + 1 });
5262
+ validateSchema(schema.items, `${path28}.items`, errors, { depth: depth + 1 });
5157
5263
  }
5158
5264
  }
5159
5265
  for (const key of SUBSCHEMA_OBJECT_KEYWORDS) {
5160
5266
  if (key in schema && isRecord(schema[key])) {
5161
- validateSchema(schema[key], `${path27}.${key}`, errors, { depth: depth + 1 });
5267
+ validateSchema(schema[key], `${path28}.${key}`, errors, { depth: depth + 1 });
5162
5268
  }
5163
5269
  }
5164
5270
  for (const key of SUBSCHEMA_LIST_KEYWORDS) {
5165
5271
  const list = schema[key];
5166
5272
  if (Array.isArray(list)) {
5167
- list.forEach((sub, i) => validateSchema(sub, `${path27}.${key}[${i}]`, errors, { depth: depth + 1 }));
5273
+ list.forEach((sub, i) => validateSchema(sub, `${path28}.${key}[${i}]`, errors, { depth: depth + 1 }));
5168
5274
  }
5169
5275
  }
5170
5276
  for (const key of SUBSCHEMA_MAP_KEYWORDS) {
5171
5277
  const map = schema[key];
5172
5278
  if (isRecord(map)) {
5173
5279
  for (const [name, sub] of Object.entries(map)) {
5174
- validateSchema(sub, `${path27}.${key}.${name}`, errors, { depth: depth + 1 });
5280
+ validateSchema(sub, `${path28}.${key}.${name}`, errors, { depth: depth + 1 });
5175
5281
  }
5176
5282
  }
5177
5283
  }
5178
5284
  const reportedPaths = new Set(errors.map((e) => e.path));
5179
5285
  for (const [k, v] of Object.entries(schema)) {
5180
5286
  if (typeof v !== "string") continue;
5181
- const fieldPath = `${path27}.${k}`;
5287
+ const fieldPath = `${path28}.${k}`;
5182
5288
  if (reportedPaths.has(fieldPath)) continue;
5183
5289
  for (const token of PLACEHOLDER_TOKENS) {
5184
5290
  if (v === token) {
@@ -5243,6 +5349,45 @@ function refineToolConfig(value, ctx) {
5243
5349
  }
5244
5350
  }
5245
5351
  }
5352
+ function describeRole(role) {
5353
+ if (typeof role === "string") {
5354
+ return JSON.stringify(role.length > ROLE_ECHO_MAX ? `${role.slice(0, ROLE_ECHO_MAX)}\u2026` : role);
5355
+ }
5356
+ if (role === null) return "null";
5357
+ if (Array.isArray(role)) return "an array";
5358
+ if (typeof role === "object") return "an object";
5359
+ return `a ${typeof role}`;
5360
+ }
5361
+ function asEvalInputRecord(input) {
5362
+ const value = typeof input === "string" ? (() => {
5363
+ try {
5364
+ return JSON.parse(input);
5365
+ } catch {
5366
+ return null;
5367
+ }
5368
+ })() : input;
5369
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
5370
+ }
5371
+ function evalInputRoleError(input) {
5372
+ const record = asEvalInputRecord(input);
5373
+ if (record === null) return null;
5374
+ const role = record.role;
5375
+ if (role === void 0 || role === null) return null;
5376
+ if (typeof role === "string" && EVAL_INPUT_ROLES.includes(role)) {
5377
+ return null;
5378
+ }
5379
+ return `role must be ${EVAL_INPUT_ROLE_LIST} (received ${describeRole(role)}) \u2014 an eval trigger is what the responder answers, and an assistant or tool role gives it nothing to answer`;
5380
+ }
5381
+ function refineEvalMessageTextRole(value, ctx) {
5382
+ const error = evalInputRoleError(value.eval.message_text);
5383
+ if (error) {
5384
+ ctx.addIssue({
5385
+ code: external_exports.ZodIssueCode.custom,
5386
+ path: ["eval", "message_text", "role"],
5387
+ message: error
5388
+ });
5389
+ }
5390
+ }
5246
5391
  function refineHubAsCodeCustomTools(config, ctx) {
5247
5392
  const agents = config.agents;
5248
5393
  if (!Array.isArray(agents)) return;
@@ -5334,10 +5479,26 @@ function refineHubAsCodeLanes(config, ctx) {
5334
5479
  }
5335
5480
  }
5336
5481
  }
5337
- function isSafeTemplatePath(path27) {
5338
- if (path27.length === 0 || path27.length > 300) return false;
5339
- if (path27.startsWith("/") || path27.includes("\\")) return false;
5340
- const segments = path27.split("/");
5482
+ function refineHubAsCodeEvals(config, ctx) {
5483
+ const evals = config.evals;
5484
+ if (!Array.isArray(evals)) return;
5485
+ for (let e = 0; e < evals.length; e++) {
5486
+ const entry = evals[e];
5487
+ const error = evalInputRoleError(entry?.input);
5488
+ if (error) {
5489
+ ctx.addIssue({
5490
+ code: external_exports.ZodIssueCode.custom,
5491
+ path: ["evals", e, "input", "role"],
5492
+ // Named, not just indexed — the YAML author has files, not an array.
5493
+ message: `eval "${entry?.name ?? "<unnamed>"}": ${error}`
5494
+ });
5495
+ }
5496
+ }
5497
+ }
5498
+ function isSafeTemplatePath(path28) {
5499
+ if (path28.length === 0 || path28.length > 300) return false;
5500
+ if (path28.startsWith("/") || path28.includes("\\")) return false;
5501
+ const segments = path28.split("/");
5341
5502
  return segments.every(
5342
5503
  (seg) => seg.length > 0 && seg !== "." && seg !== ".." && /^[A-Za-z0-9._-]+$/.test(seg)
5343
5504
  );
@@ -5407,7 +5568,7 @@ function findStepBoundaries(transcript) {
5407
5568
  }
5408
5569
  return out;
5409
5570
  }
5410
- var APP_ERROR_BRAND, AppError, LLM_RATE_LIMIT_BRAND, LlmRateLimitError, LLM_PROVIDER_HTTP_BRAND, LlmProviderHttpError, LLM_PROVIDER_TIMEOUT_BRAND, LlmProviderTimeoutError, ExternalServiceError, CHANNEL_PROVIDER_HTTP_BRAND, ChannelProviderHttpError, MEDIA_PROVIDER_HTTP_BRAND, MediaProviderHttpError, AUTH_TYPE, ORG_CREDENTIAL_AUTH_TYPES, AUTH_TYPE_DISPLAY, LEGACY_AUTH_TYPE_MAP, VALID_AUTH_TYPES, AGENT_ROLES, SAFE_USER_ID_REGEX, SUPPORTED_LOCALES, uuidSchema, paginationSchema, timestampSchema, idParamSchema, primaryRegionSchema, placementSourceSchema, orgIdParam, orgAdminIdParam, createOrganizationBody, updateOrganizationBody, addOrgAdminBody, SUMMARIZATION_THRESHOLD_MIN, SUMMARIZATION_THRESHOLD_MAX, summarizationThresholdField, monitorConfigField, agentIdParam, listAgentsQuery, agentConnectionsQuery, createAgentBody, updateAgentBody, AGENT_PARAMETER_TYPES, AGENT_PARAMETER_NAME_REGEX, agentParameterCreateSchema, MAX_AGENT_PARAMETERS_PER_REQUEST, createAgentParametersBody, SLUG_REGEX, slugSchema, INVISIBLE_NAME_CHARS, MAX_KANBAN_STATUSES, MAX_FOLLOWUPS_PER_STATUS, MAX_LANES, MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES, RESERVED_TEMPLATE_DUMP_NAME, kanbanStatusSlugSchema, followupSchema, EXCLUSIVE_FLAG_PAIRS, kanbanStatusSchema, kanbanStatusesArraySchema, laneSchema, lanesArraySchema, hubIdParam, hubAdminIdParam, hubUserIdParam, hubIdentityIdParam, hubTeamIdParam, hubTeamUserDeleteParam, hubSchemaQuery, PREVIEW_LABEL_MAX_LENGTH, MAX_ENDED_INDEX_RETENTION_DAYS, previewLabelField, createHubBody, updateHubBody, addHubAdminBody, addHubIdentityAuthorizationBody, contactDecisionBody, approveContactBody, listContactAccessQuery, createHubTeamBody, updateHubTeamBody, addHubTeamUserBody, reassignHubUserBody, replicatePreviewBody, claimCodeChannelParam, claimCodeDeleteParam, connectionIdParam, connectorIdParam, listConnectionsQuery, deleteConnectionQuery, addConnectionBody, editConnectionBody, PRODUCTION_DIRECT_FIELDS, setProductionCredentialBody, registerWhatsappQuery, registerWhatsappBody, retryProvisioningQuery, resendDomainStatusQuery, PLACEHOLDER_TOKENS, ALLOWED_TYPES, SUBSCHEMA_OBJECT_KEYWORDS, SUBSCHEMA_LIST_KEYWORDS, SUBSCHEMA_MAP_KEYWORDS, MAX_SCHEMA_DEPTH, toolIdParam, listToolsQuery, toolAgentQuery, deleteToolQuery, toolConnectionsQuery, nativeToolIdSchema, addNativeToolBody, addMcpToolBody, createCustomToolBody, updateCustomToolBody, updateToolExecutionConfigBody, initialValueCreateSchema, initialValueUpdateSchema, stateIdParam, listStatesQuery, stateNameSchema, createStateBody, updateStateBody, reorderStatesBody, variantAiModeSchema, experimentStatusSchema, overlayUpdateSchema, experimentIdParam, variantIdParam, listExperimentsQuery, listVariantsQuery, listOverridesQuery, deleteOverrideQuery, createExperimentBody, updateExperimentBody, setExperimentStatusBody, createVariantBody, updateVariantBody, upsertOverrideBody, orgTagIdParam, listOrgTagsQuery, createOrgTagBody, updateOrgTagBody, orgCredentialIdParam, listOrgCredentialsQuery, createOrgCredentialBody, updateOrgCredentialBody, orgResourceIdParam, orgResourceFileIdParam, orgResourceFolderIdParam, hubOrgResourceParam, listOrgResourcesQuery, orgIdQuery, createOrgResourceBody, updateOrgResourceBody, createOrgResourceFolderBody, updateOrgResourceFolderBody, uploadOrgResourceFileBody, updateOrgResourceFileBody, uploadOrgSkillZipBody, linkOrgResourceBody, resourceIdParam, listResourcesQuery, createResourceBody, updateResourceBody, syncSkillsBody, resourceFileIdParam, listResourceFilesQuery, createResourceFileBody, updateResourceFileBody, uploadResourceFileBody, uploadSkillZipBody, resourceFolderIdParam, listResourceFoldersQuery, createResourceFolderBody, updateResourceFolderBody, agentResourceQuery, hubResourceQuery, linkAgentResourceBody, updateAgentResourceBody, unlinkAgentResourceQuery, navItemSchema, hubCountResetBody, navItemCountResetBody, typingBody, analyticsHubIdParam, analyticsVariableIdParam, updateVariablePinBody, updateAnalyticsViewBody, NUMERIC_FILTER_OPS, TEXT_FILTER_OPS, CATEGORICAL_FILTER_OPS, VARIABLE_FILTER_OPS, STRUCTURED_QUERY_OPS, STRUCTURED_QUERY_AGGREGATIONS, filterValueSchema, conversationsBody, analyticsConversationIdParam, messagesQuery, conversationDetailDataQuery, analyticsDataBody, structuredQueryBody, analyticsSqlBody, analyticsSqlSchemaQuery, EVAL_PACING_PRESET_NAMES, PACING_INTERVAL_MIN_MS, PACING_INTERVAL_MAX_MS, EVAL_RUN_DEADLINE_MIN_MS, EVAL_RUN_DEADLINE_MAX_MS, paginationSchema2, evalIdParam, sessionIdParam, scenarioSetIdParam, hubIdQuery, createEvalBody, updateEvalBody, getEvalsQuery, toggleEvalBody, bulkToggleEvalsBody, pacingConfigSchema, sessionConfigSchema, createSessionBody, getSessionsQuery, getSessionResultsQuery, getSessionRunsQuery, evalAnalyticsQuery, getSessionCostQuery, compareSessionsQuery, evalsSqlBody, evalsSqlSchemaQuery, exportResultsQuery, validateEvalBody, hubAgentsQuery, createScenarioSetBody, updateScenarioSetBody, scenarioSetsHubQuery, createScenarioFromConversationBody, createJourneyFromConversationBody, journeyIdParam, journeyToolCallSchema, journeyTurnSchema, journeyStepOverrideSchema, fixtureField, createJourneyBody, updateJourneyBody, getConversationsQuery, getMessagesQuery, clientOptionalString, clientOptionalBoolean, appMessageSenderType, appMessageReceiverType, appMessageAttachment, MAX_ATTACHMENTS_PER_MESSAGE, appMessageBody, updateUserBody, updateProfileBody, pathnameRegex, updatePreferencesBody, registerPushTokenBody, deletePushTokenQuery, activityQuery, deletionModeSchema, deletionRequestBody, archiveHubIdParam, archiveConversationParams, archiveListQuery, archiveMessageObservabilityParams, conversationIdParam, claimBody, releaseBody, transferBody, closeBody, additionalContextPayloadSchema, kanbanUpdateBody, annotateConversationBody, observabilityParams, observabilityListParams, deleteUserConversationsBody, sendMessageBody, listConversationsQuery, getConversationDetailParams, getConversationDetailQuery, listWhatsAppTemplatesQuery, sendWhatsAppTemplateBody, billingOrgIdParam, subscriptionItemParams, spendCapBody, growthPacksBody, portalSessionBody, checkoutSessionBody, updateBillingCurrencyBody, invoicesQuery, downloadBody, uploadQuery, signUrlBody, outboundSchemaQuery, templateIdParam, listTemplatesQuery, deleteTemplateQuery, templateStatusQuery, createTemplateBody, updateTemplateBody, submitTemplateBody, testTemplateBody, contactIdParam, listContactsQuery, createContactBody, updateContactBody, listIdParam, listListsQuery, listListContactsQuery, createListBody, updateListBody, addListContactsBody, removeListContactsBody, scheduleIdParam, listSchedulesQuery, listExecutionsQuery, createScheduleBody, updateScheduleBody, uuidPattern, ciUuidSchema, hubAsCodeConfigSchema, ciPullHubIdParam, ciBranchParam, ciPullQuery, ciHubsQuery, ciLookupQuery, ciBranchesQuery, ciSyncBody, ciPushBody, ciDiffBody, ciPublishBody, ciPublishPreviewBody, ciSyncMcpBody, ciOrgResourcesParam, orgResourcesConfigSchema, ciOrgResourcesPushBody, ciOrgResourcesDiffBody, adminOrgIdParam, adminOrgAdminIdParam, adminUserIdParam, adminPlanIdParam, adminHubIdParam, adminOrganizationsQuery, adminUserSearchQuery, kanbanSlugMigrationQuery, adjustQuotaBody, updatePlanBody, addAdminUserBody, updatePlatformConfigBody, updateFreeOrgLimitBody, adminSetOrgHarnessBody, adminSetHubHarnessBody, adminScopedTargetBody, updatePricingPlanBody, dataExplorerSearchQuery, dataExplorerOrgIdParam, dataExplorerHubIdParam, dataExplorerConvIdParam, dataExplorerDoInstancesQuery, dataExplorerNsIdParam, dataExplorerKvKeysQuery, dataExplorerKvKeyParam, uuidOrHexId, dataExplorerDeleteOrgParam, dataExplorerDeleteHubParam, dataExplorerDeleteConvParam, dataExplorerDeleteUserParam, dataExplorerDeleteQuery, dataExplorerKvDeleteQuery, pitrDoNamespace, pitrBookmarkParam, pitrRestoreBody, healthSamplingTriggerBody, dataExplorerDebugDoType, DEBUG_READ_MAX_LIMIT, DEBUG_READ_DEFAULT_LIMIT, DEBUG_DO_HEX_PREFIX, debugDoEntityId, debugTableName, dataExplorerDebugTablesParam, dataExplorerDebugRowsParam, dataExplorerDebugRowsQuery, dataExplorerDebugAnalyticsTable, debugUuid, dataExplorerDebugAnalyticsRowsParam, dataExplorerDebugAnalyticsRowsQuery, debugHubConvParam, debugMessageIdQuery, sandboxEgressPolicy, SANDBOX_EXEC_MAX_CMD_LENGTH, SANDBOX_EXEC_MAX_ALLOWLIST, SANDBOX_EXEC_MAX_TIMEOUT_MS, adminSandboxExecBody, whatsappCallbackBody, authMeResponse, wsTicketResponse, sessionCheckResponse, logoutResponse, magicCodeSendBody, magicCodeSendResponse, magicCodeVerifyBody, magicCodeVerifyResponse, browserParams, browserFoldersQuery, browserFilesQuery, stateOperationBody, conversationListResourcesQuery, conversationReadResourceQuery, listPendingSchedulesQuery, listHubAggregateSchedulesQuery, reportSourceSchema, intakeReportSourceSchema, reportClassificationSchema, reportStatusSchema, reportLocaleSchema, reportMessageAuthorRoleSchema, sentryRefStatusSchema, createReportBody, editReportBody, contestReportBody, reporterListQuery, listReportsQuery, GITHUB_ISSUE_URL_REGEX, githubIssueUrlSchema, transitionReportBody, groupReportsBody, holdReportBody, clickhouseReadyResponse, bootstrapQuery, requestSnapshotChunkMessage, MAX_NAME_LENGTH, MAX_VALUE_LENGTH, MAX_TAGS, MAX_TAG_LENGTH, MAX_SCOPE_HUBS, MAX_SCOPE_TAGS, vaultSecretScopeSchema, vaultCreateBody, vaultUpdateBody, PERMISSIONS, MAX_NAME_LENGTH2, MAX_HUBS_PER_GRANT, MAX_HUB_TAGS_PER_GRANT, MAX_GRANTS, permissionEnum, grantScopeSchema, grantSchema, createTokenBody, tokenOrgIdParam, tokenGrantScopeSchema, tokenGrantSchema, tokenMetadataSchema, listTokensResponse, createTokenResponse, orgTokenSummarySchema, listOrgTokensResponse, invitePreviewQuery, invitePreviewResponse, discordTier, discordBillingCycle, discordMetadata, discordOAuthStartResponse, discordOAuthFinalizeBody, discordOAuthFinalizeResponse, discordDisconnectResponse, jsonSchemaSchema, hubUserIdentity, stateValueEntry, getHubUserContextResponse, updateHubUserBody, updateHubUserResponse, unlockHubUserNameResponse, stateResetParams, stateResetResponse, hubAlertsParam, hubAlertSeverity, hubAlert, hubAlertsListResponse, noticeSeveritySchema, noticeStatusSchema, NOTICE_SCOPE_REGEX, noticeScopeSchema, noticeLinkSchema, createNoticeBody, updateNoticeBody, listNoticesQuery, noticeIdParamSchema, templateLocaleSchema, TEMPLATE_SLUG_REGEX, templateSlugSchema, templateStatusSchema, templateFileMapSchema, templateTextSchema, templateUsesEntrySchema, templateUsesSchema, templateYamlLocaleEntry, templateYamlWayaiBlock, templateTagsSchema, templateYamlSchema, templateHeroSchema, templatePushLocaleSchema, templatePushBody, templateListQuery, templateSlugParam, templateDetailQuery, ADMIN_SKILL_NAME_REGEX, adminSkillNameParam, WAYAI_WORKSPACE_LAYOUT, MAX_RESOURCE_FILE_SIZE;
5571
+ var UUID_RE, HEX_RE, WORKOS_ID_RE, OPAQUE_SECRET_RE, BASE64_SECRET_RE, BASE64_MARKER_RE, TOKEN_RE, SENSITIVE_FIELDS, SENSITIVE_KEY_ALTERNATION, SENSITIVE_KEY_PATTERN, JSON_CREDENTIAL_RE, QUERY_CREDENTIAL_RE, REDACTED, PROVIDER_TOKEN_RE, APP_ERROR_BRAND, AppError, LLM_RATE_LIMIT_BRAND, LlmRateLimitError, LLM_PROVIDER_HTTP_BRAND, LlmProviderHttpError, LLM_PROVIDER_TIMEOUT_BRAND, LlmProviderTimeoutError, ExternalServiceError, CHANNEL_PROVIDER_HTTP_BRAND, ChannelProviderHttpError, MEDIA_PROVIDER_HTTP_BRAND, MediaProviderHttpError, AUTH_TYPE, ORG_CREDENTIAL_AUTH_TYPES, AUTH_TYPE_DISPLAY, LEGACY_AUTH_TYPE_MAP, VALID_AUTH_TYPES, AGENT_ROLES, SAFE_USER_ID_REGEX, SUPPORTED_LOCALES, uuidSchema, paginationSchema, timestampSchema, idParamSchema, clientOptionalString, clientOptionalBoolean, clientOptionalNumber, messageAttachment, MAX_MESSAGE_BODY_BYTES, MAX_ATTACHMENTS_PER_MESSAGE, primaryRegionSchema, placementSourceSchema, orgIdParam, orgAdminIdParam, createOrganizationBody, updateOrganizationBody, addOrgAdminBody, SUMMARIZATION_THRESHOLD_MIN, SUMMARIZATION_THRESHOLD_MAX, summarizationThresholdField, monitorConfigField, agentIdParam, listAgentsQuery, agentConnectionsQuery, createAgentBody, updateAgentBody, AGENT_PARAMETER_TYPES, AGENT_PARAMETER_NAME_REGEX, agentParameterCreateSchema, MAX_AGENT_PARAMETERS_PER_REQUEST, createAgentParametersBody, SLUG_REGEX, slugSchema, INVISIBLE_NAME_CHARS, MAX_KANBAN_STATUSES, MAX_FOLLOWUPS_PER_STATUS, MAX_LANES, MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES, RESERVED_TEMPLATE_DUMP_NAME, kanbanStatusSlugSchema, followupSchema, EXCLUSIVE_FLAG_PAIRS, kanbanStatusSchema, kanbanStatusesArraySchema, laneSchema, lanesArraySchema, hubIdParam, hubAdminIdParam, hubUserIdParam, hubIdentityIdParam, hubTeamIdParam, hubTeamUserDeleteParam, hubSchemaQuery, PREVIEW_LABEL_MAX_LENGTH, MAX_ENDED_INDEX_RETENTION_DAYS, previewLabelField, createHubBody, updateHubBody, addHubAdminBody, addHubIdentityAuthorizationBody, contactDecisionBody, approveContactBody, listContactAccessQuery, createHubTeamBody, updateHubTeamBody, addHubTeamUserBody, reassignHubUserBody, replicatePreviewBody, updateChannelTestIdentitiesBody, claimCodeChannelParam, claimCodeDeleteParam, connectionIdParam, connectorIdParam, listConnectionsQuery, deleteConnectionQuery, addConnectionBody, editConnectionBody, PRODUCTION_DIRECT_FIELDS, setProductionCredentialBody, registerWhatsappQuery, registerWhatsappBody, retryProvisioningQuery, resendDomainStatusQuery, PLACEHOLDER_TOKENS, ALLOWED_TYPES, SUBSCHEMA_OBJECT_KEYWORDS, SUBSCHEMA_LIST_KEYWORDS, SUBSCHEMA_MAP_KEYWORDS, MAX_SCHEMA_DEPTH, toolIdParam, listToolsQuery, toolAgentQuery, deleteToolQuery, toolConnectionsQuery, nativeToolIdSchema, addNativeToolBody, addMcpToolBody, createCustomToolBody, updateCustomToolBody, updateToolExecutionConfigBody, initialValueCreateSchema, initialValueUpdateSchema, stateIdParam, listStatesQuery, stateNameSchema, createStateBody, updateStateBody, reorderStatesBody, variantAiModeSchema, experimentStatusSchema, overlayUpdateSchema, experimentIdParam, variantIdParam, listExperimentsQuery, listVariantsQuery, listOverridesQuery, deleteOverrideQuery, createExperimentBody, updateExperimentBody, setExperimentStatusBody, createVariantBody, updateVariantBody, upsertOverrideBody, orgTagIdParam, listOrgTagsQuery, createOrgTagBody, updateOrgTagBody, orgCredentialIdParam, listOrgCredentialsQuery, createOrgCredentialBody, updateOrgCredentialBody, orgResourceIdParam, orgResourceFileIdParam, orgResourceFolderIdParam, hubOrgResourceParam, listOrgResourcesQuery, orgIdQuery, createOrgResourceBody, updateOrgResourceBody, createOrgResourceFolderBody, updateOrgResourceFolderBody, uploadOrgResourceFileBody, updateOrgResourceFileBody, uploadOrgSkillZipBody, linkOrgResourceBody, resourceIdParam, listResourcesQuery, createResourceBody, updateResourceBody, syncSkillsBody, resourceFileIdParam, listResourceFilesQuery, createResourceFileBody, updateResourceFileBody, uploadResourceFileBody, uploadSkillZipBody, resourceFolderIdParam, listResourceFoldersQuery, createResourceFolderBody, updateResourceFolderBody, agentResourceQuery, hubResourceQuery, linkAgentResourceBody, updateAgentResourceBody, unlinkAgentResourceQuery, navItemSchema, hubCountResetBody, navItemCountResetBody, typingBody, analyticsHubIdParam, analyticsVariableIdParam, updateVariablePinBody, updateAnalyticsViewBody, NUMERIC_FILTER_OPS, TEXT_FILTER_OPS, CATEGORICAL_FILTER_OPS, VARIABLE_FILTER_OPS, STRUCTURED_QUERY_OPS, STRUCTURED_QUERY_AGGREGATIONS, filterValueSchema, conversationsBody, analyticsConversationIdParam, messagesQuery, conversationDetailDataQuery, analyticsDataBody, structuredQueryBody, analyticsSqlBody, analyticsSqlSchemaQuery, EVAL_PACING_PRESET_NAMES, PACING_INTERVAL_MIN_MS, PACING_INTERVAL_MAX_MS, EVAL_RUN_DEADLINE_MIN_MS, EVAL_RUN_DEADLINE_MAX_MS, paginationSchema2, evalIdParam, sessionIdParam, scenarioSetIdParam, hubIdQuery, EVAL_INPUT_ROLES, EVAL_INPUT_ROLE_LIST, ROLE_ECHO_MAX, createEvalBody, updateEvalBody, getEvalsQuery, toggleEvalBody, bulkToggleEvalsBody, pacingConfigSchema, sessionConfigSchema, createSessionBody, getSessionsQuery, getSessionResultsQuery, getSessionRunsQuery, evalAnalyticsQuery, getSessionCostQuery, compareSessionsQuery, evalsSqlBody, evalsSqlSchemaQuery, exportResultsQuery, validateEvalBody, hubAgentsQuery, createScenarioSetBody, updateScenarioSetBody, scenarioSetsHubQuery, createScenarioFromConversationBody, createJourneyFromConversationBody, journeyIdParam, journeyToolCallSchema, journeyTurnSchema, journeyStepOverrideSchema, fixtureField, createJourneyBody, updateJourneyBody, getConversationsQuery, getMessagesQuery, appMessageSenderType, appMessageReceiverType, appMessageBody, updateUserBody, updateProfileBody, pathnameRegex, updatePreferencesBody, registerPushTokenBody, deletePushTokenQuery, activityQuery, deletionModeSchema, deletionRequestBody, archiveHubIdParam, archiveConversationParams, archiveListQuery, archiveMessageObservabilityParams, conversationIdParam, claimBody, releaseBody, transferBody, closeBody, additionalContextPayloadSchema, kanbanUpdateBody, annotateConversationBody, observabilityParams, observabilityListParams, deleteUserConversationsBody, sendMessageBody, listConversationsQuery, getConversationDetailParams, getConversationDetailQuery, listWhatsAppTemplatesQuery, sendWhatsAppTemplateBody, billingOrgIdParam, subscriptionItemParams, spendCapBody, growthPacksBody, portalSessionBody, checkoutSessionBody, updateBillingCurrencyBody, invoicesQuery, downloadBody, uploadQuery, signUrlBody, outboundSchemaQuery, templateIdParam, listTemplatesQuery, deleteTemplateQuery, templateStatusQuery, createTemplateBody, updateTemplateBody, submitTemplateBody, testTemplateBody, contactIdParam, listContactsQuery, createContactBody, updateContactBody, listIdParam, listListsQuery, listListContactsQuery, createListBody, updateListBody, addListContactsBody, removeListContactsBody, scheduleIdParam, listSchedulesQuery, listExecutionsQuery, createScheduleBody, updateScheduleBody, uuidPattern, ciUuidSchema, hubAsCodeConfigSchema, ciPullHubIdParam, ciBranchParam, ciPullQuery, ciHubsQuery, ciLookupQuery, ciBranchesQuery, ciSyncBody, ciPushBody, ciDiffBody, ciPublishBody, ciPublishPreviewBody, ciSyncMcpBody, ciOrgResourcesParam, orgResourcesConfigSchema, ciOrgResourcesPushBody, ciOrgResourcesDiffBody, adminOrgIdParam, adminOrgAdminIdParam, adminUserIdParam, adminPlanIdParam, adminHubIdParam, adminOrganizationsQuery, adminUserSearchQuery, kanbanSlugMigrationQuery, adjustQuotaBody, updatePlanBody, addAdminUserBody, updatePlatformConfigBody, updateFreeOrgLimitBody, adminSetOrgHarnessBody, adminSetHubHarnessBody, adminScopedTargetBody, updatePricingPlanBody, dataExplorerSearchQuery, dataExplorerOrgIdParam, dataExplorerHubIdParam, dataExplorerConvIdParam, dataExplorerDoInstancesQuery, dataExplorerNsIdParam, dataExplorerKvKeysQuery, dataExplorerKvKeyParam, uuidOrHexId, dataExplorerDeleteOrgParam, dataExplorerDeleteHubParam, dataExplorerDeleteConvParam, dataExplorerDeleteUserParam, dataExplorerDeleteQuery, dataExplorerKvDeleteQuery, pitrDoNamespace, pitrBookmarkParam, pitrRestoreBody, healthSamplingTriggerBody, dataExplorerDebugDoType, DEBUG_READ_MAX_LIMIT, DEBUG_READ_DEFAULT_LIMIT, DEBUG_DO_HEX_PREFIX, debugDoEntityId, debugTableName, dataExplorerDebugTablesParam, dataExplorerDebugRowsParam, dataExplorerDebugRowsQuery, dataExplorerDebugAnalyticsTable, debugUuid, dataExplorerDebugAnalyticsRowsParam, dataExplorerDebugAnalyticsRowsQuery, debugHubConvParam, debugMessageIdQuery, sandboxEgressPolicy, SANDBOX_EXEC_MAX_CMD_LENGTH, SANDBOX_EXEC_MAX_ALLOWLIST, SANDBOX_EXEC_MAX_TIMEOUT_MS, adminSandboxExecBody, whatsappCallbackBody, authMeResponse, wsTicketResponse, sessionCheckResponse, logoutResponse, magicCodeSendBody, magicCodeSendResponse, magicCodeVerifyBody, magicCodeVerifyResponse, browserParams, browserFoldersQuery, browserFilesQuery, stateOperationBody, conversationListResourcesQuery, conversationReadResourceQuery, listPendingSchedulesQuery, listHubAggregateSchedulesQuery, reportSourceSchema, intakeReportSourceSchema, reportClassificationSchema, reportStatusSchema, reportLocaleSchema, reportMessageAuthorRoleSchema, sentryRefStatusSchema, createReportBody, editReportBody, contestReportBody, reporterListQuery, listReportsQuery, GITHUB_ISSUE_URL_REGEX, githubIssueUrlSchema, transitionReportBody, groupReportsBody, holdReportBody, clickhouseReadyResponse, bootstrapQuery, requestSnapshotChunkMessage, MAX_NAME_LENGTH, MAX_VALUE_LENGTH, MAX_TAGS, MAX_TAG_LENGTH, MAX_SCOPE_HUBS, MAX_SCOPE_TAGS, vaultSecretScopeSchema, vaultCreateBody, vaultUpdateBody, PERMISSIONS, MAX_NAME_LENGTH2, MAX_HUBS_PER_GRANT, MAX_HUB_TAGS_PER_GRANT, MAX_GRANTS, permissionEnum, grantScopeSchema, grantSchema, createTokenBody, tokenOrgIdParam, tokenGrantScopeSchema, tokenGrantSchema, tokenMetadataSchema, listTokensResponse, createTokenResponse, orgTokenSummarySchema, listOrgTokensResponse, invitePreviewQuery, invitePreviewResponse, discordTier, discordBillingCycle, discordMetadata, discordOAuthStartResponse, discordOAuthFinalizeBody, discordOAuthFinalizeResponse, discordDisconnectResponse, jsonSchemaSchema, hubUserIdentity, stateValueEntry, getHubUserContextResponse, updateHubUserBody, updateHubUserResponse, unlockHubUserNameResponse, stateResetParams, stateResetResponse, hubAlertsParam, hubAlertSeverity, hubAlert, hubAlertsListResponse, noticeSeveritySchema, noticeStatusSchema, NOTICE_SCOPE_REGEX, noticeScopeSchema, noticeLinkSchema, createNoticeBody, updateNoticeBody, listNoticesQuery, noticeIdParamSchema, templateLocaleSchema, TEMPLATE_SLUG_REGEX, templateSlugSchema, templateStatusSchema, templateFileMapSchema, templateTextSchema, templateUsesEntrySchema, templateUsesSchema, templateYamlLocaleEntry, templateYamlWayaiBlock, templateTagsSchema, templateYamlSchema, templateHeroSchema, templatePushLocaleSchema, templatePushBody, templateListQuery, templateSlugParam, templateDetailQuery, ADMIN_SKILL_NAME_REGEX, adminSkillNameParam, WAYAI_WORKSPACE_LAYOUT, MAX_RESOURCE_FILE_SIZE;
5411
5572
  var init_dist = __esm({
5412
5573
  "../../packages/core/dist/index.js"() {
5413
5574
  "use strict";
@@ -5459,6 +5620,68 @@ var init_dist = __esm({
5459
5620
  init_zod();
5460
5621
  init_zod();
5461
5622
  init_zod();
5623
+ UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
5624
+ HEX_RE = /^[0-9a-f]{16,}$/;
5625
+ WORKOS_ID_RE = /^(?:user|org)_[0-9A-HJKMNP-TV-Z]{26}$/;
5626
+ OPAQUE_SECRET_RE = /^[A-Za-z0-9_-]{21,}$/;
5627
+ BASE64_SECRET_RE = /^[A-Za-z0-9+/]{20,}={0,2}$/;
5628
+ BASE64_MARKER_RE = /[+=]/;
5629
+ TOKEN_RE = new RegExp(
5630
+ [
5631
+ // WayAI API tokens and WebSocket tickets.
5632
+ "(?:way|wst)_[A-Za-z0-9._-]{8,}",
5633
+ // Authorization header values, including base64 Basic credentials.
5634
+ "(?:Bearer|Basic)\\s+[A-Za-z0-9._~+/=-]{8,}",
5635
+ // JWTs — WorkOS session/access tokens. `eyJ` is base64 for `{"`.
5636
+ "eyJ[A-Za-z0-9._-]{10,}",
5637
+ // Stripe secret/publishable/restricted keys and webhook signing secrets.
5638
+ "(?:sk|pk|rk)_(?:live|test)_[A-Za-z0-9]{8,}",
5639
+ "whsec_[A-Za-z0-9]{8,}"
5640
+ // NOTE: LLM provider keys are NOT here — they need a delimiter-preserving
5641
+ // boundary, so they live in PROVIDER_TOKEN_RE below.
5642
+ ].join("|"),
5643
+ "g"
5644
+ );
5645
+ SENSITIVE_FIELDS = [
5646
+ "password",
5647
+ "token",
5648
+ "secret",
5649
+ "api_key",
5650
+ "apikey",
5651
+ "api-key",
5652
+ "authorization",
5653
+ "auth",
5654
+ "credential",
5655
+ "private_key",
5656
+ "privatekey",
5657
+ "access_token",
5658
+ "refresh_token",
5659
+ "session_id",
5660
+ "sessionid",
5661
+ "cookie",
5662
+ "jwt"
5663
+ ];
5664
+ SENSITIVE_KEY_ALTERNATION = SENSITIVE_FIELDS.map(
5665
+ (field) => field.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
5666
+ ).join("|");
5667
+ SENSITIVE_KEY_PATTERN = `[A-Za-z0-9_.-]*(?:${SENSITIVE_KEY_ALTERNATION})[A-Za-z0-9_.-]*`;
5668
+ JSON_CREDENTIAL_RE = new RegExp(
5669
+ `("${SENSITIVE_KEY_PATTERN}"\\s*:\\s*)"(?:[^"\\\\]|\\\\.)*"`,
5670
+ "gi"
5671
+ );
5672
+ QUERY_CREDENTIAL_RE = new RegExp(
5673
+ `((?:^|[?&;\\s])${SENSITIVE_KEY_PATTERN}=)[^&;\\s"']+`,
5674
+ "gi"
5675
+ );
5676
+ REDACTED = "[REDACTED]";
5677
+ PROVIDER_TOKEN_RE = new RegExp(
5678
+ "(^|[^A-Za-z0-9])(?:" + [
5679
+ "sk-[A-Za-z0-9_-]{16,}",
5680
+ "AIza[A-Za-z0-9_-]{16,}",
5681
+ "xai-[A-Za-z0-9_-]{16,}"
5682
+ ].join("|") + ")",
5683
+ "g"
5684
+ );
5462
5685
  APP_ERROR_BRAND = /* @__PURE__ */ Symbol.for("wayai.AppError");
5463
5686
  AppError = class extends Error {
5464
5687
  constructor(message, code, statusCode = 500, details) {
@@ -5490,7 +5713,7 @@ var init_dist = __esm({
5490
5713
  LLM_PROVIDER_HTTP_BRAND = /* @__PURE__ */ Symbol.for("wayai.LlmProviderHttpError");
5491
5714
  LlmProviderHttpError = class extends Error {
5492
5715
  constructor(message, status, provider, providerError) {
5493
- super(message);
5716
+ super(redactSecrets(message));
5494
5717
  this.status = status;
5495
5718
  this.provider = provider;
5496
5719
  this.providerError = providerError;
@@ -5596,6 +5819,30 @@ var init_dist = __esm({
5596
5819
  idParamSchema = external_exports.object({
5597
5820
  id: uuidSchema
5598
5821
  });
5822
+ clientOptionalString = external_exports.string().nullish().transform((v) => v ?? void 0);
5823
+ clientOptionalBoolean = external_exports.boolean().nullish().transform((v) => v ?? void 0);
5824
+ clientOptionalNumber = external_exports.number().nullish().transform((v) => v ?? void 0);
5825
+ messageAttachment = external_exports.object({
5826
+ /**
5827
+ * Capped at the same 255 the storage layer already truncates names to, so nothing
5828
+ * legitimate is lost — every filesystem caps there, and `sanitizeFileName` sliced
5829
+ * longer names anyway.
5830
+ *
5831
+ * The bound is load-bearing, not hygiene: the RAW name is written to R2
5832
+ * `customMetadata.originalFileName`, and R2 rejects oversized metadata. An unbounded
5833
+ * name let a client make the R2 write throw a generic storage error — indistinguishable
5834
+ * from a real outage — which pages us via `logger.error` and, on the app channel, is
5835
+ * read as "we lost the file" and escalates the user to a human. Client input must not
5836
+ * be able to impersonate an infrastructure failure (gh #3365).
5837
+ */
5838
+ file_name: external_exports.string().max(255),
5839
+ /** Base64. Bounded by the route's bodyLimit, not by this schema. */
5840
+ file_binary: external_exports.string(),
5841
+ file_size: clientOptionalNumber,
5842
+ file_extension: clientOptionalString
5843
+ });
5844
+ MAX_MESSAGE_BODY_BYTES = 10 * 1024 * 1024;
5845
+ MAX_ATTACHMENTS_PER_MESSAGE = 20;
5599
5846
  primaryRegionSchema = external_exports.enum([
5600
5847
  "wnam",
5601
5848
  "enam",
@@ -5756,7 +6003,7 @@ var init_dist = __esm({
5756
6003
  eventName: external_exports.string().optional(),
5757
6004
  additional_instructions: external_exports.string().optional(),
5758
6005
  additional_context_schema: external_exports.record(external_exports.unknown()).refine(
5759
- (s) => JSON.stringify(s).length <= MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES,
6006
+ (s) => withinJsonLength(s, MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES),
5760
6007
  `additional_context_schema must be at most ${MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES} bytes when JSON-serialized`
5761
6008
  ).optional(),
5762
6009
  followups: external_exports.array(followupSchema).max(MAX_FOLLOWUPS_PER_STATUS, `followups must have at most ${MAX_FOLLOWUPS_PER_STATUS} entries`).optional(),
@@ -5982,6 +6229,9 @@ var init_dist = __esm({
5982
6229
  replicatePreviewBody = external_exports.object({
5983
6230
  preview_label: previewLabelField
5984
6231
  });
6232
+ updateChannelTestIdentitiesBody = external_exports.object({
6233
+ test_identities: external_exports.array(external_exports.string().max(320)).max(1e3)
6234
+ });
5985
6235
  claimCodeChannelParam = external_exports.object({
5986
6236
  id: uuidSchema,
5987
6237
  channelId: uuidSchema
@@ -6632,12 +6882,15 @@ var init_dist = __esm({
6632
6882
  hubIdQuery = external_exports.object({
6633
6883
  hub_id: external_exports.string().uuid()
6634
6884
  });
6885
+ EVAL_INPUT_ROLES = ["user", "system"];
6886
+ EVAL_INPUT_ROLE_LIST = EVAL_INPUT_ROLES.map((r) => `"${r}"`).join(" or ");
6887
+ ROLE_ECHO_MAX = 40;
6635
6888
  createEvalBody = external_exports.object({
6636
6889
  eval: external_exports.record(external_exports.unknown())
6637
- });
6890
+ }).superRefine(refineEvalMessageTextRole);
6638
6891
  updateEvalBody = external_exports.object({
6639
6892
  eval: external_exports.record(external_exports.unknown())
6640
- });
6893
+ }).superRefine(refineEvalMessageTextRole);
6641
6894
  getEvalsQuery = external_exports.object({
6642
6895
  hub_id: external_exports.string().uuid(),
6643
6896
  agent_id: external_exports.string().uuid().optional(),
@@ -6809,6 +7062,15 @@ var init_dist = __esm({
6809
7062
  hub_user_id: external_exports.string().optional(),
6810
7063
  search_filter: external_exports.string().optional(),
6811
7064
  hub_id: external_exports.string().uuid().optional(),
7065
+ // NON-authorizing single-hub narrow. Unlike `hub_id` (which runs the
7066
+ // grant-gated `loadHub('hub:read')` and so throws for grant-less end users /
7067
+ // team members), `scope_hub_id` INTERSECTS the caller's already-resolved hub
7068
+ // roster server-side. Intersecting the caller's own roster IS the
7069
+ // authorization — a hub the caller isn't in narrows to empty and leaks
7070
+ // nothing. Continuous history sends it to take the single-hub ended-index
7071
+ // path (one HubDO read, accurate uncapped total) instead of the all-hub
7072
+ // fan-out it would otherwise discard client-side (gh #3319).
7073
+ scope_hub_id: external_exports.string().uuid().optional(),
6812
7074
  conversation_id: external_exports.string().uuid().optional(),
6813
7075
  // 'ended' = recently-closed, served warm from the HubDO index (≤ retention
6814
7076
  // window). 'archived' = the full closed-conversation history from ClickHouse.
@@ -6849,17 +7111,8 @@ var init_dist = __esm({
6849
7111
  });
6850
7112
  }
6851
7113
  });
6852
- clientOptionalString = external_exports.string().nullish().transform((v) => v ?? void 0);
6853
- clientOptionalBoolean = external_exports.boolean().nullish().transform((v) => v ?? void 0);
6854
7114
  appMessageSenderType = external_exports.enum(["user", "team"]);
6855
7115
  appMessageReceiverType = external_exports.enum(["user", "team", "agent", "assistant"]).transform((v) => v === "assistant" ? "agent" : v);
6856
- appMessageAttachment = external_exports.object({
6857
- file_name: external_exports.string(),
6858
- file_binary: external_exports.string(),
6859
- file_size: external_exports.number().nullish().transform((v) => v ?? void 0),
6860
- file_extension: clientOptionalString
6861
- });
6862
- MAX_ATTACHMENTS_PER_MESSAGE = 20;
6863
7116
  appMessageBody = external_exports.object({
6864
7117
  // Message content — three historical aliases. All optional: an attachment-only
6865
7118
  // or voice-only message carries no text.
@@ -6888,7 +7141,7 @@ var init_dist = __esm({
6888
7141
  // Pre-generated by the client so the optimistic bubble and the stored row share
6889
7142
  // a key (transcription live-updates land on the same row instead of duplicating).
6890
7143
  message_id: clientOptionalString,
6891
- attachments: external_exports.array(appMessageAttachment).max(MAX_ATTACHMENTS_PER_MESSAGE).nullish().transform((v) => v ?? void 0),
7144
+ attachments: external_exports.array(messageAttachment).max(MAX_ATTACHMENTS_PER_MESSAGE).nullish().transform((v) => v ?? void 0),
6892
7145
  // Base64-encoded audio for STT. Size-capped in the route (the cap is a byte
6893
7146
  // budget tied to the /channels/* bodyLimit, not a shape rule).
6894
7147
  audio_file: clientOptionalString
@@ -7015,7 +7268,7 @@ var init_dist = __esm({
7015
7268
  hub_type: external_exports.enum(["chat", "task"]).default("chat"),
7016
7269
  user_id: external_exports.string().optional()
7017
7270
  });
7018
- additionalContextPayloadSchema = external_exports.record(external_exports.unknown()).refine((r) => JSON.stringify(r).length <= 16384, {
7271
+ additionalContextPayloadSchema = external_exports.record(external_exports.unknown()).refine((r) => withinJsonLength(r, 16384), {
7019
7272
  message: "additional_context payload must be at most 16384 bytes when JSON-serialized"
7020
7273
  });
7021
7274
  kanbanUpdateBody = external_exports.object({
@@ -7059,11 +7312,27 @@ var init_dist = __esm({
7059
7312
  ]);
7060
7313
  sendMessageBody = external_exports.object({
7061
7314
  hub_id: external_exports.string().uuid(),
7062
- message: external_exports.string().min(1).max(5e4),
7315
+ /**
7316
+ * Optional ONLY when `attachments` carries the payload — see the refinement below.
7317
+ * An attachment-only message (a photo with no caption) is the ordinary WhatsApp
7318
+ * gesture, so the endpoint that exists to rehearse inbound flows has to express it.
7319
+ * Mirrors `appMessageBody`, where content is optional for the same reason.
7320
+ */
7321
+ message: external_exports.string().min(1).max(5e4).optional(),
7063
7322
  /** For chat hubs: optional — automatically continues the user's active conversation (or creates one).
7064
7323
  * For task hubs: required to continue an existing conversation. Omit to start a new task conversation. */
7065
- conversation_id: external_exports.string().uuid().optional()
7066
- });
7324
+ conversation_id: external_exports.string().uuid().optional(),
7325
+ /**
7326
+ * Base64 attachments, delivered over the hub's `app` channel exactly as a real
7327
+ * channel delivers them. Total bytes are bounded by the route's bodyLimit —
7328
+ * `/api/*` carries no global one (only `/webhooks/*` and `/channels/*` do), so the
7329
+ * route declares its own rather than inheriting an unbounded upload path.
7330
+ */
7331
+ attachments: external_exports.array(messageAttachment).max(MAX_ATTACHMENTS_PER_MESSAGE).optional()
7332
+ }).refine(
7333
+ (b) => (b.message?.length ?? 0) > 0 || (b.attachments?.length ?? 0) > 0,
7334
+ { message: "message or attachments required" }
7335
+ );
7067
7336
  listConversationsQuery = external_exports.object({
7068
7337
  hub_id: external_exports.string().uuid(),
7069
7338
  status: external_exports.enum(["agent", "team", "ended"]).optional(),
@@ -7275,6 +7544,7 @@ var init_dist = __esm({
7275
7544
  refineHubAsCodeCustomTools(config, ctx);
7276
7545
  refineHubAsCodeKanbanStatuses(config, ctx);
7277
7546
  refineHubAsCodeLanes(config, ctx);
7547
+ refineHubAsCodeEvals(config, ctx);
7278
7548
  });
7279
7549
  ciPullHubIdParam = external_exports.object({
7280
7550
  hub_id: ciUuidSchema
@@ -8418,7 +8688,7 @@ function findHubByFolderName(workspaceDir, hubFolderName) {
8418
8688
  function resolveHubFolderBySelector(hubsDir, selector) {
8419
8689
  const asPath = path2.resolve(selector);
8420
8690
  if (isDirectory(asPath) && fs2.existsSync(path2.join(asPath, "hub.yaml"))) return asPath;
8421
- if (UUID_RE.test(selector)) {
8691
+ if (UUID_RE2.test(selector)) {
8422
8692
  const match = scanWorkspaceHubs(hubsDir).find((h) => h.hubId === selector);
8423
8693
  return match ? match.hubFolder : null;
8424
8694
  }
@@ -8525,7 +8795,7 @@ function resolveActiveHubId(args2) {
8525
8795
  const workspaceDir = workspace?.workspaceDir ?? (gitRoot ? resolveLayout(gitRoot).hubsDir : null);
8526
8796
  const wsLabel = hubsDirLabel(gitRoot);
8527
8797
  if (!workspaceDir || !fs2.existsSync(workspaceDir)) {
8528
- if (selector && UUID_RE.test(selector)) return selector;
8798
+ if (selector && UUID_RE2.test(selector)) return selector;
8529
8799
  console.error(`No ${wsLabel}/ directory found. Run \`wayai pull --hub <uuid>\` to fetch a hub, or pass --hub <uuid>.`);
8530
8800
  process.exit(1);
8531
8801
  }
@@ -8535,7 +8805,7 @@ function resolveActiveHubId(args2) {
8535
8805
  (h) => h.hubId === selector || path2.basename(h.hubFolder) === selector
8536
8806
  );
8537
8807
  if (match) return match.hubId;
8538
- if (UUID_RE.test(selector)) return selector;
8808
+ if (UUID_RE2.test(selector)) return selector;
8539
8809
  console.error(`No hub matching --hub ${selector} found in ${wsLabel}/.`);
8540
8810
  process.exit(1);
8541
8811
  }
@@ -8608,7 +8878,7 @@ function readRepoConfig(root) {
8608
8878
  }
8609
8879
  return null;
8610
8880
  }
8611
- if (!UUID_RE.test(config.organization_id)) return null;
8881
+ if (!UUID_RE2.test(config.organization_id)) return null;
8612
8882
  const presentLegacy = LEGACY_FIELDS.filter((f) => config[f] !== void 0);
8613
8883
  warnAboutLegacyFields(presentLegacy);
8614
8884
  const organizationName = typeof config.organization_name === "string" && config.organization_name.trim() ? config.organization_name.trim() : void 0;
@@ -8784,7 +9054,7 @@ function parseDateArg(date, position) {
8784
9054
  }
8785
9055
  async function resolveOrganizationId(client, orgIdFlag) {
8786
9056
  if (orgIdFlag) {
8787
- if (!UUID_RE.test(orgIdFlag)) {
9057
+ if (!UUID_RE2.test(orgIdFlag)) {
8788
9058
  console.error("Invalid --org value. Expected a UUID.");
8789
9059
  process.exit(1);
8790
9060
  }
@@ -8842,12 +9112,12 @@ function isNewerVersion(latest, current) {
8842
9112
  }
8843
9113
  return false;
8844
9114
  }
8845
- var UUID_RE, slugify, OWN_HELP_COMMANDS;
9115
+ var UUID_RE2, slugify, OWN_HELP_COMMANDS;
8846
9116
  var init_utils = __esm({
8847
9117
  "src/lib/utils.ts"() {
8848
9118
  "use strict";
8849
9119
  init_dist();
8850
- UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
9120
+ UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
8851
9121
  slugify = slugifySkillName;
8852
9122
  OWN_HELP_COMMANDS = /* @__PURE__ */ new Set([
8853
9123
  "eval",
@@ -8868,9 +9138,9 @@ function getVersionCachePath(filename = CLI_CACHE_FILE) {
8868
9138
  }
8869
9139
  function readVersionCache(filename = CLI_CACHE_FILE) {
8870
9140
  try {
8871
- const path27 = getVersionCachePath(filename);
8872
- if (!existsSync4(path27)) return null;
8873
- const parsed = JSON.parse(readFileSync5(path27, "utf-8"));
9141
+ const path28 = getVersionCachePath(filename);
9142
+ if (!existsSync4(path28)) return null;
9143
+ const parsed = JSON.parse(readFileSync5(path28, "utf-8"));
8874
9144
  if (typeof parsed.lastCheck !== "number") return null;
8875
9145
  if (parsed.latest !== null && typeof parsed.latest !== "string") return null;
8876
9146
  return parsed;
@@ -8890,10 +9160,10 @@ function isVersionCacheStale(filename = CLI_CACHE_FILE, maxAgeMs = MAX_AGE_24H_M
8890
9160
  return Date.now() - cache.lastCheck > maxAgeMs;
8891
9161
  }
8892
9162
  function writeVersionCache(filename, cache) {
8893
- const path27 = getVersionCachePath(filename);
8894
- const dir = dirname3(path27);
9163
+ const path28 = getVersionCachePath(filename);
9164
+ const dir = dirname3(path28);
8895
9165
  if (!existsSync4(dir)) mkdirSync(dir, { recursive: true });
8896
- writeFileSync2(path27, JSON.stringify(cache));
9166
+ writeFileSync2(path28, JSON.stringify(cache));
8897
9167
  }
8898
9168
  function touchVersionCache(filename) {
8899
9169
  writeVersionCache(filename, { lastCheck: Date.now(), latest: readVersionCache(filename)?.latest ?? null });
@@ -8932,14 +9202,14 @@ function parseFrontmatterVersion(content) {
8932
9202
  function findInstalledSkills(projectRoot, paths = SKILL_INSTALL_PATHS) {
8933
9203
  const found = [];
8934
9204
  for (const rel of paths) {
8935
- const path27 = join7(projectRoot, rel);
8936
- if (!existsSync5(path27)) continue;
9205
+ const path28 = join7(projectRoot, rel);
9206
+ if (!existsSync5(path28)) continue;
8937
9207
  let version = null;
8938
9208
  try {
8939
- version = parseFrontmatterVersion(readFileSync6(path27, "utf-8"));
9209
+ version = parseFrontmatterVersion(readFileSync6(path28, "utf-8"));
8940
9210
  } catch {
8941
9211
  }
8942
- found.push({ path: path27, version });
9212
+ found.push({ path: path28, version });
8943
9213
  }
8944
9214
  return found;
8945
9215
  }
@@ -9361,7 +9631,7 @@ async function exchangeCodeForTokens(authkitDomain, clientId, code, codeVerifier
9361
9631
  });
9362
9632
  if (!response.ok) {
9363
9633
  const body = await response.text();
9364
- throw new Error(`Token exchange failed (${response.status}): ${redactSecrets(body)}`);
9634
+ throw new Error(`Token exchange failed (${response.status}): ${maskSecretsInMessage(body)}`);
9365
9635
  }
9366
9636
  return response.json();
9367
9637
  }
@@ -9387,7 +9657,7 @@ async function refreshAccessToken(authkitDomain, clientId, refreshToken) {
9387
9657
  }
9388
9658
  if (isInvalidGrant) throw new Error("SESSION_EXPIRED");
9389
9659
  }
9390
- throw new Error(`Token refresh failed (${status}): ${redactSecrets(body)}`);
9660
+ throw new Error(`Token refresh failed (${status}): ${maskSecretsInMessage(body)}`);
9391
9661
  }
9392
9662
  return response.json();
9393
9663
  }
@@ -9519,7 +9789,7 @@ var init_auth = __esm({
9519
9789
  init_config();
9520
9790
  init_token_store();
9521
9791
  init_sentry();
9522
- init_redact();
9792
+ init_mask_secrets();
9523
9793
  OAUTH_CALLBACK_PORT = 3829;
9524
9794
  AUTHKIT_DOMAIN = "https://sprightly-comic-51.authkit.app";
9525
9795
  AUTHKIT_CLIENT_ID = "client_01KMZHB50KENM5SV90ZA80VXK4";
@@ -9842,12 +10112,12 @@ function readBinding() {
9842
10112
  throw err;
9843
10113
  }
9844
10114
  const trimmed = raw.trim();
9845
- return UUID_RE.test(trimmed) ? trimmed : null;
10115
+ return UUID_RE2.test(trimmed) ? trimmed : null;
9846
10116
  }
9847
10117
  return null;
9848
10118
  }
9849
10119
  function writeBinding(hubId) {
9850
- if (!UUID_RE.test(hubId)) {
10120
+ if (!UUID_RE2.test(hubId)) {
9851
10121
  throw new Error(`Invalid hub_id (must be a UUID): ${hubId}`);
9852
10122
  }
9853
10123
  const bindingPath = getBindingPath();
@@ -10317,7 +10587,7 @@ async function initCommand(args2) {
10317
10587
  );
10318
10588
  }
10319
10589
  async function initDirect(client, orgId) {
10320
- if (!UUID_RE.test(orgId)) {
10590
+ if (!UUID_RE2.test(orgId)) {
10321
10591
  console.error("Invalid organization ID. Expected a UUID.");
10322
10592
  process.exit(1);
10323
10593
  }
@@ -11297,7 +11567,7 @@ function resolveHubTarget(workspaceDir, selector) {
11297
11567
  (h) => h.hubId === selector || path14.basename(h.hubFolder) === selector
11298
11568
  );
11299
11569
  if (match) return { hubId: match.hubId, hubFolder: match.hubFolder };
11300
- if (UUID_RE.test(selector)) return { hubId: selector, hubFolder: null };
11570
+ if (UUID_RE2.test(selector)) return { hubId: selector, hubFolder: null };
11301
11571
  console.error(`No hub matching --hub ${selector} found in ${wsLabel}/. Pass a UUID for first-time pulls.`);
11302
11572
  process.exit(1);
11303
11573
  }
@@ -11800,7 +12070,7 @@ New hub: "${newHub.hubName}" (${hubType})`);
11800
12070
  });
11801
12071
  const createdHub = createResult.data[0];
11802
12072
  const hubId = createdHub.hub_id;
11803
- if (!UUID_RE.test(hubId)) {
12073
+ if (!UUID_RE2.test(hubId)) {
11804
12074
  console.error(`Invalid hub_id received from server: ${hubId}`);
11805
12075
  process.exit(1);
11806
12076
  }
@@ -12066,6 +12336,18 @@ var init_diff = __esm({
12066
12336
  });
12067
12337
 
12068
12338
  // ../../packages/core/dist/contracts/index.js
12339
+ function jsonLengthOrNull2(value) {
12340
+ try {
12341
+ const json = JSON.stringify(value);
12342
+ return typeof json === "string" ? json.length : null;
12343
+ } catch {
12344
+ return null;
12345
+ }
12346
+ }
12347
+ function withinJsonLength2(value, max) {
12348
+ const length = jsonLengthOrNull2(value);
12349
+ return length !== null && length <= max;
12350
+ }
12069
12351
  function normalizeAuthType2(raw) {
12070
12352
  if (VALID_AUTH_TYPES3.has(raw)) return raw;
12071
12353
  return LEGACY_AUTH_TYPE_MAP3[raw] ?? raw;
@@ -12136,12 +12418,12 @@ function typeMatches2(typeField, allowed) {
12136
12418
  if (Array.isArray(typeField)) return typeField.every((t) => typeof t === "string" && allowed.has(t));
12137
12419
  return false;
12138
12420
  }
12139
- function validateSchema2(schema, path27, errors, opts = {}) {
12421
+ function validateSchema2(schema, path28, errors, opts = {}) {
12140
12422
  if (typeof schema === "boolean") return;
12141
12423
  const depth = opts.depth ?? 0;
12142
12424
  if (depth > MAX_SCHEMA_DEPTH2) {
12143
12425
  errors.push({
12144
- path: path27 || "<root>",
12426
+ path: path28 || "<root>",
12145
12427
  message: `schema nesting exceeds ${MAX_SCHEMA_DEPTH2} levels`,
12146
12428
  suggestion: "Flatten the schema; LLM providers reject deeply nested tool input_schemas."
12147
12429
  });
@@ -12149,7 +12431,7 @@ function validateSchema2(schema, path27, errors, opts = {}) {
12149
12431
  }
12150
12432
  if (!isRecord2(schema)) {
12151
12433
  errors.push({
12152
- path: path27,
12434
+ path: path28,
12153
12435
  message: `expected object, got ${schema === null ? "null" : typeof schema}`
12154
12436
  });
12155
12437
  return;
@@ -12157,14 +12439,14 @@ function validateSchema2(schema, path27, errors, opts = {}) {
12157
12439
  if (opts.isRoot) {
12158
12440
  if ("type" in schema && schema.type !== "object") {
12159
12441
  errors.push({
12160
- path: path27 ? `${path27}.type` : "type",
12442
+ path: path28 ? `${path28}.type` : "type",
12161
12443
  message: `root type must be 'object', got ${JSON.stringify(schema.type)}`,
12162
12444
  suggestion: "Tool parameters at the root must be an object: `{ type: 'object', properties: { ... } }`."
12163
12445
  });
12164
12446
  }
12165
12447
  } else if ("type" in schema && !typeMatches2(schema.type, ALLOWED_TYPES2)) {
12166
12448
  errors.push({
12167
- path: `${path27}.type`,
12449
+ path: `${path28}.type`,
12168
12450
  message: `type must be one of ${[...ALLOWED_TYPES2].join("/")} or an array of those, got ${JSON.stringify(schema.type)}`
12169
12451
  });
12170
12452
  }
@@ -12173,25 +12455,25 @@ function validateSchema2(schema, path27, errors, opts = {}) {
12173
12455
  if (typeof e === "string") {
12174
12456
  const isPlaceholder = PLACEHOLDER_TOKENS2.includes(e);
12175
12457
  errors.push({
12176
- path: `${path27}.enum`,
12458
+ path: `${path28}.enum`,
12177
12459
  message: `enum must be a non-empty array of primitives, got string ${JSON.stringify(e)}`,
12178
12460
  suggestion: 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"]`.'
12179
12461
  });
12180
12462
  } else if (!Array.isArray(e)) {
12181
12463
  errors.push({
12182
- path: `${path27}.enum`,
12464
+ path: `${path28}.enum`,
12183
12465
  message: `enum must be a non-empty array of primitives, got ${typeof e}`
12184
12466
  });
12185
12467
  } else if (e.length === 0) {
12186
12468
  errors.push({
12187
- path: `${path27}.enum`,
12469
+ path: `${path28}.enum`,
12188
12470
  message: "enum must not be empty"
12189
12471
  });
12190
12472
  } else {
12191
12473
  for (let i = 0; i < e.length; i++) {
12192
12474
  if (!isPrimitive2(e[i])) {
12193
12475
  errors.push({
12194
- path: `${path27}.enum[${i}]`,
12476
+ path: `${path28}.enum[${i}]`,
12195
12477
  message: `enum entry must be a primitive (string/number/boolean/null), got ${typeof e[i]}`
12196
12478
  });
12197
12479
  }
@@ -12201,7 +12483,7 @@ function validateSchema2(schema, path27, errors, opts = {}) {
12201
12483
  for (const key of ["exclusiveMinimum", "exclusiveMaximum"]) {
12202
12484
  if (key in schema && typeof schema[key] === "boolean") {
12203
12485
  errors.push({
12204
- path: `${path27}.${key}`,
12486
+ path: `${path28}.${key}`,
12205
12487
  message: `${key} as boolean is draft-04 syntax; draft 2020-12 requires a numeric value`,
12206
12488
  suggestion: `Replace with the numeric bound, e.g. \`${key}: 0\`.`
12207
12489
  });
@@ -12210,45 +12492,45 @@ function validateSchema2(schema, path27, errors, opts = {}) {
12210
12492
  if ("properties" in schema) {
12211
12493
  if (!isRecord2(schema.properties)) {
12212
12494
  errors.push({
12213
- path: `${path27}.properties`,
12495
+ path: `${path28}.properties`,
12214
12496
  message: `properties must be an object, got ${Array.isArray(schema.properties) ? "array" : typeof schema.properties}`
12215
12497
  });
12216
12498
  } else {
12217
12499
  for (const [propName, propSchema] of Object.entries(schema.properties)) {
12218
- validateSchema2(propSchema, `${path27}.properties.${propName}`, errors, { depth: depth + 1 });
12500
+ validateSchema2(propSchema, `${path28}.properties.${propName}`, errors, { depth: depth + 1 });
12219
12501
  }
12220
12502
  }
12221
12503
  }
12222
12504
  if (schemaTypeIncludes2(schema, "array") && "items" in schema) {
12223
12505
  if (Array.isArray(schema.items)) {
12224
- schema.items.forEach((sub, i) => validateSchema2(sub, `${path27}.items[${i}]`, errors, { depth: depth + 1 }));
12506
+ schema.items.forEach((sub, i) => validateSchema2(sub, `${path28}.items[${i}]`, errors, { depth: depth + 1 }));
12225
12507
  } else {
12226
- validateSchema2(schema.items, `${path27}.items`, errors, { depth: depth + 1 });
12508
+ validateSchema2(schema.items, `${path28}.items`, errors, { depth: depth + 1 });
12227
12509
  }
12228
12510
  }
12229
12511
  for (const key of SUBSCHEMA_OBJECT_KEYWORDS2) {
12230
12512
  if (key in schema && isRecord2(schema[key])) {
12231
- validateSchema2(schema[key], `${path27}.${key}`, errors, { depth: depth + 1 });
12513
+ validateSchema2(schema[key], `${path28}.${key}`, errors, { depth: depth + 1 });
12232
12514
  }
12233
12515
  }
12234
12516
  for (const key of SUBSCHEMA_LIST_KEYWORDS2) {
12235
12517
  const list = schema[key];
12236
12518
  if (Array.isArray(list)) {
12237
- list.forEach((sub, i) => validateSchema2(sub, `${path27}.${key}[${i}]`, errors, { depth: depth + 1 }));
12519
+ list.forEach((sub, i) => validateSchema2(sub, `${path28}.${key}[${i}]`, errors, { depth: depth + 1 }));
12238
12520
  }
12239
12521
  }
12240
12522
  for (const key of SUBSCHEMA_MAP_KEYWORDS2) {
12241
12523
  const map = schema[key];
12242
12524
  if (isRecord2(map)) {
12243
12525
  for (const [name, sub] of Object.entries(map)) {
12244
- validateSchema2(sub, `${path27}.${key}.${name}`, errors, { depth: depth + 1 });
12526
+ validateSchema2(sub, `${path28}.${key}.${name}`, errors, { depth: depth + 1 });
12245
12527
  }
12246
12528
  }
12247
12529
  }
12248
12530
  const reportedPaths = new Set(errors.map((e) => e.path));
12249
12531
  for (const [k, v] of Object.entries(schema)) {
12250
12532
  if (typeof v !== "string") continue;
12251
- const fieldPath = `${path27}.${k}`;
12533
+ const fieldPath = `${path28}.${k}`;
12252
12534
  if (reportedPaths.has(fieldPath)) continue;
12253
12535
  for (const token of PLACEHOLDER_TOKENS2) {
12254
12536
  if (v === token) {
@@ -12313,6 +12595,45 @@ function refineToolConfig2(value, ctx) {
12313
12595
  }
12314
12596
  }
12315
12597
  }
12598
+ function describeRole2(role) {
12599
+ if (typeof role === "string") {
12600
+ return JSON.stringify(role.length > ROLE_ECHO_MAX2 ? `${role.slice(0, ROLE_ECHO_MAX2)}\u2026` : role);
12601
+ }
12602
+ if (role === null) return "null";
12603
+ if (Array.isArray(role)) return "an array";
12604
+ if (typeof role === "object") return "an object";
12605
+ return `a ${typeof role}`;
12606
+ }
12607
+ function asEvalInputRecord2(input) {
12608
+ const value = typeof input === "string" ? (() => {
12609
+ try {
12610
+ return JSON.parse(input);
12611
+ } catch {
12612
+ return null;
12613
+ }
12614
+ })() : input;
12615
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
12616
+ }
12617
+ function evalInputRoleError2(input) {
12618
+ const record = asEvalInputRecord2(input);
12619
+ if (record === null) return null;
12620
+ const role = record.role;
12621
+ if (role === void 0 || role === null) return null;
12622
+ if (typeof role === "string" && EVAL_INPUT_ROLES2.includes(role)) {
12623
+ return null;
12624
+ }
12625
+ return `role must be ${EVAL_INPUT_ROLE_LIST2} (received ${describeRole2(role)}) \u2014 an eval trigger is what the responder answers, and an assistant or tool role gives it nothing to answer`;
12626
+ }
12627
+ function refineEvalMessageTextRole2(value, ctx) {
12628
+ const error = evalInputRoleError2(value.eval.message_text);
12629
+ if (error) {
12630
+ ctx.addIssue({
12631
+ code: external_exports.ZodIssueCode.custom,
12632
+ path: ["eval", "message_text", "role"],
12633
+ message: error
12634
+ });
12635
+ }
12636
+ }
12316
12637
  function refineHubAsCodeCustomTools2(config, ctx) {
12317
12638
  const agents = config.agents;
12318
12639
  if (!Array.isArray(agents)) return;
@@ -12404,10 +12725,26 @@ function refineHubAsCodeLanes2(config, ctx) {
12404
12725
  }
12405
12726
  }
12406
12727
  }
12407
- function isSafeTemplatePath2(path27) {
12408
- if (path27.length === 0 || path27.length > 300) return false;
12409
- if (path27.startsWith("/") || path27.includes("\\")) return false;
12410
- const segments = path27.split("/");
12728
+ function refineHubAsCodeEvals2(config, ctx) {
12729
+ const evals = config.evals;
12730
+ if (!Array.isArray(evals)) return;
12731
+ for (let e = 0; e < evals.length; e++) {
12732
+ const entry = evals[e];
12733
+ const error = evalInputRoleError2(entry?.input);
12734
+ if (error) {
12735
+ ctx.addIssue({
12736
+ code: external_exports.ZodIssueCode.custom,
12737
+ path: ["evals", e, "input", "role"],
12738
+ // Named, not just indexed — the YAML author has files, not an array.
12739
+ message: `eval "${entry?.name ?? "<unnamed>"}": ${error}`
12740
+ });
12741
+ }
12742
+ }
12743
+ }
12744
+ function isSafeTemplatePath2(path28) {
12745
+ if (path28.length === 0 || path28.length > 300) return false;
12746
+ if (path28.startsWith("/") || path28.includes("\\")) return false;
12747
+ const segments = path28.split("/");
12411
12748
  return segments.every(
12412
12749
  (seg) => seg.length > 0 && seg !== "." && seg !== ".." && /^[A-Za-z0-9._-]+$/.test(seg)
12413
12750
  );
@@ -12435,14 +12772,14 @@ function isPlainObject(value) {
12435
12772
  const proto = Object.getPrototypeOf(value);
12436
12773
  return proto === Object.prototype || proto === null;
12437
12774
  }
12438
- function isSanitizableSliceFile(path27) {
12439
- if (!/\.ya?ml$/i.test(path27)) return false;
12440
- return path27 !== "resources" && !path27.startsWith("resources/");
12775
+ function isSanitizableSliceFile(path28) {
12776
+ if (!/\.ya?ml$/i.test(path28)) return false;
12777
+ return path28 !== "resources" && !path28.startsWith("resources/");
12441
12778
  }
12442
12779
  function distinctUsesBackends(uses) {
12443
12780
  return [...new Set((uses ?? []).map((u) => u.backend))];
12444
12781
  }
12445
- var uuidSchema2, paginationSchema3, timestampSchema2, idParamSchema2, primaryRegionSchema2, placementSourceSchema2, orgIdParam2, orgAdminIdParam2, createOrganizationBody2, updateOrganizationBody2, addOrgAdminBody2, AUTH_TYPE3, ORG_CREDENTIAL_AUTH_TYPES3, AUTH_TYPE_DISPLAY3, LEGACY_AUTH_TYPE_MAP3, VALID_AUTH_TYPES3, AGENT_ROLES2, SAFE_USER_ID_REGEX2, SUPPORTED_LOCALES2, SUMMARIZATION_THRESHOLD_MIN2, SUMMARIZATION_THRESHOLD_MAX2, summarizationThresholdField2, monitorConfigField2, agentIdParam2, listAgentsQuery2, agentConnectionsQuery2, createAgentBody2, updateAgentBody2, AGENT_PARAMETER_TYPES2, AGENT_PARAMETER_NAME_REGEX2, agentParameterCreateSchema2, MAX_AGENT_PARAMETERS_PER_REQUEST2, createAgentParametersBody2, SLUG_REGEX2, slugSchema2, INVISIBLE_NAME_CHARS2, MAX_KANBAN_STATUSES2, MAX_FOLLOWUPS_PER_STATUS2, MAX_LANES2, MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES2, RESERVED_TEMPLATE_DUMP_NAME2, kanbanStatusSlugSchema2, followupSchema2, EXCLUSIVE_FLAG_PAIRS2, kanbanStatusSchema2, kanbanStatusesArraySchema2, laneSchema2, lanesArraySchema2, hubIdParam2, hubAdminIdParam2, hubUserIdParam2, hubIdentityIdParam2, hubTeamIdParam2, hubTeamUserDeleteParam2, hubSchemaQuery2, PREVIEW_LABEL_MAX_LENGTH2, MAX_ENDED_INDEX_RETENTION_DAYS2, previewLabelField2, createHubBody2, updateHubBody2, addHubAdminBody2, addHubIdentityAuthorizationBody2, contactDecisionBody2, approveContactBody2, listContactAccessQuery2, createHubTeamBody2, updateHubTeamBody2, addHubTeamUserBody2, reassignHubUserBody2, replicatePreviewBody2, claimCodeChannelParam2, claimCodeDeleteParam2, connectionIdParam2, connectorIdParam2, listConnectionsQuery2, deleteConnectionQuery2, addConnectionBody2, editConnectionBody2, PRODUCTION_DIRECT_FIELDS2, setProductionCredentialBody2, registerWhatsappQuery2, registerWhatsappBody2, retryProvisioningQuery2, resendDomainStatusQuery2, PLACEHOLDER_TOKENS2, ALLOWED_TYPES2, SUBSCHEMA_OBJECT_KEYWORDS2, SUBSCHEMA_LIST_KEYWORDS2, SUBSCHEMA_MAP_KEYWORDS2, MAX_SCHEMA_DEPTH2, toolIdParam2, listToolsQuery2, toolAgentQuery2, deleteToolQuery2, toolConnectionsQuery2, nativeToolIdSchema2, addNativeToolBody2, addMcpToolBody2, createCustomToolBody2, updateCustomToolBody2, updateToolExecutionConfigBody2, initialValueCreateSchema2, initialValueUpdateSchema2, stateIdParam2, listStatesQuery2, stateNameSchema2, createStateBody2, updateStateBody2, reorderStatesBody2, variantAiModeSchema2, experimentStatusSchema2, overlayUpdateSchema2, experimentIdParam2, variantIdParam2, listExperimentsQuery2, listVariantsQuery2, listOverridesQuery2, deleteOverrideQuery2, createExperimentBody2, updateExperimentBody2, setExperimentStatusBody2, createVariantBody2, updateVariantBody2, upsertOverrideBody2, orgTagIdParam2, listOrgTagsQuery2, createOrgTagBody2, updateOrgTagBody2, orgCredentialIdParam2, listOrgCredentialsQuery2, createOrgCredentialBody2, updateOrgCredentialBody2, orgResourceIdParam2, orgResourceFileIdParam2, orgResourceFolderIdParam2, hubOrgResourceParam2, listOrgResourcesQuery2, orgIdQuery2, createOrgResourceBody2, updateOrgResourceBody2, createOrgResourceFolderBody2, updateOrgResourceFolderBody2, uploadOrgResourceFileBody2, updateOrgResourceFileBody2, uploadOrgSkillZipBody2, linkOrgResourceBody2, resourceIdParam2, listResourcesQuery2, createResourceBody2, updateResourceBody2, syncSkillsBody2, resourceFileIdParam2, listResourceFilesQuery2, createResourceFileBody2, updateResourceFileBody2, uploadResourceFileBody2, uploadSkillZipBody2, resourceFolderIdParam2, listResourceFoldersQuery2, createResourceFolderBody2, updateResourceFolderBody2, agentResourceQuery2, hubResourceQuery2, linkAgentResourceBody2, updateAgentResourceBody2, unlinkAgentResourceQuery2, navItemSchema2, hubCountResetBody2, navItemCountResetBody2, typingBody2, analyticsHubIdParam2, analyticsVariableIdParam2, updateVariablePinBody2, updateAnalyticsViewBody2, NUMERIC_FILTER_OPS2, TEXT_FILTER_OPS2, CATEGORICAL_FILTER_OPS2, VARIABLE_FILTER_OPS2, STRUCTURED_QUERY_OPS2, STRUCTURED_QUERY_AGGREGATIONS2, filterValueSchema2, conversationsBody2, analyticsConversationIdParam2, messagesQuery2, conversationDetailDataQuery2, analyticsDataBody2, structuredQueryBody2, analyticsSqlBody2, analyticsSqlSchemaQuery2, EVAL_PACING_PRESET_NAMES2, PACING_INTERVAL_MIN_MS2, PACING_INTERVAL_MAX_MS2, EVAL_RUN_DEADLINE_MIN_MS2, EVAL_RUN_DEADLINE_MAX_MS2, paginationSchema22, evalIdParam2, sessionIdParam2, scenarioSetIdParam2, hubIdQuery2, createEvalBody2, updateEvalBody2, getEvalsQuery2, toggleEvalBody2, bulkToggleEvalsBody2, pacingConfigSchema2, sessionConfigSchema2, createSessionBody2, getSessionsQuery2, getSessionResultsQuery2, getSessionRunsQuery2, evalAnalyticsQuery2, getSessionCostQuery2, compareSessionsQuery2, evalsSqlBody2, evalsSqlSchemaQuery2, exportResultsQuery2, validateEvalBody2, hubAgentsQuery2, createScenarioSetBody2, updateScenarioSetBody2, scenarioSetsHubQuery2, createScenarioFromConversationBody2, createJourneyFromConversationBody2, journeyIdParam2, journeyToolCallSchema2, journeyTurnSchema2, journeyStepOverrideSchema2, fixtureField2, createJourneyBody2, updateJourneyBody2, getConversationsQuery2, getMessagesQuery2, clientOptionalString2, clientOptionalBoolean2, appMessageSenderType2, appMessageReceiverType2, appMessageAttachment2, MAX_ATTACHMENTS_PER_MESSAGE2, appMessageBody2, updateUserBody2, updateProfileBody2, pathnameRegex2, updatePreferencesBody2, registerPushTokenBody2, deletePushTokenQuery2, activityQuery2, deletionModeSchema2, deletionRequestBody2, archiveHubIdParam2, archiveConversationParams2, archiveListQuery2, archiveMessageObservabilityParams2, conversationIdParam2, claimBody2, releaseBody2, transferBody2, closeBody2, additionalContextPayloadSchema2, kanbanUpdateBody2, annotateConversationBody2, observabilityParams2, observabilityListParams2, deleteUserConversationsBody2, sendMessageBody2, listConversationsQuery2, getConversationDetailParams2, getConversationDetailQuery2, listWhatsAppTemplatesQuery2, sendWhatsAppTemplateBody2, billingOrgIdParam2, subscriptionItemParams2, spendCapBody2, growthPacksBody2, portalSessionBody2, checkoutSessionBody2, updateBillingCurrencyBody2, invoicesQuery2, downloadBody2, uploadQuery2, signUrlBody2, outboundSchemaQuery2, templateIdParam2, listTemplatesQuery2, deleteTemplateQuery2, templateStatusQuery2, createTemplateBody2, updateTemplateBody2, submitTemplateBody2, testTemplateBody2, contactIdParam2, listContactsQuery2, createContactBody2, updateContactBody2, listIdParam2, listListsQuery2, listListContactsQuery2, createListBody2, updateListBody2, addListContactsBody2, removeListContactsBody2, scheduleIdParam2, listSchedulesQuery2, listExecutionsQuery2, createScheduleBody2, updateScheduleBody2, uuidPattern2, ciUuidSchema2, hubAsCodeConfigSchema2, ciPullHubIdParam2, ciBranchParam2, ciPullQuery2, ciHubsQuery2, ciLookupQuery2, ciBranchesQuery2, ciSyncBody2, ciPushBody2, ciDiffBody2, ciPublishBody2, ciPublishPreviewBody2, ciSyncMcpBody2, ciOrgResourcesParam2, orgResourcesConfigSchema2, ciOrgResourcesPushBody2, ciOrgResourcesDiffBody2, adminOrgIdParam2, adminOrgAdminIdParam2, adminUserIdParam2, adminPlanIdParam2, adminHubIdParam2, adminOrganizationsQuery2, adminUserSearchQuery2, kanbanSlugMigrationQuery2, adjustQuotaBody2, updatePlanBody2, addAdminUserBody2, updatePlatformConfigBody2, updateFreeOrgLimitBody2, adminSetOrgHarnessBody2, adminSetHubHarnessBody2, adminScopedTargetBody2, updatePricingPlanBody2, dataExplorerSearchQuery2, dataExplorerOrgIdParam2, dataExplorerHubIdParam2, dataExplorerConvIdParam2, dataExplorerDoInstancesQuery2, dataExplorerNsIdParam2, dataExplorerKvKeysQuery2, dataExplorerKvKeyParam2, uuidOrHexId2, dataExplorerDeleteOrgParam2, dataExplorerDeleteHubParam2, dataExplorerDeleteConvParam2, dataExplorerDeleteUserParam2, dataExplorerDeleteQuery2, dataExplorerKvDeleteQuery2, pitrDoNamespace2, pitrBookmarkParam2, pitrRestoreBody2, healthSamplingTriggerBody2, dataExplorerDebugDoType2, DEBUG_READ_MAX_LIMIT2, DEBUG_READ_DEFAULT_LIMIT2, DEBUG_DO_HEX_PREFIX2, debugDoEntityId2, debugTableName2, dataExplorerDebugTablesParam2, dataExplorerDebugRowsParam2, dataExplorerDebugRowsQuery2, dataExplorerDebugAnalyticsTable2, debugUuid2, dataExplorerDebugAnalyticsRowsParam2, dataExplorerDebugAnalyticsRowsQuery2, debugHubConvParam2, debugMessageIdQuery2, sandboxEgressPolicy2, SANDBOX_EXEC_MAX_CMD_LENGTH2, SANDBOX_EXEC_MAX_ALLOWLIST2, SANDBOX_EXEC_MAX_TIMEOUT_MS2, adminSandboxExecBody2, whatsappCallbackBody2, authMeResponse2, wsTicketResponse2, sessionCheckResponse2, logoutResponse2, magicCodeSendBody2, magicCodeSendResponse2, magicCodeVerifyBody2, magicCodeVerifyResponse2, browserParams2, browserFoldersQuery2, browserFilesQuery2, stateOperationBody2, conversationListResourcesQuery2, conversationReadResourceQuery2, listPendingSchedulesQuery2, listHubAggregateSchedulesQuery2, reportSourceSchema2, intakeReportSourceSchema2, reportClassificationSchema2, reportStatusSchema2, reportLocaleSchema2, reportMessageAuthorRoleSchema2, sentryRefStatusSchema2, createReportBody2, editReportBody2, contestReportBody2, reporterListQuery2, listReportsQuery2, GITHUB_ISSUE_URL_REGEX2, githubIssueUrlSchema2, transitionReportBody2, groupReportsBody2, holdReportBody2, clickhouseReadyResponse2, bootstrapQuery2, requestSnapshotChunkMessage2, MAX_NAME_LENGTH3, MAX_VALUE_LENGTH2, MAX_TAGS2, MAX_TAG_LENGTH2, MAX_SCOPE_HUBS2, MAX_SCOPE_TAGS2, vaultSecretScopeSchema2, vaultCreateBody2, vaultUpdateBody2, PERMISSIONS2, MAX_NAME_LENGTH22, MAX_HUBS_PER_GRANT2, MAX_HUB_TAGS_PER_GRANT2, MAX_GRANTS2, permissionEnum2, grantScopeSchema2, grantSchema2, createTokenBody2, tokenOrgIdParam2, tokenGrantScopeSchema2, tokenGrantSchema2, tokenMetadataSchema2, listTokensResponse2, createTokenResponse2, orgTokenSummarySchema2, listOrgTokensResponse2, invitePreviewQuery2, invitePreviewResponse2, discordTier2, discordBillingCycle2, discordMetadata2, discordOAuthStartResponse2, discordOAuthFinalizeBody2, discordOAuthFinalizeResponse2, discordDisconnectResponse2, jsonSchemaSchema2, hubUserIdentity2, stateValueEntry2, getHubUserContextResponse2, updateHubUserBody2, updateHubUserResponse2, unlockHubUserNameResponse2, stateResetParams2, stateResetResponse2, hubAlertsParam2, hubAlertSeverity2, hubAlert2, hubAlertsListResponse2, noticeSeveritySchema2, noticeStatusSchema2, NOTICE_SCOPE_REGEX2, noticeScopeSchema2, noticeLinkSchema2, createNoticeBody2, updateNoticeBody2, listNoticesQuery2, noticeIdParamSchema2, templateLocaleSchema2, TEMPLATE_SLUG_REGEX2, templateSlugSchema2, templateStatusSchema2, templateFileMapSchema2, TEMPLATE_INSTANCE_ID_KEYS, TEMPLATE_OPAQUE_BLOB_KEYS, TEMPLATE_AUTHOR_DATA_KEYS, templateTextSchema2, templateUsesEntrySchema2, templateUsesSchema2, templateYamlLocaleEntry2, templateYamlWayaiBlock2, templateTagsSchema2, templateYamlSchema2, templateHeroSchema2, templatePushLocaleSchema2, templatePushBody2, templateListQuery2, templateSlugParam2, templateDetailQuery2, ADMIN_SKILL_NAME_REGEX2, adminSkillNameParam2;
12782
+ var uuidSchema2, paginationSchema3, timestampSchema2, idParamSchema2, clientOptionalString2, clientOptionalBoolean2, clientOptionalNumber2, messageAttachment2, MAX_MESSAGE_BODY_BYTES2, MAX_ATTACHMENTS_PER_MESSAGE2, primaryRegionSchema2, placementSourceSchema2, orgIdParam2, orgAdminIdParam2, createOrganizationBody2, updateOrganizationBody2, addOrgAdminBody2, AUTH_TYPE3, ORG_CREDENTIAL_AUTH_TYPES3, AUTH_TYPE_DISPLAY3, LEGACY_AUTH_TYPE_MAP3, VALID_AUTH_TYPES3, AGENT_ROLES2, SAFE_USER_ID_REGEX2, SUPPORTED_LOCALES2, SUMMARIZATION_THRESHOLD_MIN2, SUMMARIZATION_THRESHOLD_MAX2, summarizationThresholdField2, monitorConfigField2, agentIdParam2, listAgentsQuery2, agentConnectionsQuery2, createAgentBody2, updateAgentBody2, AGENT_PARAMETER_TYPES2, AGENT_PARAMETER_NAME_REGEX2, agentParameterCreateSchema2, MAX_AGENT_PARAMETERS_PER_REQUEST2, createAgentParametersBody2, SLUG_REGEX2, slugSchema2, INVISIBLE_NAME_CHARS2, MAX_KANBAN_STATUSES2, MAX_FOLLOWUPS_PER_STATUS2, MAX_LANES2, MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES2, RESERVED_TEMPLATE_DUMP_NAME2, kanbanStatusSlugSchema2, followupSchema2, EXCLUSIVE_FLAG_PAIRS2, kanbanStatusSchema2, kanbanStatusesArraySchema2, laneSchema2, lanesArraySchema2, hubIdParam2, hubAdminIdParam2, hubUserIdParam2, hubIdentityIdParam2, hubTeamIdParam2, hubTeamUserDeleteParam2, hubSchemaQuery2, PREVIEW_LABEL_MAX_LENGTH2, MAX_ENDED_INDEX_RETENTION_DAYS2, previewLabelField2, createHubBody2, updateHubBody2, addHubAdminBody2, addHubIdentityAuthorizationBody2, contactDecisionBody2, approveContactBody2, listContactAccessQuery2, createHubTeamBody2, updateHubTeamBody2, addHubTeamUserBody2, reassignHubUserBody2, replicatePreviewBody2, updateChannelTestIdentitiesBody2, claimCodeChannelParam2, claimCodeDeleteParam2, connectionIdParam2, connectorIdParam2, listConnectionsQuery2, deleteConnectionQuery2, addConnectionBody2, editConnectionBody2, PRODUCTION_DIRECT_FIELDS2, setProductionCredentialBody2, registerWhatsappQuery2, registerWhatsappBody2, retryProvisioningQuery2, resendDomainStatusQuery2, PLACEHOLDER_TOKENS2, ALLOWED_TYPES2, SUBSCHEMA_OBJECT_KEYWORDS2, SUBSCHEMA_LIST_KEYWORDS2, SUBSCHEMA_MAP_KEYWORDS2, MAX_SCHEMA_DEPTH2, toolIdParam2, listToolsQuery2, toolAgentQuery2, deleteToolQuery2, toolConnectionsQuery2, nativeToolIdSchema2, addNativeToolBody2, addMcpToolBody2, createCustomToolBody2, updateCustomToolBody2, updateToolExecutionConfigBody2, initialValueCreateSchema2, initialValueUpdateSchema2, stateIdParam2, listStatesQuery2, stateNameSchema2, createStateBody2, updateStateBody2, reorderStatesBody2, variantAiModeSchema2, experimentStatusSchema2, overlayUpdateSchema2, experimentIdParam2, variantIdParam2, listExperimentsQuery2, listVariantsQuery2, listOverridesQuery2, deleteOverrideQuery2, createExperimentBody2, updateExperimentBody2, setExperimentStatusBody2, createVariantBody2, updateVariantBody2, upsertOverrideBody2, orgTagIdParam2, listOrgTagsQuery2, createOrgTagBody2, updateOrgTagBody2, orgCredentialIdParam2, listOrgCredentialsQuery2, createOrgCredentialBody2, updateOrgCredentialBody2, orgResourceIdParam2, orgResourceFileIdParam2, orgResourceFolderIdParam2, hubOrgResourceParam2, listOrgResourcesQuery2, orgIdQuery2, createOrgResourceBody2, updateOrgResourceBody2, createOrgResourceFolderBody2, updateOrgResourceFolderBody2, uploadOrgResourceFileBody2, updateOrgResourceFileBody2, uploadOrgSkillZipBody2, linkOrgResourceBody2, resourceIdParam2, listResourcesQuery2, createResourceBody2, updateResourceBody2, syncSkillsBody2, resourceFileIdParam2, listResourceFilesQuery2, createResourceFileBody2, updateResourceFileBody2, uploadResourceFileBody2, uploadSkillZipBody2, resourceFolderIdParam2, listResourceFoldersQuery2, createResourceFolderBody2, updateResourceFolderBody2, agentResourceQuery2, hubResourceQuery2, linkAgentResourceBody2, updateAgentResourceBody2, unlinkAgentResourceQuery2, navItemSchema2, hubCountResetBody2, navItemCountResetBody2, typingBody2, analyticsHubIdParam2, analyticsVariableIdParam2, updateVariablePinBody2, updateAnalyticsViewBody2, NUMERIC_FILTER_OPS2, TEXT_FILTER_OPS2, CATEGORICAL_FILTER_OPS2, VARIABLE_FILTER_OPS2, STRUCTURED_QUERY_OPS2, STRUCTURED_QUERY_AGGREGATIONS2, filterValueSchema2, conversationsBody2, analyticsConversationIdParam2, messagesQuery2, conversationDetailDataQuery2, analyticsDataBody2, structuredQueryBody2, analyticsSqlBody2, analyticsSqlSchemaQuery2, EVAL_PACING_PRESET_NAMES2, PACING_INTERVAL_MIN_MS2, PACING_INTERVAL_MAX_MS2, EVAL_RUN_DEADLINE_MIN_MS2, EVAL_RUN_DEADLINE_MAX_MS2, paginationSchema22, evalIdParam2, sessionIdParam2, scenarioSetIdParam2, hubIdQuery2, EVAL_INPUT_ROLES2, EVAL_INPUT_ROLE_LIST2, ROLE_ECHO_MAX2, createEvalBody2, updateEvalBody2, getEvalsQuery2, toggleEvalBody2, bulkToggleEvalsBody2, pacingConfigSchema2, sessionConfigSchema2, createSessionBody2, getSessionsQuery2, getSessionResultsQuery2, getSessionRunsQuery2, evalAnalyticsQuery2, getSessionCostQuery2, compareSessionsQuery2, evalsSqlBody2, evalsSqlSchemaQuery2, exportResultsQuery2, validateEvalBody2, hubAgentsQuery2, createScenarioSetBody2, updateScenarioSetBody2, scenarioSetsHubQuery2, createScenarioFromConversationBody2, createJourneyFromConversationBody2, journeyIdParam2, journeyToolCallSchema2, journeyTurnSchema2, journeyStepOverrideSchema2, fixtureField2, createJourneyBody2, updateJourneyBody2, getConversationsQuery2, getMessagesQuery2, appMessageSenderType2, appMessageReceiverType2, appMessageBody2, updateUserBody2, updateProfileBody2, pathnameRegex2, updatePreferencesBody2, registerPushTokenBody2, deletePushTokenQuery2, activityQuery2, deletionModeSchema2, deletionRequestBody2, archiveHubIdParam2, archiveConversationParams2, archiveListQuery2, archiveMessageObservabilityParams2, conversationIdParam2, claimBody2, releaseBody2, transferBody2, closeBody2, additionalContextPayloadSchema2, kanbanUpdateBody2, annotateConversationBody2, observabilityParams2, observabilityListParams2, deleteUserConversationsBody2, sendMessageBody2, listConversationsQuery2, getConversationDetailParams2, getConversationDetailQuery2, listWhatsAppTemplatesQuery2, sendWhatsAppTemplateBody2, billingOrgIdParam2, subscriptionItemParams2, spendCapBody2, growthPacksBody2, portalSessionBody2, checkoutSessionBody2, updateBillingCurrencyBody2, invoicesQuery2, downloadBody2, uploadQuery2, signUrlBody2, outboundSchemaQuery2, templateIdParam2, listTemplatesQuery2, deleteTemplateQuery2, templateStatusQuery2, createTemplateBody2, updateTemplateBody2, submitTemplateBody2, testTemplateBody2, contactIdParam2, listContactsQuery2, createContactBody2, updateContactBody2, listIdParam2, listListsQuery2, listListContactsQuery2, createListBody2, updateListBody2, addListContactsBody2, removeListContactsBody2, scheduleIdParam2, listSchedulesQuery2, listExecutionsQuery2, createScheduleBody2, updateScheduleBody2, uuidPattern2, ciUuidSchema2, hubAsCodeConfigSchema2, ciPullHubIdParam2, ciBranchParam2, ciPullQuery2, ciHubsQuery2, ciLookupQuery2, ciBranchesQuery2, ciSyncBody2, ciPushBody2, ciDiffBody2, ciPublishBody2, ciPublishPreviewBody2, ciSyncMcpBody2, ciOrgResourcesParam2, orgResourcesConfigSchema2, ciOrgResourcesPushBody2, ciOrgResourcesDiffBody2, adminOrgIdParam2, adminOrgAdminIdParam2, adminUserIdParam2, adminPlanIdParam2, adminHubIdParam2, adminOrganizationsQuery2, adminUserSearchQuery2, kanbanSlugMigrationQuery2, adjustQuotaBody2, updatePlanBody2, addAdminUserBody2, updatePlatformConfigBody2, updateFreeOrgLimitBody2, adminSetOrgHarnessBody2, adminSetHubHarnessBody2, adminScopedTargetBody2, updatePricingPlanBody2, dataExplorerSearchQuery2, dataExplorerOrgIdParam2, dataExplorerHubIdParam2, dataExplorerConvIdParam2, dataExplorerDoInstancesQuery2, dataExplorerNsIdParam2, dataExplorerKvKeysQuery2, dataExplorerKvKeyParam2, uuidOrHexId2, dataExplorerDeleteOrgParam2, dataExplorerDeleteHubParam2, dataExplorerDeleteConvParam2, dataExplorerDeleteUserParam2, dataExplorerDeleteQuery2, dataExplorerKvDeleteQuery2, pitrDoNamespace2, pitrBookmarkParam2, pitrRestoreBody2, healthSamplingTriggerBody2, dataExplorerDebugDoType2, DEBUG_READ_MAX_LIMIT2, DEBUG_READ_DEFAULT_LIMIT2, DEBUG_DO_HEX_PREFIX2, debugDoEntityId2, debugTableName2, dataExplorerDebugTablesParam2, dataExplorerDebugRowsParam2, dataExplorerDebugRowsQuery2, dataExplorerDebugAnalyticsTable2, debugUuid2, dataExplorerDebugAnalyticsRowsParam2, dataExplorerDebugAnalyticsRowsQuery2, debugHubConvParam2, debugMessageIdQuery2, sandboxEgressPolicy2, SANDBOX_EXEC_MAX_CMD_LENGTH2, SANDBOX_EXEC_MAX_ALLOWLIST2, SANDBOX_EXEC_MAX_TIMEOUT_MS2, adminSandboxExecBody2, whatsappCallbackBody2, authMeResponse2, wsTicketResponse2, sessionCheckResponse2, logoutResponse2, magicCodeSendBody2, magicCodeSendResponse2, magicCodeVerifyBody2, magicCodeVerifyResponse2, browserParams2, browserFoldersQuery2, browserFilesQuery2, stateOperationBody2, conversationListResourcesQuery2, conversationReadResourceQuery2, listPendingSchedulesQuery2, listHubAggregateSchedulesQuery2, reportSourceSchema2, intakeReportSourceSchema2, reportClassificationSchema2, reportStatusSchema2, reportLocaleSchema2, reportMessageAuthorRoleSchema2, sentryRefStatusSchema2, createReportBody2, editReportBody2, contestReportBody2, reporterListQuery2, listReportsQuery2, GITHUB_ISSUE_URL_REGEX2, githubIssueUrlSchema2, transitionReportBody2, groupReportsBody2, holdReportBody2, clickhouseReadyResponse2, bootstrapQuery2, requestSnapshotChunkMessage2, MAX_NAME_LENGTH3, MAX_VALUE_LENGTH2, MAX_TAGS2, MAX_TAG_LENGTH2, MAX_SCOPE_HUBS2, MAX_SCOPE_TAGS2, vaultSecretScopeSchema2, vaultCreateBody2, vaultUpdateBody2, PERMISSIONS2, MAX_NAME_LENGTH22, MAX_HUBS_PER_GRANT2, MAX_HUB_TAGS_PER_GRANT2, MAX_GRANTS2, permissionEnum2, grantScopeSchema2, grantSchema2, createTokenBody2, tokenOrgIdParam2, tokenGrantScopeSchema2, tokenGrantSchema2, tokenMetadataSchema2, listTokensResponse2, createTokenResponse2, orgTokenSummarySchema2, listOrgTokensResponse2, invitePreviewQuery2, invitePreviewResponse2, discordTier2, discordBillingCycle2, discordMetadata2, discordOAuthStartResponse2, discordOAuthFinalizeBody2, discordOAuthFinalizeResponse2, discordDisconnectResponse2, jsonSchemaSchema2, hubUserIdentity2, stateValueEntry2, getHubUserContextResponse2, updateHubUserBody2, updateHubUserResponse2, unlockHubUserNameResponse2, stateResetParams2, stateResetResponse2, hubAlertsParam2, hubAlertSeverity2, hubAlert2, hubAlertsListResponse2, noticeSeveritySchema2, noticeStatusSchema2, NOTICE_SCOPE_REGEX2, noticeScopeSchema2, noticeLinkSchema2, createNoticeBody2, updateNoticeBody2, listNoticesQuery2, noticeIdParamSchema2, templateLocaleSchema2, TEMPLATE_SLUG_REGEX2, templateSlugSchema2, templateStatusSchema2, templateFileMapSchema2, TEMPLATE_INSTANCE_ID_KEYS, TEMPLATE_OPAQUE_BLOB_KEYS, TEMPLATE_AUTHOR_DATA_KEYS, templateTextSchema2, templateUsesEntrySchema2, templateUsesSchema2, templateYamlLocaleEntry2, templateYamlWayaiBlock2, templateTagsSchema2, templateYamlSchema2, templateHeroSchema2, templatePushLocaleSchema2, templatePushBody2, templateListQuery2, templateSlugParam2, templateDetailQuery2, ADMIN_SKILL_NAME_REGEX2, adminSkillNameParam2;
12446
12783
  var init_contracts = __esm({
12447
12784
  "../../packages/core/dist/contracts/index.js"() {
12448
12785
  "use strict";
@@ -12503,6 +12840,30 @@ var init_contracts = __esm({
12503
12840
  idParamSchema2 = external_exports.object({
12504
12841
  id: uuidSchema2
12505
12842
  });
12843
+ clientOptionalString2 = external_exports.string().nullish().transform((v) => v ?? void 0);
12844
+ clientOptionalBoolean2 = external_exports.boolean().nullish().transform((v) => v ?? void 0);
12845
+ clientOptionalNumber2 = external_exports.number().nullish().transform((v) => v ?? void 0);
12846
+ messageAttachment2 = external_exports.object({
12847
+ /**
12848
+ * Capped at the same 255 the storage layer already truncates names to, so nothing
12849
+ * legitimate is lost — every filesystem caps there, and `sanitizeFileName` sliced
12850
+ * longer names anyway.
12851
+ *
12852
+ * The bound is load-bearing, not hygiene: the RAW name is written to R2
12853
+ * `customMetadata.originalFileName`, and R2 rejects oversized metadata. An unbounded
12854
+ * name let a client make the R2 write throw a generic storage error — indistinguishable
12855
+ * from a real outage — which pages us via `logger.error` and, on the app channel, is
12856
+ * read as "we lost the file" and escalates the user to a human. Client input must not
12857
+ * be able to impersonate an infrastructure failure (gh #3365).
12858
+ */
12859
+ file_name: external_exports.string().max(255),
12860
+ /** Base64. Bounded by the route's bodyLimit, not by this schema. */
12861
+ file_binary: external_exports.string(),
12862
+ file_size: clientOptionalNumber2,
12863
+ file_extension: clientOptionalString2
12864
+ });
12865
+ MAX_MESSAGE_BODY_BYTES2 = 10 * 1024 * 1024;
12866
+ MAX_ATTACHMENTS_PER_MESSAGE2 = 20;
12506
12867
  primaryRegionSchema2 = external_exports.enum([
12507
12868
  "wnam",
12508
12869
  "enam",
@@ -12706,7 +13067,7 @@ var init_contracts = __esm({
12706
13067
  eventName: external_exports.string().optional(),
12707
13068
  additional_instructions: external_exports.string().optional(),
12708
13069
  additional_context_schema: external_exports.record(external_exports.unknown()).refine(
12709
- (s) => JSON.stringify(s).length <= MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES2,
13070
+ (s) => withinJsonLength2(s, MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES2),
12710
13071
  `additional_context_schema must be at most ${MAX_ADDITIONAL_CONTEXT_SCHEMA_BYTES2} bytes when JSON-serialized`
12711
13072
  ).optional(),
12712
13073
  followups: external_exports.array(followupSchema2).max(MAX_FOLLOWUPS_PER_STATUS2, `followups must have at most ${MAX_FOLLOWUPS_PER_STATUS2} entries`).optional(),
@@ -12932,6 +13293,9 @@ var init_contracts = __esm({
12932
13293
  replicatePreviewBody2 = external_exports.object({
12933
13294
  preview_label: previewLabelField2
12934
13295
  });
13296
+ updateChannelTestIdentitiesBody2 = external_exports.object({
13297
+ test_identities: external_exports.array(external_exports.string().max(320)).max(1e3)
13298
+ });
12935
13299
  claimCodeChannelParam2 = external_exports.object({
12936
13300
  id: uuidSchema2,
12937
13301
  channelId: uuidSchema2
@@ -13582,12 +13946,15 @@ var init_contracts = __esm({
13582
13946
  hubIdQuery2 = external_exports.object({
13583
13947
  hub_id: external_exports.string().uuid()
13584
13948
  });
13949
+ EVAL_INPUT_ROLES2 = ["user", "system"];
13950
+ EVAL_INPUT_ROLE_LIST2 = EVAL_INPUT_ROLES2.map((r) => `"${r}"`).join(" or ");
13951
+ ROLE_ECHO_MAX2 = 40;
13585
13952
  createEvalBody2 = external_exports.object({
13586
13953
  eval: external_exports.record(external_exports.unknown())
13587
- });
13954
+ }).superRefine(refineEvalMessageTextRole2);
13588
13955
  updateEvalBody2 = external_exports.object({
13589
13956
  eval: external_exports.record(external_exports.unknown())
13590
- });
13957
+ }).superRefine(refineEvalMessageTextRole2);
13591
13958
  getEvalsQuery2 = external_exports.object({
13592
13959
  hub_id: external_exports.string().uuid(),
13593
13960
  agent_id: external_exports.string().uuid().optional(),
@@ -13759,6 +14126,15 @@ var init_contracts = __esm({
13759
14126
  hub_user_id: external_exports.string().optional(),
13760
14127
  search_filter: external_exports.string().optional(),
13761
14128
  hub_id: external_exports.string().uuid().optional(),
14129
+ // NON-authorizing single-hub narrow. Unlike `hub_id` (which runs the
14130
+ // grant-gated `loadHub('hub:read')` and so throws for grant-less end users /
14131
+ // team members), `scope_hub_id` INTERSECTS the caller's already-resolved hub
14132
+ // roster server-side. Intersecting the caller's own roster IS the
14133
+ // authorization — a hub the caller isn't in narrows to empty and leaks
14134
+ // nothing. Continuous history sends it to take the single-hub ended-index
14135
+ // path (one HubDO read, accurate uncapped total) instead of the all-hub
14136
+ // fan-out it would otherwise discard client-side (gh #3319).
14137
+ scope_hub_id: external_exports.string().uuid().optional(),
13762
14138
  conversation_id: external_exports.string().uuid().optional(),
13763
14139
  // 'ended' = recently-closed, served warm from the HubDO index (≤ retention
13764
14140
  // window). 'archived' = the full closed-conversation history from ClickHouse.
@@ -13799,17 +14175,8 @@ var init_contracts = __esm({
13799
14175
  });
13800
14176
  }
13801
14177
  });
13802
- clientOptionalString2 = external_exports.string().nullish().transform((v) => v ?? void 0);
13803
- clientOptionalBoolean2 = external_exports.boolean().nullish().transform((v) => v ?? void 0);
13804
14178
  appMessageSenderType2 = external_exports.enum(["user", "team"]);
13805
14179
  appMessageReceiverType2 = external_exports.enum(["user", "team", "agent", "assistant"]).transform((v) => v === "assistant" ? "agent" : v);
13806
- appMessageAttachment2 = external_exports.object({
13807
- file_name: external_exports.string(),
13808
- file_binary: external_exports.string(),
13809
- file_size: external_exports.number().nullish().transform((v) => v ?? void 0),
13810
- file_extension: clientOptionalString2
13811
- });
13812
- MAX_ATTACHMENTS_PER_MESSAGE2 = 20;
13813
14180
  appMessageBody2 = external_exports.object({
13814
14181
  // Message content — three historical aliases. All optional: an attachment-only
13815
14182
  // or voice-only message carries no text.
@@ -13838,7 +14205,7 @@ var init_contracts = __esm({
13838
14205
  // Pre-generated by the client so the optimistic bubble and the stored row share
13839
14206
  // a key (transcription live-updates land on the same row instead of duplicating).
13840
14207
  message_id: clientOptionalString2,
13841
- attachments: external_exports.array(appMessageAttachment2).max(MAX_ATTACHMENTS_PER_MESSAGE2).nullish().transform((v) => v ?? void 0),
14208
+ attachments: external_exports.array(messageAttachment2).max(MAX_ATTACHMENTS_PER_MESSAGE2).nullish().transform((v) => v ?? void 0),
13842
14209
  // Base64-encoded audio for STT. Size-capped in the route (the cap is a byte
13843
14210
  // budget tied to the /channels/* bodyLimit, not a shape rule).
13844
14211
  audio_file: clientOptionalString2
@@ -13965,7 +14332,7 @@ var init_contracts = __esm({
13965
14332
  hub_type: external_exports.enum(["chat", "task"]).default("chat"),
13966
14333
  user_id: external_exports.string().optional()
13967
14334
  });
13968
- additionalContextPayloadSchema2 = external_exports.record(external_exports.unknown()).refine((r) => JSON.stringify(r).length <= 16384, {
14335
+ additionalContextPayloadSchema2 = external_exports.record(external_exports.unknown()).refine((r) => withinJsonLength2(r, 16384), {
13969
14336
  message: "additional_context payload must be at most 16384 bytes when JSON-serialized"
13970
14337
  });
13971
14338
  kanbanUpdateBody2 = external_exports.object({
@@ -14009,11 +14376,27 @@ var init_contracts = __esm({
14009
14376
  ]);
14010
14377
  sendMessageBody2 = external_exports.object({
14011
14378
  hub_id: external_exports.string().uuid(),
14012
- message: external_exports.string().min(1).max(5e4),
14379
+ /**
14380
+ * Optional ONLY when `attachments` carries the payload — see the refinement below.
14381
+ * An attachment-only message (a photo with no caption) is the ordinary WhatsApp
14382
+ * gesture, so the endpoint that exists to rehearse inbound flows has to express it.
14383
+ * Mirrors `appMessageBody`, where content is optional for the same reason.
14384
+ */
14385
+ message: external_exports.string().min(1).max(5e4).optional(),
14013
14386
  /** For chat hubs: optional — automatically continues the user's active conversation (or creates one).
14014
14387
  * For task hubs: required to continue an existing conversation. Omit to start a new task conversation. */
14015
- conversation_id: external_exports.string().uuid().optional()
14016
- });
14388
+ conversation_id: external_exports.string().uuid().optional(),
14389
+ /**
14390
+ * Base64 attachments, delivered over the hub's `app` channel exactly as a real
14391
+ * channel delivers them. Total bytes are bounded by the route's bodyLimit —
14392
+ * `/api/*` carries no global one (only `/webhooks/*` and `/channels/*` do), so the
14393
+ * route declares its own rather than inheriting an unbounded upload path.
14394
+ */
14395
+ attachments: external_exports.array(messageAttachment2).max(MAX_ATTACHMENTS_PER_MESSAGE2).optional()
14396
+ }).refine(
14397
+ (b) => (b.message?.length ?? 0) > 0 || (b.attachments?.length ?? 0) > 0,
14398
+ { message: "message or attachments required" }
14399
+ );
14017
14400
  listConversationsQuery2 = external_exports.object({
14018
14401
  hub_id: external_exports.string().uuid(),
14019
14402
  status: external_exports.enum(["agent", "team", "ended"]).optional(),
@@ -14225,6 +14608,7 @@ var init_contracts = __esm({
14225
14608
  refineHubAsCodeCustomTools2(config, ctx);
14226
14609
  refineHubAsCodeKanbanStatuses2(config, ctx);
14227
14610
  refineHubAsCodeLanes2(config, ctx);
14611
+ refineHubAsCodeEvals2(config, ctx);
14228
14612
  });
14229
14613
  ciPullHubIdParam2 = external_exports.object({
14230
14614
  hub_id: ciUuidSchema2
@@ -15437,7 +15821,7 @@ async function useCommand(args2) {
15437
15821
  process.exit(1);
15438
15822
  }
15439
15823
  let hubId;
15440
- if (UUID_RE.test(target)) {
15824
+ if (UUID_RE2.test(target)) {
15441
15825
  hubId = target;
15442
15826
  } else {
15443
15827
  const workspace = detectWorkspace();
@@ -15617,37 +16001,109 @@ var send_message_exports = {};
15617
16001
  __export(send_message_exports, {
15618
16002
  sendMessageCommand: () => sendMessageCommand
15619
16003
  });
16004
+ import * as fs17 from "fs";
16005
+ import * as path22 from "path";
16006
+ function statAttachment(filePath) {
16007
+ let stat;
16008
+ try {
16009
+ stat = fs17.statSync(filePath);
16010
+ } catch {
16011
+ console.error(`Error: file not found: ${filePath}`);
16012
+ process.exit(1);
16013
+ }
16014
+ if (stat.isDirectory()) {
16015
+ console.error(`Error: not a file: ${filePath}`);
16016
+ process.exit(1);
16017
+ }
16018
+ return { filePath, size: stat.size };
16019
+ }
16020
+ function readAttachment(filePath, size) {
16021
+ const fileName = path22.basename(filePath);
16022
+ const ext = path22.extname(fileName).replace(/^\./, "");
16023
+ return {
16024
+ file_name: fileName,
16025
+ file_binary: fs17.readFileSync(filePath).toString("base64"),
16026
+ file_size: size,
16027
+ ...ext && { file_extension: ext }
16028
+ };
16029
+ }
16030
+ function usage() {
16031
+ console.error('Usage: wayai send-message [options] ["message text"]');
16032
+ console.error("");
16033
+ console.error("Options:");
16034
+ console.error(" -c, --conversation <id> Continue an existing conversation");
16035
+ console.error(" -f, --file <path> Attach a file (repeatable)");
16036
+ console.error("");
16037
+ console.error("The message text is optional when at least one --file is attached.");
16038
+ console.error("The hub type (chat/task) is determined automatically from the hub.");
16039
+ console.error("Chat hubs auto-continue the active conversation (or create one).");
16040
+ console.error("Task hubs create a new conversation unless -c is provided.");
16041
+ process.exit(1);
16042
+ }
15620
16043
  async function sendMessageCommand(args2) {
15621
16044
  const hubId = resolveActiveHubId(args2);
15622
16045
  const { config, accessToken } = await requireAuth();
15623
16046
  requireRepoConfig();
15624
16047
  let conversationId;
15625
16048
  let message;
16049
+ const filePaths = [];
15626
16050
  for (let i = 0; i < args2.length; i++) {
15627
16051
  const arg = args2[i];
15628
16052
  if (arg === "-c" || arg === "--conversation") {
15629
16053
  conversationId = args2[++i];
16054
+ } else if (arg === "-f" || arg === "--file") {
16055
+ const filePath = args2[++i];
16056
+ if (!filePath) {
16057
+ console.error("Error: --file requires a path");
16058
+ process.exit(1);
16059
+ }
16060
+ filePaths.push(filePath);
15630
16061
  } else if (!arg.startsWith("-")) {
15631
16062
  message = arg;
15632
16063
  }
15633
16064
  }
15634
- if (!message) {
15635
- console.error('Usage: wayai send-message [options] "message text"');
15636
- console.error("");
15637
- console.error("Options:");
15638
- console.error(" -c, --conversation <id> Continue an existing conversation");
15639
- console.error("");
15640
- console.error("The hub type (chat/task) is determined automatically from the hub.");
15641
- console.error("Chat hubs auto-continue the active conversation (or create one).");
15642
- console.error("Task hubs create a new conversation unless -c is provided.");
16065
+ if (!message && filePaths.length === 0) usage();
16066
+ if (filePaths.length > MAX_ATTACHMENTS_PER_MESSAGE2) {
16067
+ console.error(`Error: at most ${MAX_ATTACHMENTS_PER_MESSAGE2} files per message (got ${filePaths.length}).`);
16068
+ process.exit(1);
16069
+ }
16070
+ const stats = filePaths.map(statAttachment);
16071
+ const filesTotal = stats.reduce((sum, s) => sum + base64Length(s.size), 0);
16072
+ const fileDetail = () => stats.map((s) => `${path22.basename(s.filePath)} ${asMb(s.size)} MB`).join(", ");
16073
+ if (filesTotal > MAX_MESSAGE_BODY_BYTES2) {
16074
+ console.error(
16075
+ `Error: ${fileDetail()} encode to ~${asMb(filesTotal)} MB, over the ${asMb(MAX_MESSAGE_BODY_BYTES2)} MB per-request limit.`
16076
+ );
16077
+ console.error("Base64 inflates a file by about a third, so ~7 MB of files is the practical ceiling.");
16078
+ process.exit(1);
16079
+ }
16080
+ const attachments = stats.map((s) => readAttachment(s.filePath, s.size));
16081
+ const bodyBytes = Buffer.byteLength(
16082
+ JSON.stringify({
16083
+ hub_id: hubId,
16084
+ ...message && { message },
16085
+ ...conversationId && { conversation_id: conversationId },
16086
+ ...attachments.length > 0 && { attachments }
16087
+ }),
16088
+ "utf8"
16089
+ );
16090
+ if (bodyBytes > MAX_MESSAGE_BODY_BYTES2) {
16091
+ console.error(
16092
+ `Error: the request is ~${asMb(bodyBytes)} MB, over the ${asMb(MAX_MESSAGE_BODY_BYTES2)} MB per-request limit.`
16093
+ );
16094
+ if (stats.length > 0) console.error(`Attachments: ${fileDetail()} (base64 adds about a third).`);
15643
16095
  process.exit(1);
15644
16096
  }
15645
16097
  const client = new ApiClient({ apiUrl: config.api_url, accessToken });
15646
16098
  const result = await client.sendMessage(hubId, message, {
15647
- conversationId
16099
+ conversationId,
16100
+ ...attachments.length > 0 && { attachments }
15648
16101
  });
15649
16102
  console.log(`Conversation: ${result.conversation_id}`);
15650
16103
  console.log(`Status: ${result.status}`);
16104
+ if (attachments.length > 0 && result.status !== "error") {
16105
+ console.log(`Attached: ${attachments.map((a) => a.file_name).join(", ")}`);
16106
+ }
15651
16107
  if (result.status_reason) {
15652
16108
  console.log(`Reason: ${result.status_reason}`);
15653
16109
  }
@@ -15664,13 +16120,17 @@ async function sendMessageCommand(args2) {
15664
16120
  console.log("(Agent processing failed \u2014 user message was stored)");
15665
16121
  }
15666
16122
  }
16123
+ var asMb, base64Length;
15667
16124
  var init_send_message = __esm({
15668
16125
  "src/commands/send-message.ts"() {
15669
16126
  "use strict";
16127
+ init_contracts();
15670
16128
  init_auth();
15671
16129
  init_repo_config();
15672
16130
  init_workspace();
15673
16131
  init_api_client();
16132
+ asMb = (bytes) => (bytes / 1024 / 1024).toFixed(1);
16133
+ base64Length = (bytes) => Math.ceil(bytes / 3) * 4;
15674
16134
  }
15675
16135
  });
15676
16136
 
@@ -17069,8 +17529,8 @@ var eval_capture_exports = {};
17069
17529
  __export(eval_capture_exports, {
17070
17530
  evalCaptureCommand: () => evalCaptureCommand
17071
17531
  });
17072
- import * as fs17 from "fs";
17073
- import * as path22 from "path";
17532
+ import * as fs18 from "fs";
17533
+ import * as path23 from "path";
17074
17534
  import * as yaml7 from "js-yaml";
17075
17535
  function isValidSetName(name) {
17076
17536
  if (name.length === 0 || name === "." || name === "..") return false;
@@ -17083,7 +17543,7 @@ function parseArgs13(args2) {
17083
17543
  process.exit(1);
17084
17544
  }
17085
17545
  const conversationId = args2[0];
17086
- if (!UUID_RE.test(conversationId)) {
17546
+ if (!UUID_RE2.test(conversationId)) {
17087
17547
  console.error(`Invalid conversation ID "${conversationId}". Expected a UUID.`);
17088
17548
  process.exit(1);
17089
17549
  }
@@ -17136,15 +17596,15 @@ async function evalCaptureCommand(args2) {
17136
17596
  const setFolderName = targetSetName;
17137
17597
  const scenarioName = parsed.evalName ?? `Capture ${parsed.conversationId.slice(0, 8)}`;
17138
17598
  const slug = slugify(scenarioName);
17139
- const evalsDir = path22.join(hubFolder, "evals");
17140
- const targetDir = path22.join(evalsDir, setFolderName);
17141
- const targetPath = path22.join(targetDir, `${slug}.yaml`);
17142
- if (!targetPath.startsWith(evalsDir + path22.sep)) {
17143
- console.error(`Resolved path "${path22.relative(hubFolder, targetPath)}" escapes evals/. Aborting.`);
17599
+ const evalsDir = path23.join(hubFolder, "evals");
17600
+ const targetDir = path23.join(evalsDir, setFolderName);
17601
+ const targetPath = path23.join(targetDir, `${slug}.yaml`);
17602
+ if (!targetPath.startsWith(evalsDir + path23.sep)) {
17603
+ console.error(`Resolved path "${path23.relative(hubFolder, targetPath)}" escapes evals/. Aborting.`);
17144
17604
  process.exit(1);
17145
17605
  }
17146
- if (fs17.existsSync(targetPath)) {
17147
- console.error(`File already exists: ${path22.relative(hubFolder, targetPath)}. Use --name to choose a different name.`);
17606
+ if (fs18.existsSync(targetPath)) {
17607
+ console.error(`File already exists: ${path23.relative(hubFolder, targetPath)}. Use --name to choose a different name.`);
17148
17608
  process.exit(1);
17149
17609
  }
17150
17610
  console.log("Resolving scenario set...");
@@ -17176,9 +17636,9 @@ async function evalCaptureCommand(args2) {
17176
17636
  ...captured.evaluator_instructions ? { evaluator_instructions: captured.evaluator_instructions } : {}
17177
17637
  };
17178
17638
  const yamlObj = buildEvalYamlObject(evalEntry, slug);
17179
- fs17.mkdirSync(targetDir, { recursive: true });
17180
- fs17.writeFileSync(targetPath, yaml7.dump(yamlObj, YAML_DUMP_OPTIONS), "utf-8");
17181
- const relPath = path22.relative(process.cwd(), targetPath);
17639
+ fs18.mkdirSync(targetDir, { recursive: true });
17640
+ fs18.writeFileSync(targetPath, yaml7.dump(yamlObj, YAML_DUMP_OPTIONS), "utf-8");
17641
+ const relPath = path23.relative(process.cwd(), targetPath);
17182
17642
  console.log(`
17183
17643
  Wrote ${relPath}`);
17184
17644
  console.log("Run `wayai pull` to refresh the agent display name, then commit. The scenario is already on the platform.");
@@ -17206,7 +17666,7 @@ function parseArgs14(args2) {
17206
17666
  process.exit(1);
17207
17667
  }
17208
17668
  const conversationId = args2[0];
17209
- if (!UUID_RE.test(conversationId)) {
17669
+ if (!UUID_RE2.test(conversationId)) {
17210
17670
  console.error(`Invalid conversation ID "${conversationId}". Expected a UUID.`);
17211
17671
  process.exit(1);
17212
17672
  }
@@ -17288,7 +17748,7 @@ async function evalSessionDeleteCommand(args2) {
17288
17748
  console.error(" wayai eval session delete --all");
17289
17749
  process.exit(1);
17290
17750
  }
17291
- if (sessionId && !UUID_RE.test(sessionId)) {
17751
+ if (sessionId && !UUID_RE2.test(sessionId)) {
17292
17752
  console.error(`Invalid session id: ${sessionId}`);
17293
17753
  process.exit(1);
17294
17754
  }
@@ -18326,7 +18786,7 @@ function parseArgs17(args2) {
18326
18786
  }
18327
18787
  return { connection, orgCredential, field, stdin };
18328
18788
  }
18329
- function usage(msg) {
18789
+ function usage2(msg) {
18330
18790
  if (msg) console.error(`${msg}
18331
18791
  `);
18332
18792
  console.error("Usage: wayai set-connection-credential --hub <id|name> --connection <name|id> ( --org-credential <name> | --field <field> --stdin )");
@@ -18337,17 +18797,17 @@ function usage(msg) {
18337
18797
  async function setConnectionCredentialCommand(args2) {
18338
18798
  const hubId = resolveActiveHubId(args2);
18339
18799
  const parsed = parseArgs17(args2);
18340
- if (!parsed.connection) usage("Missing required flag: --connection <name|id>");
18800
+ if (!parsed.connection) usage2("Missing required flag: --connection <name|id>");
18341
18801
  const orgMode = !!parsed.orgCredential;
18342
18802
  const directMode = !!parsed.field;
18343
18803
  if (orgMode === directMode) {
18344
- usage("Provide exactly one of --org-credential or --field.");
18804
+ usage2("Provide exactly one of --org-credential or --field.");
18345
18805
  }
18346
18806
  if (directMode && !VALID_FIELDS.includes(parsed.field)) {
18347
- usage(`Invalid --field "${parsed.field}". Valid fields: ${VALID_FIELDS.join(", ")}`);
18807
+ usage2(`Invalid --field "${parsed.field}". Valid fields: ${VALID_FIELDS.join(", ")}`);
18348
18808
  }
18349
18809
  if (directMode && !parsed.stdin) {
18350
- usage("--field requires --stdin (the secret is read from stdin, never an argument).");
18810
+ usage2("--field requires --stdin (the secret is read from stdin, never an argument).");
18351
18811
  }
18352
18812
  const { organization_id: organizationId } = requireRepoConfig();
18353
18813
  const { config, accessToken } = await requireAuth();
@@ -18359,27 +18819,27 @@ async function setConnectionCredentialCommand(args2) {
18359
18819
  else if (hubs.some((h) => h.production_hub_id === hubId)) environment = "production";
18360
18820
  }
18361
18821
  if (!environment) {
18362
- usage(`Could not resolve hub "${hubId}". Pull it first (\`wayai pull --hub ${hubId}\`) or check the id.`);
18822
+ usage2(`Could not resolve hub "${hubId}". Pull it first (\`wayai pull --hub ${hubId}\`) or check the id.`);
18363
18823
  }
18364
18824
  const isProduction = environment === "production";
18365
18825
  const { connections } = await client.listConnections(hubId);
18366
18826
  const conn = connections.find(
18367
18827
  (c) => c.connection_id === parsed.connection || c.connection_display_name === parsed.connection
18368
18828
  );
18369
- if (!conn || !conn.connection_id) usage(`Connection "${parsed.connection}" not found on hub ${hubId}.`);
18829
+ if (!conn || !conn.connection_id) usage2(`Connection "${parsed.connection}" not found on hub ${hubId}.`);
18370
18830
  const connectionId = conn.connection_id;
18371
18831
  const body = { hub_id: hubId };
18372
18832
  if (orgMode) {
18373
18833
  const { data: creds } = await client.listOrgCredentials(organizationId);
18374
18834
  const cred = creds.find((c) => c.credential_display_name === parsed.orgCredential);
18375
- if (!cred) usage(`Organization credential "${parsed.orgCredential}" not found.`);
18835
+ if (!cred) usage2(`Organization credential "${parsed.orgCredential}" not found.`);
18376
18836
  body.organization_credential_id = cred.organization_credential_id;
18377
18837
  } else {
18378
18838
  if (process.stdin.isTTY) {
18379
- usage('--field requires the secret on stdin. Example: echo "$SECRET" | wayai set-connection-credential ... --field api_key --stdin');
18839
+ usage2('--field requires the secret on stdin. Example: echo "$SECRET" | wayai set-connection-credential ... --field api_key --stdin');
18380
18840
  }
18381
18841
  const secret = (await readStdin())?.trim();
18382
- if (!secret) usage("No secret received from stdin.");
18842
+ if (!secret) usage2("No secret received from stdin.");
18383
18843
  body[parsed.field] = secret;
18384
18844
  }
18385
18845
  const target = isProduction ? "production" : "preview";
@@ -18405,23 +18865,23 @@ var init_set_connection_credential = __esm({
18405
18865
  });
18406
18866
 
18407
18867
  // src/lib/org-workspace.ts
18408
- import * as fs18 from "fs";
18409
- import * as path23 from "path";
18868
+ import * as fs19 from "fs";
18869
+ import * as path24 from "path";
18410
18870
  import * as yaml8 from "js-yaml";
18411
18871
  function getOrgDir(gitRoot) {
18412
18872
  return resolveLayout(gitRoot).orgDir;
18413
18873
  }
18414
18874
  function orgManifestExists(orgDir) {
18415
- return fs18.existsSync(path23.join(orgDir, ORG_MANIFEST_NAME));
18875
+ return fs19.existsSync(path24.join(orgDir, ORG_MANIFEST_NAME));
18416
18876
  }
18417
18877
  function parseOrgResources(orgDir) {
18418
- const manifestPath = path23.join(orgDir, ORG_MANIFEST_NAME);
18878
+ const manifestPath = path24.join(orgDir, ORG_MANIFEST_NAME);
18419
18879
  let manifest = {};
18420
- if (fs18.existsSync(manifestPath)) {
18421
- manifest = yaml8.load(fs18.readFileSync(manifestPath, "utf-8")) ?? {};
18880
+ if (fs19.existsSync(manifestPath)) {
18881
+ manifest = yaml8.load(fs19.readFileSync(manifestPath, "utf-8")) ?? {};
18422
18882
  }
18423
18883
  const rawResources = Array.isArray(manifest.resources) ? manifest.resources : [];
18424
- const resourcesDir = path23.join(orgDir, "resources");
18884
+ const resourcesDir = path24.join(orgDir, "resources");
18425
18885
  const resources = rawResources.map((res) => {
18426
18886
  const resource = { name: res.name };
18427
18887
  if (res.id) resource.id = res.id;
@@ -18433,8 +18893,8 @@ function parseOrgResources(orgDir) {
18433
18893
  if (res.environment) resource.environment = res.environment;
18434
18894
  if (Array.isArray(res.tags)) resource.tags = res.tags;
18435
18895
  if (Array.isArray(res.folders)) resource.folders = res.folders;
18436
- const resDir = path23.join(resourcesDir, slugify(resource.name));
18437
- if (fs18.existsSync(resDir)) {
18896
+ const resDir = path24.join(resourcesDir, slugify(resource.name));
18897
+ if (fs19.existsSync(resDir)) {
18438
18898
  const files = scanResourceFiles(resDir, "");
18439
18899
  if (files.length > 0) resource.files = files;
18440
18900
  }
@@ -18443,28 +18903,28 @@ function parseOrgResources(orgDir) {
18443
18903
  return { version: 1, resources };
18444
18904
  }
18445
18905
  function writeOrgResources(orgDir, payload) {
18446
- fs18.mkdirSync(orgDir, { recursive: true });
18906
+ fs19.mkdirSync(orgDir, { recursive: true });
18447
18907
  const resources = payload.resources ?? [];
18448
18908
  const manifestResources = resources.map((r) => {
18449
18909
  const { files: _files, ...rest } = r;
18450
18910
  return rest;
18451
18911
  });
18452
- fs18.writeFileSync(
18453
- path23.join(orgDir, ORG_MANIFEST_NAME),
18912
+ fs19.writeFileSync(
18913
+ path24.join(orgDir, ORG_MANIFEST_NAME),
18454
18914
  yaml8.dump({ version: 1, resources: manifestResources }, YAML_DUMP_OPTIONS),
18455
18915
  "utf-8"
18456
18916
  );
18457
- const resourcesDir = path23.join(orgDir, "resources");
18917
+ const resourcesDir = path24.join(orgDir, "resources");
18458
18918
  const currentSlugs = /* @__PURE__ */ new Set();
18459
18919
  for (const resource of resources) {
18460
18920
  const resSlug = slugify(resource.name);
18461
18921
  currentSlugs.add(resSlug);
18462
- writeResourceFileTree(path23.join(resourcesDir, resSlug), resource.files || []);
18922
+ writeResourceFileTree(path24.join(resourcesDir, resSlug), resource.files || []);
18463
18923
  }
18464
- if (fs18.existsSync(resourcesDir)) {
18465
- for (const entry of fs18.readdirSync(resourcesDir, { withFileTypes: true })) {
18924
+ if (fs19.existsSync(resourcesDir)) {
18925
+ for (const entry of fs19.readdirSync(resourcesDir, { withFileTypes: true })) {
18466
18926
  if (entry.isDirectory() && !currentSlugs.has(entry.name)) {
18467
- fs18.rmSync(path23.join(resourcesDir, entry.name), { recursive: true, force: true });
18927
+ fs19.rmSync(path24.join(resourcesDir, entry.name), { recursive: true, force: true });
18468
18928
  }
18469
18929
  }
18470
18930
  }
@@ -18473,7 +18933,7 @@ async function downloadOrgBinaryFiles(orgDir, payload) {
18473
18933
  let count = 0;
18474
18934
  for (const resource of payload.resources ?? []) {
18475
18935
  if (!resource.files) continue;
18476
- const resDir = path23.join(orgDir, "resources", slugify(resource.name));
18936
+ const resDir = path24.join(orgDir, "resources", slugify(resource.name));
18477
18937
  count += await downloadBinaryFiles(resDir, resource.files);
18478
18938
  }
18479
18939
  if (count > 0) console.log(`Downloaded ${count} binary resource file(s).`);
@@ -18729,20 +19189,20 @@ var init_list = __esm({
18729
19189
  });
18730
19190
 
18731
19191
  // src/lib/template-files.ts
18732
- import * as fs19 from "fs";
18733
- import * as path24 from "path";
19192
+ import * as fs20 from "fs";
19193
+ import * as path25 from "path";
18734
19194
  function readDirToFileMap(rootDir) {
18735
19195
  const out = {};
18736
19196
  function walk(dir, prefix) {
18737
- const entries = fs19.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
19197
+ const entries = fs20.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
18738
19198
  for (const entry of entries) {
18739
- const abs = path24.join(dir, entry.name);
19199
+ const abs = path25.join(dir, entry.name);
18740
19200
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
18741
19201
  if (entry.isDirectory()) walk(abs, rel);
18742
- else if (entry.isFile()) out[rel] = fs19.readFileSync(abs, "utf-8");
19202
+ else if (entry.isFile()) out[rel] = fs20.readFileSync(abs, "utf-8");
18743
19203
  }
18744
19204
  }
18745
- if (fs19.existsSync(rootDir)) walk(rootDir, "");
19205
+ if (fs20.existsSync(rootDir)) walk(rootDir, "");
18746
19206
  return out;
18747
19207
  }
18748
19208
  function detectCollisions(targetDir, files) {
@@ -18751,7 +19211,7 @@ function detectCollisions(targetDir, files) {
18751
19211
  if (!isSafeTemplatePath2(rel)) {
18752
19212
  throw new Error(`Refusing to inspect unsafe template path: ${rel}`);
18753
19213
  }
18754
- if (fs19.existsSync(path24.join(targetDir, rel))) collisions.push(rel);
19214
+ if (fs20.existsSync(path25.join(targetDir, rel))) collisions.push(rel);
18755
19215
  }
18756
19216
  return collisions.sort((a, b) => a.localeCompare(b));
18757
19217
  }
@@ -18761,9 +19221,9 @@ function writeFileMap(targetDir, files) {
18761
19221
  if (!isSafeTemplatePath2(rel)) {
18762
19222
  throw new Error(`Refusing to write unsafe template path: ${rel}`);
18763
19223
  }
18764
- const abs = path24.join(targetDir, rel);
18765
- fs19.mkdirSync(path24.dirname(abs), { recursive: true });
18766
- fs19.writeFileSync(abs, body, "utf-8");
19224
+ const abs = path25.join(targetDir, rel);
19225
+ fs20.mkdirSync(path25.dirname(abs), { recursive: true });
19226
+ fs20.writeFileSync(abs, body, "utf-8");
18767
19227
  written.push(rel);
18768
19228
  }
18769
19229
  return written;
@@ -18771,20 +19231,20 @@ function writeFileMap(targetDir, files) {
18771
19231
  function listDirRelFiles(dir) {
18772
19232
  const out = [];
18773
19233
  function walk(d, prefix) {
18774
- for (const entry of fs19.readdirSync(d, { withFileTypes: true })) {
19234
+ for (const entry of fs20.readdirSync(d, { withFileTypes: true })) {
18775
19235
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
18776
- if (entry.isDirectory()) walk(path24.join(d, entry.name), rel);
19236
+ if (entry.isDirectory()) walk(path25.join(d, entry.name), rel);
18777
19237
  else if (entry.isFile()) out.push(rel);
18778
19238
  }
18779
19239
  }
18780
- if (fs19.existsSync(dir)) walk(dir, "");
19240
+ if (fs20.existsSync(dir)) walk(dir, "");
18781
19241
  return out;
18782
19242
  }
18783
19243
  function writeSliceSnapshot(targetDir, files) {
18784
19244
  const keep = new Set(Object.keys(files));
18785
19245
  const removed = listDirRelFiles(targetDir).filter((rel) => !keep.has(rel)).sort((a, b) => a.localeCompare(b));
18786
19246
  const written = writeFileMap(targetDir, files).sort((a, b) => a.localeCompare(b));
18787
- if (fs19.existsSync(targetDir)) cleanOrphanFiles(targetDir, "", keep);
19247
+ if (fs20.existsSync(targetDir)) cleanOrphanFiles(targetDir, "", keep);
18788
19248
  return { written, removed };
18789
19249
  }
18790
19250
  var init_template_files = __esm({
@@ -18800,7 +19260,7 @@ var templates_exports = {};
18800
19260
  __export(templates_exports, {
18801
19261
  templateCommand: () => templateCommand
18802
19262
  });
18803
- import * as path25 from "path";
19263
+ import * as path26 from "path";
18804
19264
  async function templateCommand(args2) {
18805
19265
  const [sub, ...rest] = args2;
18806
19266
  switch (sub) {
@@ -18916,8 +19376,8 @@ async function runTemplatePull(rest) {
18916
19376
  console.log(`Template "${slug}" has no WayAI slice${hint}`);
18917
19377
  return;
18918
19378
  }
18919
- const targetDir = path25.join(resolveLayout(gitRoot).hubsDir, slug);
18920
- const relTarget = path25.relative(gitRoot, targetDir);
19379
+ const targetDir = path26.join(resolveLayout(gitRoot).hubsDir, slug);
19380
+ const relTarget = path26.relative(gitRoot, targetDir);
18921
19381
  const collisions = detectCollisions(targetDir, detail.files);
18922
19382
  if (dryRun) {
18923
19383
  const planned = Object.keys(detail.files).sort((a, b) => a.localeCompare(b));
@@ -19091,8 +19551,8 @@ var admin_exports = {};
19091
19551
  __export(admin_exports, {
19092
19552
  adminCommand: () => adminCommand
19093
19553
  });
19094
- import * as fs20 from "fs";
19095
- import * as path26 from "path";
19554
+ import * as fs21 from "fs";
19555
+ import * as path27 from "path";
19096
19556
  import * as yaml10 from "js-yaml";
19097
19557
  async function adminCommand(args2) {
19098
19558
  const [group, ...afterGroup] = args2;
@@ -19414,7 +19874,7 @@ async function runArchiveRead(positional, flagArgs) {
19414
19874
  exitOnApiError(err);
19415
19875
  throw err;
19416
19876
  }
19417
- fs20.writeFileSync(outPath, zip);
19877
+ fs21.writeFileSync(outPath, zip);
19418
19878
  console.log(`Wrote ${zip.byteLength} bytes to ${outPath}`);
19419
19879
  return;
19420
19880
  }
@@ -19546,15 +20006,15 @@ function loadTemplateManifest(slug) {
19546
20006
  console.error("Not in a git repository. Run from the tutorials/ authoring repo.");
19547
20007
  process.exit(1);
19548
20008
  }
19549
- const templateDir = path26.join(resolveTemplatesDir(gitRoot), slug);
19550
- const manifestPath = path26.join(templateDir, "template.yaml");
19551
- if (!fs20.existsSync(manifestPath)) {
19552
- console.error(`template.yaml not found at ${path26.relative(gitRoot, manifestPath)}`);
20009
+ const templateDir = path27.join(resolveTemplatesDir(gitRoot), slug);
20010
+ const manifestPath = path27.join(templateDir, "template.yaml");
20011
+ if (!fs21.existsSync(manifestPath)) {
20012
+ console.error(`template.yaml not found at ${path27.relative(gitRoot, manifestPath)}`);
19553
20013
  process.exit(1);
19554
20014
  }
19555
20015
  let manifest;
19556
20016
  try {
19557
- manifest = templateYamlSchema2.parse(yaml10.load(fs20.readFileSync(manifestPath, "utf-8")));
20017
+ manifest = templateYamlSchema2.parse(yaml10.load(fs21.readFileSync(manifestPath, "utf-8")));
19558
20018
  } catch (err) {
19559
20019
  console.error(`Invalid template.yaml: ${err instanceof Error ? err.message : String(err)}`);
19560
20020
  process.exit(1);
@@ -19584,20 +20044,20 @@ async function runTemplatePush(positional) {
19584
20044
  const wayaiEntry = manifest.wayai.locales[locale];
19585
20045
  let wayaiFiles;
19586
20046
  if (wayaiEntry) {
19587
- const sliceDir = path26.resolve(templateDir, wayaiEntry.source);
19588
- if (!fs20.existsSync(sliceDir)) {
20047
+ const sliceDir = path27.resolve(templateDir, wayaiEntry.source);
20048
+ if (!fs21.existsSync(sliceDir)) {
19589
20049
  console.error(`wayai source not found for ${locale}: ${wayaiEntry.source} (resolved ${sliceDir})`);
19590
20050
  process.exit(1);
19591
20051
  }
19592
20052
  if (!isInsideTemplateDir(sliceDir, templateDir)) {
19593
20053
  console.warn(
19594
- `Note: ${locale} source points at a live hub (${wayaiEntry.source}); it can go stale on a hub recreate. Run \`wayai admin template freeze ${slug} --locale ${locale} --from ${path26.basename(sliceDir)}\` to commit a stable frozen slice.`
20054
+ `Note: ${locale} source points at a live hub (${wayaiEntry.source}); it can go stale on a hub recreate. Run \`wayai admin template freeze ${slug} --locale ${locale} --from ${path27.basename(sliceDir)}\` to commit a stable frozen slice.`
19595
20055
  );
19596
20056
  }
19597
20057
  wayaiFiles = readDirToFileMap(sliceDir);
19598
20058
  }
19599
- const readmePath = path26.join(templateDir, `README.${locale}.md`);
19600
- const readmeMarkdown = fs20.existsSync(readmePath) ? fs20.readFileSync(readmePath, "utf-8") : "";
20059
+ const readmePath = path27.join(templateDir, `README.${locale}.md`);
20060
+ const readmeMarkdown = fs21.existsSync(readmePath) ? fs21.readFileSync(readmePath, "utf-8") : "";
19601
20061
  locales[locale] = {
19602
20062
  readmeMarkdown,
19603
20063
  ...wayaiFiles && { wayaiFiles },
@@ -19608,9 +20068,9 @@ async function runTemplatePush(positional) {
19608
20068
  }
19609
20069
  let hero;
19610
20070
  if (manifest.hero) {
19611
- const heroPath = path26.resolve(templateDir, manifest.hero);
19612
- if (fs20.existsSync(heroPath)) {
19613
- hero = { filename: path26.basename(heroPath), dataBase64: fs20.readFileSync(heroPath).toString("base64") };
20071
+ const heroPath = path27.resolve(templateDir, manifest.hero);
20072
+ if (fs21.existsSync(heroPath)) {
20073
+ hero = { filename: path27.basename(heroPath), dataBase64: fs21.readFileSync(heroPath).toString("base64") };
19614
20074
  } else {
19615
20075
  console.error(`Warning: hero not found at ${manifest.hero}; skipping.`);
19616
20076
  }
@@ -19636,7 +20096,7 @@ async function runTemplatePush(positional) {
19636
20096
  }
19637
20097
  }
19638
20098
  function isInsideTemplateDir(dest, templateDir) {
19639
- return dest === templateDir || dest.startsWith(templateDir + path26.sep);
20099
+ return dest === templateDir || dest.startsWith(templateDir + path27.sep);
19640
20100
  }
19641
20101
  async function runTemplateFreeze(positional, flagArgs) {
19642
20102
  const slug = positional[0];
@@ -19697,7 +20157,7 @@ async function runTemplateFreeze(positional, flagArgs) {
19697
20157
  process.exit(1);
19698
20158
  }
19699
20159
  const entry = manifest.wayai.locales[targetLocale];
19700
- const dest = path26.resolve(templateDir, entry.source);
20160
+ const dest = path27.resolve(templateDir, entry.source);
19701
20161
  if (!isInsideTemplateDir(dest, templateDir) || dest === templateDir) {
19702
20162
  console.error(
19703
20163
  `source for "${targetLocale}" must be a committed path inside ${slug}/ (e.g. "./${targetLocale}/slice"), but resolved to:
@@ -19716,7 +20176,7 @@ Set it to a subdir of the template folder and re-run freeze.`
19716
20176
  const hubs = scanWorkspaceHubs(hubsDir);
19717
20177
  if (hubs.length) {
19718
20178
  console.error("Available hubs:");
19719
- for (const h of hubs) console.error(` ${path26.basename(h.hubFolder)} (${h.hubId})`);
20179
+ for (const h of hubs) console.error(` ${path27.basename(h.hubFolder)} (${h.hubId})`);
19720
20180
  }
19721
20181
  console.error(`
19722
20182
  Pass --from <folder|uuid>${selector ? "." : " or run `wayai use <hub>` first."}`);
@@ -19724,12 +20184,12 @@ Pass --from <folder|uuid>${selector ? "." : " or run `wayai use <hub>` first."}`
19724
20184
  }
19725
20185
  const liveFiles = readDirToFileMap(hubFolder);
19726
20186
  if (Object.keys(liveFiles).length === 0) {
19727
- console.error(`Source hub folder has no files to freeze: ${path26.relative(gitRoot, hubFolder)}`);
20187
+ console.error(`Source hub folder has no files to freeze: ${path27.relative(gitRoot, hubFolder)}`);
19728
20188
  process.exit(1);
19729
20189
  }
19730
20190
  const sanitized = sanitizeWayaiSliceFiles(liveFiles);
19731
- const relDest = path26.relative(gitRoot, dest);
19732
- const relSrc = path26.relative(gitRoot, hubFolder);
20191
+ const relDest = path27.relative(gitRoot, dest);
20192
+ const relSrc = path27.relative(gitRoot, hubFolder);
19733
20193
  if (dryRun) {
19734
20194
  const existing = new Set(listDirRelFiles(dest));
19735
20195
  const nextKeys = new Set(Object.keys(sanitized));
@@ -19789,7 +20249,7 @@ async function runTemplatePull2(positional, flagArgs) {
19789
20249
  console.log(JSON.stringify(detail, null, 2));
19790
20250
  return;
19791
20251
  }
19792
- const target = outDir ? path26.resolve(outDir) : path26.join(process.cwd(), "template-store-pull", slug);
20252
+ const target = outDir ? path27.resolve(outDir) : path27.join(process.cwd(), "template-store-pull", slug);
19793
20253
  const written = writeFileMap(target, detail.files);
19794
20254
  console.log(`Pulled "${slug}" from the store \u2192 ${target} (${written.length} file${written.length === 1 ? "" : "s"}).`);
19795
20255
  const uses = detail.uses ?? [];
@@ -19812,13 +20272,13 @@ async function runSkillInstall(positional) {
19812
20272
  throw err;
19813
20273
  }
19814
20274
  const root = findGitRoot() ?? process.cwd();
19815
- const present = HARNESS_SKILL_DIRS.filter((dir) => fs20.existsSync(path26.join(root, dir)));
20275
+ const present = HARNESS_SKILL_DIRS.filter((dir) => fs21.existsSync(path27.join(root, dir)));
19816
20276
  const targets = present.length > 0 ? present : HARNESS_SKILL_DIRS;
19817
20277
  const fileCount = Object.keys(res.files).length;
19818
20278
  const relDirs = targets.map((harness) => {
19819
- const targetDir = path26.join(root, harness, "skills", name);
20279
+ const targetDir = path27.join(root, harness, "skills", name);
19820
20280
  writeFileMap(targetDir, res.files);
19821
- return `${path26.relative(root, targetDir)}/`;
20281
+ return `${path27.relative(root, targetDir)}/`;
19822
20282
  });
19823
20283
  console.log(`Installed skill "${name}" (${fileCount} file${fileCount === 1 ? "" : "s"}) \u2192 ${relDirs.join(", ")}`);
19824
20284
  console.log("Reload your agent (e.g. restart Claude Code) to pick up the skill.");
@@ -19929,7 +20389,7 @@ async function runSandboxExec(positional, flagArgs) {
19929
20389
  process.exit(data.exit_code);
19930
20390
  }
19931
20391
  }
19932
- function parseScopedTargetFlags(flagArgs, usage2) {
20392
+ function parseScopedTargetFlags(flagArgs, usage3) {
19933
20393
  let all = false;
19934
20394
  let orgId;
19935
20395
  let hubId;
@@ -19964,7 +20424,7 @@ function parseScopedTargetFlags(flagArgs, usage2) {
19964
20424
  }
19965
20425
  if ((all ? 1 : 0) + (orgId ? 1 : 0) + (hubId ? 1 : 0) !== 1) {
19966
20426
  console.error("Provide exactly ONE of --all, --org <org_id>, or --hub <hub_id>.");
19967
- console.error(usage2);
20427
+ console.error(usage3);
19968
20428
  process.exit(1);
19969
20429
  }
19970
20430
  if (all) {
@@ -20070,7 +20530,7 @@ async function runHarnessMassDestroy(flagArgs) {
20070
20530
  );
20071
20531
  }
20072
20532
  }
20073
- function resolveHarnessLayer(flagArgs, usage2) {
20533
+ function resolveHarnessLayer(flagArgs, usage3) {
20074
20534
  let orgId;
20075
20535
  let hubId;
20076
20536
  for (let i = 0; i < flagArgs.length; i++) {
@@ -20084,13 +20544,13 @@ function resolveHarnessLayer(flagArgs, usage2) {
20084
20544
  break;
20085
20545
  default:
20086
20546
  console.error(`Unknown flag: ${arg}`);
20087
- console.error(usage2);
20547
+ console.error(usage3);
20088
20548
  process.exit(1);
20089
20549
  }
20090
20550
  }
20091
20551
  if (orgId && hubId) {
20092
20552
  console.error("Provide at most ONE of --org <org_id> or --hub <hub_id> (or neither for the platform layer).");
20093
- console.error(usage2);
20553
+ console.error(usage3);
20094
20554
  process.exit(1);
20095
20555
  }
20096
20556
  if (orgId) return { kind: "org", orgId };
@@ -21160,7 +21620,7 @@ var init_update = __esm({
21160
21620
 
21161
21621
  // src/index.ts
21162
21622
  init_sentry();
21163
- import { readFileSync as readFileSync18 } from "fs";
21623
+ import { readFileSync as readFileSync19 } from "fs";
21164
21624
  import { fileURLToPath as fileURLToPath2 } from "url";
21165
21625
  import { dirname as dirname9, join as join25 } from "path";
21166
21626
 
@@ -21185,7 +21645,7 @@ function friendlyHint(err) {
21185
21645
  }
21186
21646
 
21187
21647
  // src/index.ts
21188
- init_redact();
21648
+ init_mask_secrets();
21189
21649
  init_utils();
21190
21650
 
21191
21651
  // src/lib/version-refresh.ts
@@ -21342,7 +21802,7 @@ Run \`wayai admin skill install\` to update.`);
21342
21802
 
21343
21803
  // src/index.ts
21344
21804
  var __dirname = dirname9(fileURLToPath2(import.meta.url));
21345
- var pkg = JSON.parse(readFileSync18(join25(__dirname, "..", "package.json"), "utf-8"));
21805
+ var pkg = JSON.parse(readFileSync19(join25(__dirname, "..", "package.json"), "utf-8"));
21346
21806
  var [, , command, ...args] = process.argv;
21347
21807
  var isBackgroundRefresh = command === REFRESH_COMMAND;
21348
21808
  if (!isBackgroundRefresh) initSentry(command, pkg.version);
@@ -21587,7 +22047,7 @@ Commands:
21587
22047
  use <hub> Bind this worktree to a specific hub (UUID or folder name)
21588
22048
  migrate Move a legacy repo to the wayai-ws/{hubs,org} layout
21589
22049
  unbind Clear the worktree hub binding
21590
- send-message Send a test message to a hub (preview or production)
22050
+ send-message Send a test message to a hub (preview or production; -f <path> to attach a file)
21591
22051
  conversations List or inspect conversations
21592
22052
  alerts Show a hub's active connection/credential alerts (run this FIRST when a hub misbehaves)
21593
22053
  analytics Show analytics summary and metrics (use \`analytics query\` for structured ClickHouse queries)
@@ -21679,7 +22139,7 @@ async function runForeground() {
21679
22139
  captureException2(err);
21680
22140
  }
21681
22141
  await closeSentry();
21682
- console.error(redactSecrets(err instanceof Error ? err.message : String(err)));
22142
+ console.error(maskSecretsInMessage(err instanceof Error ? err.message : String(err)));
21683
22143
  const hint = friendlyHint(err);
21684
22144
  if (hint) console.error(hint);
21685
22145
  process.exit(1);