@wayai/cli 0.3.137 → 0.3.138

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -447,11 +447,11 @@ function captureException2(error, context) {
447
447
  Sentry.captureException(error);
448
448
  });
449
449
  }
450
- function addApiBreadcrumb(method, path31) {
450
+ function addApiBreadcrumb(method, path36) {
451
451
  if (!initialized) return;
452
452
  Sentry.addBreadcrumb({
453
453
  category: "http",
454
- message: `${method} ${path31}`,
454
+ message: `${method} ${path36}`,
455
455
  level: "info"
456
456
  });
457
457
  }
@@ -905,8 +905,8 @@ var init_parseUtil = __esm({
905
905
  init_errors();
906
906
  init_en();
907
907
  makeIssue = (params) => {
908
- const { data, path: path31, errorMaps, issueData } = params;
909
- const fullPath = [...path31, ...issueData.path || []];
908
+ const { data, path: path36, errorMaps, issueData } = params;
909
+ const fullPath = [...path36, ...issueData.path || []];
910
910
  const fullIssue = {
911
911
  ...issueData,
912
912
  path: fullPath
@@ -1217,11 +1217,11 @@ var init_types = __esm({
1217
1217
  init_parseUtil();
1218
1218
  init_util();
1219
1219
  ParseInputLazyPath = class {
1220
- constructor(parent, value, path31, key) {
1220
+ constructor(parent, value, path36, key) {
1221
1221
  this._cachedPath = [];
1222
1222
  this.parent = parent;
1223
1223
  this.data = value;
1224
- this._path = path31;
1224
+ this._path = path36;
1225
1225
  this._key = key;
1226
1226
  }
1227
1227
  get path() {
@@ -4634,12 +4634,12 @@ function validateFollowupLinks(followups, label, ctx) {
4634
4634
  const linkTargets = /* @__PURE__ */ new Set();
4635
4635
  followups.forEach((followup, i) => {
4636
4636
  const ref = followup?.after_followup_id;
4637
- const path31 = ["followups", i, "after_followup_id"];
4637
+ const path36 = ["followups", i, "after_followup_id"];
4638
4638
  if (followup?.type !== "inactivity_after_before_event") {
4639
4639
  if (ref !== void 0) {
4640
4640
  ctx.addIssue({
4641
4641
  code: external_exports.ZodIssueCode.custom,
4642
- path: path31,
4642
+ path: path36,
4643
4643
  message: `kanban status ${label}: after_followup_id is only valid on inactivity_after_before_event followups (this one is ${followup?.type})`
4644
4644
  });
4645
4645
  }
@@ -4648,7 +4648,7 @@ function validateFollowupLinks(followups, label, ctx) {
4648
4648
  if (ref === void 0) {
4649
4649
  ctx.addIssue({
4650
4650
  code: external_exports.ZodIssueCode.custom,
4651
- path: path31,
4651
+ path: path36,
4652
4652
  message: `kanban status ${label}: inactivity_after_before_event requires after_followup_id naming the id of a before_event followup in the same status`
4653
4653
  });
4654
4654
  return;
@@ -4658,7 +4658,7 @@ function validateFollowupLinks(followups, label, ctx) {
4658
4658
  if (matches.length > 1) {
4659
4659
  ctx.addIssue({
4660
4660
  code: external_exports.ZodIssueCode.custom,
4661
- path: path31,
4661
+ path: path36,
4662
4662
  message: `kanban status ${label}: after_followup_id "${ref}" matches ${matches.length} followups \u2014 a link must name exactly one`
4663
4663
  });
4664
4664
  return;
@@ -4670,7 +4670,7 @@ function validateFollowupLinks(followups, label, ctx) {
4670
4670
  );
4671
4671
  ctx.addIssue({
4672
4672
  code: external_exports.ZodIssueCode.custom,
4673
- path: path31,
4673
+ path: path36,
4674
4674
  message: hasIdlessBeforeEvent ? `kanban status ${label}: after_followup_id "${ref}" matches no followup \u2014 a link target must declare an explicit id, and this status has before_event followups without one` : `kanban status ${label}: after_followup_id "${ref}" matches no followup in this status`
4675
4675
  });
4676
4676
  return;
@@ -4678,7 +4678,7 @@ function validateFollowupLinks(followups, label, ctx) {
4678
4678
  if (target.type !== "before_event") {
4679
4679
  ctx.addIssue({
4680
4680
  code: external_exports.ZodIssueCode.custom,
4681
- path: path31,
4681
+ path: path36,
4682
4682
  message: `kanban status ${label}: after_followup_id "${ref}" points at a ${target.type} followup \u2014 only before_event followups can anchor a chain`
4683
4683
  });
4684
4684
  }
@@ -4754,12 +4754,12 @@ function typeMatches(typeField, allowed) {
4754
4754
  if (Array.isArray(typeField)) return typeField.every((t) => typeof t === "string" && allowed.has(t));
4755
4755
  return false;
4756
4756
  }
4757
- function validateSchema(schema, path31, errors, opts = {}) {
4757
+ function validateSchema(schema, path36, errors, opts = {}) {
4758
4758
  if (typeof schema === "boolean") return;
4759
4759
  const depth = opts.depth ?? 0;
4760
4760
  if (depth > MAX_SCHEMA_DEPTH) {
4761
4761
  errors.push({
4762
- path: path31 || "<root>",
4762
+ path: path36 || "<root>",
4763
4763
  message: `schema nesting exceeds ${MAX_SCHEMA_DEPTH} levels`,
4764
4764
  suggestion: "Flatten the schema; LLM providers reject deeply nested tool input_schemas."
4765
4765
  });
@@ -4767,7 +4767,7 @@ function validateSchema(schema, path31, errors, opts = {}) {
4767
4767
  }
4768
4768
  if (!isRecord(schema)) {
4769
4769
  errors.push({
4770
- path: path31,
4770
+ path: path36,
4771
4771
  message: `expected object, got ${schema === null ? "null" : typeof schema}`
4772
4772
  });
4773
4773
  return;
@@ -4775,14 +4775,14 @@ function validateSchema(schema, path31, errors, opts = {}) {
4775
4775
  if (opts.isRoot) {
4776
4776
  if ("type" in schema && schema.type !== "object") {
4777
4777
  errors.push({
4778
- path: path31 ? `${path31}.type` : "type",
4778
+ path: path36 ? `${path36}.type` : "type",
4779
4779
  message: `root type must be 'object', got ${JSON.stringify(schema.type)}`,
4780
4780
  suggestion: "Tool parameters at the root must be an object: `{ type: 'object', properties: { ... } }`."
4781
4781
  });
4782
4782
  }
4783
4783
  } else if ("type" in schema && !typeMatches(schema.type, ALLOWED_TYPES)) {
4784
4784
  errors.push({
4785
- path: `${path31}.type`,
4785
+ path: `${path36}.type`,
4786
4786
  message: `type must be one of ${[...ALLOWED_TYPES].join("/")} or an array of those, got ${JSON.stringify(schema.type)}`
4787
4787
  });
4788
4788
  }
@@ -4792,25 +4792,25 @@ function validateSchema(schema, path31, errors, opts = {}) {
4792
4792
  const isPlaceholder = PLACEHOLDER_TOKENS.includes(e);
4793
4793
  const isOutcomePlaceholder = e === "[KANBAN_OUTCOME_VALUES]";
4794
4794
  errors.push({
4795
- path: `${path31}.enum`,
4795
+ path: `${path36}.enum`,
4796
4796
  message: `enum must be a non-empty array of primitives, got string ${JSON.stringify(e)}`,
4797
4797
  suggestion: isOutcomePlaceholder ? "Declare `outcomes` on the hub's terminal kanban status so the platform can render the placeholder into a valid array; with none configured the platform drops the parameter instead." : isPlaceholder ? "Set `operation: 'update_kanban_status'` on the tool and ensure at least one hub.kanban_status has `allowsAgentUpdate: true` so the platform can render the placeholder into a valid array." : 'Wrap the value in an array: `enum: ["value"]`.'
4798
4798
  });
4799
4799
  } else if (!Array.isArray(e)) {
4800
4800
  errors.push({
4801
- path: `${path31}.enum`,
4801
+ path: `${path36}.enum`,
4802
4802
  message: `enum must be a non-empty array of primitives, got ${typeof e}`
4803
4803
  });
4804
4804
  } else if (e.length === 0) {
4805
4805
  errors.push({
4806
- path: `${path31}.enum`,
4806
+ path: `${path36}.enum`,
4807
4807
  message: "enum must not be empty"
4808
4808
  });
4809
4809
  } else {
4810
4810
  for (let i = 0; i < e.length; i++) {
4811
4811
  if (!isPrimitive(e[i])) {
4812
4812
  errors.push({
4813
- path: `${path31}.enum[${i}]`,
4813
+ path: `${path36}.enum[${i}]`,
4814
4814
  message: `enum entry must be a primitive (string/number/boolean/null), got ${typeof e[i]}`
4815
4815
  });
4816
4816
  }
@@ -4820,7 +4820,7 @@ function validateSchema(schema, path31, errors, opts = {}) {
4820
4820
  for (const key of ["exclusiveMinimum", "exclusiveMaximum"]) {
4821
4821
  if (key in schema && typeof schema[key] === "boolean") {
4822
4822
  errors.push({
4823
- path: `${path31}.${key}`,
4823
+ path: `${path36}.${key}`,
4824
4824
  message: `${key} as boolean is draft-04 syntax; draft 2020-12 requires a numeric value`,
4825
4825
  suggestion: `Replace with the numeric bound, e.g. \`${key}: 0\`.`
4826
4826
  });
@@ -4829,45 +4829,45 @@ function validateSchema(schema, path31, errors, opts = {}) {
4829
4829
  if ("properties" in schema) {
4830
4830
  if (!isRecord(schema.properties)) {
4831
4831
  errors.push({
4832
- path: `${path31}.properties`,
4832
+ path: `${path36}.properties`,
4833
4833
  message: `properties must be an object, got ${Array.isArray(schema.properties) ? "array" : typeof schema.properties}`
4834
4834
  });
4835
4835
  } else {
4836
4836
  for (const [propName, propSchema] of Object.entries(schema.properties)) {
4837
- validateSchema(propSchema, `${path31}.properties.${propName}`, errors, { depth: depth + 1 });
4837
+ validateSchema(propSchema, `${path36}.properties.${propName}`, errors, { depth: depth + 1 });
4838
4838
  }
4839
4839
  }
4840
4840
  }
4841
4841
  if (schemaTypeIncludes(schema, "array") && "items" in schema) {
4842
4842
  if (Array.isArray(schema.items)) {
4843
- schema.items.forEach((sub, i) => validateSchema(sub, `${path31}.items[${i}]`, errors, { depth: depth + 1 }));
4843
+ schema.items.forEach((sub, i) => validateSchema(sub, `${path36}.items[${i}]`, errors, { depth: depth + 1 }));
4844
4844
  } else {
4845
- validateSchema(schema.items, `${path31}.items`, errors, { depth: depth + 1 });
4845
+ validateSchema(schema.items, `${path36}.items`, errors, { depth: depth + 1 });
4846
4846
  }
4847
4847
  }
4848
4848
  for (const key of SUBSCHEMA_OBJECT_KEYWORDS) {
4849
4849
  if (key in schema && isRecord(schema[key])) {
4850
- validateSchema(schema[key], `${path31}.${key}`, errors, { depth: depth + 1 });
4850
+ validateSchema(schema[key], `${path36}.${key}`, errors, { depth: depth + 1 });
4851
4851
  }
4852
4852
  }
4853
4853
  for (const key of SUBSCHEMA_LIST_KEYWORDS) {
4854
4854
  const list = schema[key];
4855
4855
  if (Array.isArray(list)) {
4856
- list.forEach((sub, i) => validateSchema(sub, `${path31}.${key}[${i}]`, errors, { depth: depth + 1 }));
4856
+ list.forEach((sub, i) => validateSchema(sub, `${path36}.${key}[${i}]`, errors, { depth: depth + 1 }));
4857
4857
  }
4858
4858
  }
4859
4859
  for (const key of SUBSCHEMA_MAP_KEYWORDS) {
4860
4860
  const map = schema[key];
4861
4861
  if (isRecord(map)) {
4862
4862
  for (const [name, sub] of Object.entries(map)) {
4863
- validateSchema(sub, `${path31}.${key}.${name}`, errors, { depth: depth + 1 });
4863
+ validateSchema(sub, `${path36}.${key}.${name}`, errors, { depth: depth + 1 });
4864
4864
  }
4865
4865
  }
4866
4866
  }
4867
4867
  const reportedPaths = new Set(errors.map((e) => e.path));
4868
4868
  for (const [k, v] of Object.entries(schema)) {
4869
4869
  if (typeof v !== "string") continue;
4870
- const fieldPath = `${path31}.${k}`;
4870
+ const fieldPath = `${path36}.${k}`;
4871
4871
  if (reportedPaths.has(fieldPath)) continue;
4872
4872
  for (const token of PLACEHOLDER_TOKENS) {
4873
4873
  if (v === token) {
@@ -5012,8 +5012,8 @@ function evalInitialStateError(input) {
5012
5012
  const parsed = evalInitialStateEntry.safeParse(entries[i]);
5013
5013
  if (!parsed.success) {
5014
5014
  const issue = parsed.error.issues[0];
5015
- const path31 = issue?.path.join(".") || "?";
5016
- return `initial_state[${i}].${path31} is invalid: ${issue?.message ?? "malformed"}`;
5015
+ const path36 = issue?.path.join(".") || "?";
5016
+ return `initial_state[${i}].${path36} is invalid: ${issue?.message ?? "malformed"}`;
5017
5017
  }
5018
5018
  if (seenSlugs.has(parsed.data.slug)) {
5019
5019
  return `initial_state[${i}].slug "${parsed.data.slug}" is declared more than once`;
@@ -5201,10 +5201,10 @@ function refineHubAsCodeEvals(config, ctx) {
5201
5201
  function refineHubAsCodeEvalAttachments(config, ctx) {
5202
5202
  const cfg = config;
5203
5203
  const referencedHashes = /* @__PURE__ */ new Set();
5204
- const addTurnIssue = (path31, turn, name) => {
5204
+ const addTurnIssue = (path36, turn, name) => {
5205
5205
  const error = evalTurnAttachmentsError(turn);
5206
5206
  if (error) {
5207
- ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: path31, message: `${name}: ${error}` });
5207
+ ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: path36, message: `${name}: ${error}` });
5208
5208
  return;
5209
5209
  }
5210
5210
  for (const hash of collectTurnAttachmentHashes(turn)) referencedHashes.add(hash);
@@ -5350,11 +5350,11 @@ function refineHubAsCodeDelegation(config, ctx) {
5350
5350
  }
5351
5351
  }
5352
5352
  if (del.context_boundary === void 0) return;
5353
- const path31 = ["agents", agentIndex, "tools", "delegation", delIndex, "context_boundary"];
5353
+ const path36 = ["agents", agentIndex, "tools", "delegation", delIndex, "context_boundary"];
5354
5354
  if (del.type !== "hub") {
5355
5355
  ctx.addIssue({
5356
5356
  code: external_exports.ZodIssueCode.custom,
5357
- path: path31,
5357
+ path: path36,
5358
5358
  message: `context_boundary applies only to \`type: hub\` delegations (got type "${String(del.type)}")`
5359
5359
  });
5360
5360
  return;
@@ -5362,7 +5362,7 @@ function refineHubAsCodeDelegation(config, ctx) {
5362
5362
  if (!CONTEXT_BOUNDARIES.includes(del.context_boundary)) {
5363
5363
  ctx.addIssue({
5364
5364
  code: external_exports.ZodIssueCode.custom,
5365
- path: path31,
5365
+ path: path36,
5366
5366
  message: `context_boundary must be one of: ${CONTEXT_BOUNDARIES.join(", ")}`
5367
5367
  });
5368
5368
  }
@@ -8737,10 +8737,10 @@ function toDataProxyPath(v1Path) {
8737
8737
  }
8738
8738
  return `${DATA_PROXY_PREFIX}${v1Path.slice(REKOR_V1_PREFIX.length)}`;
8739
8739
  }
8740
- function withOrgSelector(path31, orgId) {
8741
- if (!orgId) return path31;
8742
- const separator = path31.includes("?") ? "&" : "?";
8743
- return `${path31}${separator}${DATA_PROXY_ORG_QUERY_PARAM}=${encodeURIComponent(orgId)}`;
8740
+ function withOrgSelector(path36, orgId) {
8741
+ if (!orgId) return path36;
8742
+ const separator = path36.includes("?") ? "&" : "?";
8743
+ return `${path36}${separator}${DATA_PROXY_ORG_QUERY_PARAM}=${encodeURIComponent(orgId)}`;
8744
8744
  }
8745
8745
  function dataErrorMessage(err) {
8746
8746
  if (!(err instanceof ApiError)) return null;
@@ -8764,7 +8764,7 @@ var init_api_client = __esm({
8764
8764
  init_sentry();
8765
8765
  init_mask_secrets();
8766
8766
  RETRYABLE_BACKOFF_MS = [500, 1e3, 2e3];
8767
- delay = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
8767
+ delay = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
8768
8768
  ApiError = class extends Error {
8769
8769
  status;
8770
8770
  body;
@@ -8774,13 +8774,13 @@ var init_api_client = __esm({
8774
8774
  * telling them apart by body shape misreads one for the other.
8775
8775
  */
8776
8776
  path;
8777
- constructor(method, path31, status, body) {
8777
+ constructor(method, path36, status, body) {
8778
8778
  const safeBody = maskSecretsInMessage(body);
8779
- super(`API request failed: ${method} ${path31} (${status}): ${safeBody}`);
8779
+ super(`API request failed: ${method} ${path36} (${status}): ${safeBody}`);
8780
8780
  this.name = "ApiError";
8781
8781
  this.status = status;
8782
8782
  this.body = safeBody;
8783
- this.path = path31;
8783
+ this.path = path36;
8784
8784
  }
8785
8785
  /** True when the status code is a 4xx client error (expected user-facing condition, not a bug). */
8786
8786
  get isExpected() {
@@ -8876,8 +8876,8 @@ var init_api_client = __esm({
8876
8876
  ...opts?.check && { check: true }
8877
8877
  });
8878
8878
  }
8879
- async lookup(path31, opts) {
8880
- const params = new URLSearchParams({ path: path31 });
8879
+ async lookup(path36, opts) {
8880
+ const params = new URLSearchParams({ path: path36 });
8881
8881
  if (opts?.organizationId) params.set("organization_id", opts.organizationId);
8882
8882
  return this.request("GET", `/api/ci/lookup?${params.toString()}`);
8883
8883
  }
@@ -9298,9 +9298,9 @@ var init_api_client = __esm({
9298
9298
  * sandbox for this conversation, or the blob was purged).
9299
9299
  */
9300
9300
  async downloadArchiveSandboxFs(hubId, conversationId) {
9301
- const path31 = `/api/archive/${encodeURIComponent(hubId)}/conversations/${encodeURIComponent(conversationId)}/sandbox`;
9302
- addApiBreadcrumb("GET", path31);
9303
- const url = `${this.apiUrl}${path31}`;
9301
+ const path36 = `/api/archive/${encodeURIComponent(hubId)}/conversations/${encodeURIComponent(conversationId)}/sandbox`;
9302
+ addApiBreadcrumb("GET", path36);
9303
+ const url = `${this.apiUrl}${path36}`;
9304
9304
  let response = await this.send(url, "GET");
9305
9305
  if (response.status === 401 && this.onUnauthorized) {
9306
9306
  let refreshed;
@@ -9314,7 +9314,7 @@ var init_api_client = __esm({
9314
9314
  }
9315
9315
  }
9316
9316
  if (!response.ok) {
9317
- throw new ApiError("GET", path31, response.status, await response.text());
9317
+ throw new ApiError("GET", path36, response.status, await response.text());
9318
9318
  }
9319
9319
  return new Uint8Array(await response.arrayBuffer());
9320
9320
  }
@@ -9354,9 +9354,9 @@ var init_api_client = __esm({
9354
9354
  `/api/admin/data-explorer/debug/observability/${encodeURIComponent(hubId)}/conversations/${encodeURIComponent(conversationId)}${qs}`
9355
9355
  );
9356
9356
  }
9357
- async request(method, path31, body, extraHeaders, contentType) {
9358
- addApiBreadcrumb(method, path31);
9359
- const url = `${this.apiUrl}${path31}`;
9357
+ async request(method, path36, body, extraHeaders, contentType) {
9358
+ addApiBreadcrumb(method, path36);
9359
+ const url = `${this.apiUrl}${path36}`;
9360
9360
  let refreshedOn401 = false;
9361
9361
  for (let retry = 0; ; retry++) {
9362
9362
  let response = await this.send(url, method, body, extraHeaders, contentType);
@@ -9381,7 +9381,7 @@ var init_api_client = __esm({
9381
9381
  await delay(RETRYABLE_BACKOFF_MS[retry]);
9382
9382
  continue;
9383
9383
  }
9384
- throw new ApiError(method, path31, response.status, errorBody);
9384
+ throw new ApiError(method, path36, response.status, errorBody);
9385
9385
  }
9386
9386
  }
9387
9387
  /**
@@ -9443,9 +9443,9 @@ var init_api_client = __esm({
9443
9443
  * transient-retry loop — re-streaming a blob is not worth a cold-start probe.
9444
9444
  */
9445
9445
  async dataDownload(v1Path, orgId) {
9446
- const path31 = withOrgSelector(toDataProxyPath(v1Path), orgId);
9447
- addApiBreadcrumb("GET", path31);
9448
- const url = `${this.apiUrl}${path31}`;
9446
+ const path36 = withOrgSelector(toDataProxyPath(v1Path), orgId);
9447
+ addApiBreadcrumb("GET", path36);
9448
+ const url = `${this.apiUrl}${path36}`;
9449
9449
  let response = await this.send(url, "GET");
9450
9450
  if (response.status === 401 && this.onUnauthorized) {
9451
9451
  let refreshed;
@@ -9459,7 +9459,7 @@ var init_api_client = __esm({
9459
9459
  }
9460
9460
  }
9461
9461
  if (!response.ok) {
9462
- throw new ApiError("GET", path31, response.status, await response.text());
9462
+ throw new ApiError("GET", path36, response.status, await response.text());
9463
9463
  }
9464
9464
  return {
9465
9465
  bytes: new Uint8Array(await response.arrayBuffer()),
@@ -9611,12 +9611,12 @@ function validateFollowupLinks2(followups, label, ctx) {
9611
9611
  const linkTargets = /* @__PURE__ */ new Set();
9612
9612
  followups.forEach((followup, i) => {
9613
9613
  const ref = followup?.after_followup_id;
9614
- const path31 = ["followups", i, "after_followup_id"];
9614
+ const path36 = ["followups", i, "after_followup_id"];
9615
9615
  if (followup?.type !== "inactivity_after_before_event") {
9616
9616
  if (ref !== void 0) {
9617
9617
  ctx.addIssue({
9618
9618
  code: external_exports.ZodIssueCode.custom,
9619
- path: path31,
9619
+ path: path36,
9620
9620
  message: `kanban status ${label}: after_followup_id is only valid on inactivity_after_before_event followups (this one is ${followup?.type})`
9621
9621
  });
9622
9622
  }
@@ -9625,7 +9625,7 @@ function validateFollowupLinks2(followups, label, ctx) {
9625
9625
  if (ref === void 0) {
9626
9626
  ctx.addIssue({
9627
9627
  code: external_exports.ZodIssueCode.custom,
9628
- path: path31,
9628
+ path: path36,
9629
9629
  message: `kanban status ${label}: inactivity_after_before_event requires after_followup_id naming the id of a before_event followup in the same status`
9630
9630
  });
9631
9631
  return;
@@ -9635,7 +9635,7 @@ function validateFollowupLinks2(followups, label, ctx) {
9635
9635
  if (matches.length > 1) {
9636
9636
  ctx.addIssue({
9637
9637
  code: external_exports.ZodIssueCode.custom,
9638
- path: path31,
9638
+ path: path36,
9639
9639
  message: `kanban status ${label}: after_followup_id "${ref}" matches ${matches.length} followups \u2014 a link must name exactly one`
9640
9640
  });
9641
9641
  return;
@@ -9647,7 +9647,7 @@ function validateFollowupLinks2(followups, label, ctx) {
9647
9647
  );
9648
9648
  ctx.addIssue({
9649
9649
  code: external_exports.ZodIssueCode.custom,
9650
- path: path31,
9650
+ path: path36,
9651
9651
  message: hasIdlessBeforeEvent ? `kanban status ${label}: after_followup_id "${ref}" matches no followup \u2014 a link target must declare an explicit id, and this status has before_event followups without one` : `kanban status ${label}: after_followup_id "${ref}" matches no followup in this status`
9652
9652
  });
9653
9653
  return;
@@ -9655,7 +9655,7 @@ function validateFollowupLinks2(followups, label, ctx) {
9655
9655
  if (target.type !== "before_event") {
9656
9656
  ctx.addIssue({
9657
9657
  code: external_exports.ZodIssueCode.custom,
9658
- path: path31,
9658
+ path: path36,
9659
9659
  message: `kanban status ${label}: after_followup_id "${ref}" points at a ${target.type} followup \u2014 only before_event followups can anchor a chain`
9660
9660
  });
9661
9661
  }
@@ -9731,12 +9731,12 @@ function typeMatches2(typeField, allowed) {
9731
9731
  if (Array.isArray(typeField)) return typeField.every((t) => typeof t === "string" && allowed.has(t));
9732
9732
  return false;
9733
9733
  }
9734
- function validateSchema2(schema, path31, errors, opts = {}) {
9734
+ function validateSchema2(schema, path36, errors, opts = {}) {
9735
9735
  if (typeof schema === "boolean") return;
9736
9736
  const depth = opts.depth ?? 0;
9737
9737
  if (depth > MAX_SCHEMA_DEPTH2) {
9738
9738
  errors.push({
9739
- path: path31 || "<root>",
9739
+ path: path36 || "<root>",
9740
9740
  message: `schema nesting exceeds ${MAX_SCHEMA_DEPTH2} levels`,
9741
9741
  suggestion: "Flatten the schema; LLM providers reject deeply nested tool input_schemas."
9742
9742
  });
@@ -9744,7 +9744,7 @@ function validateSchema2(schema, path31, errors, opts = {}) {
9744
9744
  }
9745
9745
  if (!isRecord2(schema)) {
9746
9746
  errors.push({
9747
- path: path31,
9747
+ path: path36,
9748
9748
  message: `expected object, got ${schema === null ? "null" : typeof schema}`
9749
9749
  });
9750
9750
  return;
@@ -9752,14 +9752,14 @@ function validateSchema2(schema, path31, errors, opts = {}) {
9752
9752
  if (opts.isRoot) {
9753
9753
  if ("type" in schema && schema.type !== "object") {
9754
9754
  errors.push({
9755
- path: path31 ? `${path31}.type` : "type",
9755
+ path: path36 ? `${path36}.type` : "type",
9756
9756
  message: `root type must be 'object', got ${JSON.stringify(schema.type)}`,
9757
9757
  suggestion: "Tool parameters at the root must be an object: `{ type: 'object', properties: { ... } }`."
9758
9758
  });
9759
9759
  }
9760
9760
  } else if ("type" in schema && !typeMatches2(schema.type, ALLOWED_TYPES2)) {
9761
9761
  errors.push({
9762
- path: `${path31}.type`,
9762
+ path: `${path36}.type`,
9763
9763
  message: `type must be one of ${[...ALLOWED_TYPES2].join("/")} or an array of those, got ${JSON.stringify(schema.type)}`
9764
9764
  });
9765
9765
  }
@@ -9769,25 +9769,25 @@ function validateSchema2(schema, path31, errors, opts = {}) {
9769
9769
  const isPlaceholder = PLACEHOLDER_TOKENS2.includes(e);
9770
9770
  const isOutcomePlaceholder = e === "[KANBAN_OUTCOME_VALUES]";
9771
9771
  errors.push({
9772
- path: `${path31}.enum`,
9772
+ path: `${path36}.enum`,
9773
9773
  message: `enum must be a non-empty array of primitives, got string ${JSON.stringify(e)}`,
9774
9774
  suggestion: isOutcomePlaceholder ? "Declare `outcomes` on the hub's terminal kanban status so the platform can render the placeholder into a valid array; with none configured the platform drops the parameter instead." : isPlaceholder ? "Set `operation: 'update_kanban_status'` on the tool and ensure at least one hub.kanban_status has `allowsAgentUpdate: true` so the platform can render the placeholder into a valid array." : 'Wrap the value in an array: `enum: ["value"]`.'
9775
9775
  });
9776
9776
  } else if (!Array.isArray(e)) {
9777
9777
  errors.push({
9778
- path: `${path31}.enum`,
9778
+ path: `${path36}.enum`,
9779
9779
  message: `enum must be a non-empty array of primitives, got ${typeof e}`
9780
9780
  });
9781
9781
  } else if (e.length === 0) {
9782
9782
  errors.push({
9783
- path: `${path31}.enum`,
9783
+ path: `${path36}.enum`,
9784
9784
  message: "enum must not be empty"
9785
9785
  });
9786
9786
  } else {
9787
9787
  for (let i = 0; i < e.length; i++) {
9788
9788
  if (!isPrimitive2(e[i])) {
9789
9789
  errors.push({
9790
- path: `${path31}.enum[${i}]`,
9790
+ path: `${path36}.enum[${i}]`,
9791
9791
  message: `enum entry must be a primitive (string/number/boolean/null), got ${typeof e[i]}`
9792
9792
  });
9793
9793
  }
@@ -9797,7 +9797,7 @@ function validateSchema2(schema, path31, errors, opts = {}) {
9797
9797
  for (const key of ["exclusiveMinimum", "exclusiveMaximum"]) {
9798
9798
  if (key in schema && typeof schema[key] === "boolean") {
9799
9799
  errors.push({
9800
- path: `${path31}.${key}`,
9800
+ path: `${path36}.${key}`,
9801
9801
  message: `${key} as boolean is draft-04 syntax; draft 2020-12 requires a numeric value`,
9802
9802
  suggestion: `Replace with the numeric bound, e.g. \`${key}: 0\`.`
9803
9803
  });
@@ -9806,45 +9806,45 @@ function validateSchema2(schema, path31, errors, opts = {}) {
9806
9806
  if ("properties" in schema) {
9807
9807
  if (!isRecord2(schema.properties)) {
9808
9808
  errors.push({
9809
- path: `${path31}.properties`,
9809
+ path: `${path36}.properties`,
9810
9810
  message: `properties must be an object, got ${Array.isArray(schema.properties) ? "array" : typeof schema.properties}`
9811
9811
  });
9812
9812
  } else {
9813
9813
  for (const [propName, propSchema] of Object.entries(schema.properties)) {
9814
- validateSchema2(propSchema, `${path31}.properties.${propName}`, errors, { depth: depth + 1 });
9814
+ validateSchema2(propSchema, `${path36}.properties.${propName}`, errors, { depth: depth + 1 });
9815
9815
  }
9816
9816
  }
9817
9817
  }
9818
9818
  if (schemaTypeIncludes2(schema, "array") && "items" in schema) {
9819
9819
  if (Array.isArray(schema.items)) {
9820
- schema.items.forEach((sub, i) => validateSchema2(sub, `${path31}.items[${i}]`, errors, { depth: depth + 1 }));
9820
+ schema.items.forEach((sub, i) => validateSchema2(sub, `${path36}.items[${i}]`, errors, { depth: depth + 1 }));
9821
9821
  } else {
9822
- validateSchema2(schema.items, `${path31}.items`, errors, { depth: depth + 1 });
9822
+ validateSchema2(schema.items, `${path36}.items`, errors, { depth: depth + 1 });
9823
9823
  }
9824
9824
  }
9825
9825
  for (const key of SUBSCHEMA_OBJECT_KEYWORDS2) {
9826
9826
  if (key in schema && isRecord2(schema[key])) {
9827
- validateSchema2(schema[key], `${path31}.${key}`, errors, { depth: depth + 1 });
9827
+ validateSchema2(schema[key], `${path36}.${key}`, errors, { depth: depth + 1 });
9828
9828
  }
9829
9829
  }
9830
9830
  for (const key of SUBSCHEMA_LIST_KEYWORDS2) {
9831
9831
  const list = schema[key];
9832
9832
  if (Array.isArray(list)) {
9833
- list.forEach((sub, i) => validateSchema2(sub, `${path31}.${key}[${i}]`, errors, { depth: depth + 1 }));
9833
+ list.forEach((sub, i) => validateSchema2(sub, `${path36}.${key}[${i}]`, errors, { depth: depth + 1 }));
9834
9834
  }
9835
9835
  }
9836
9836
  for (const key of SUBSCHEMA_MAP_KEYWORDS2) {
9837
9837
  const map = schema[key];
9838
9838
  if (isRecord2(map)) {
9839
9839
  for (const [name, sub] of Object.entries(map)) {
9840
- validateSchema2(sub, `${path31}.${key}.${name}`, errors, { depth: depth + 1 });
9840
+ validateSchema2(sub, `${path36}.${key}.${name}`, errors, { depth: depth + 1 });
9841
9841
  }
9842
9842
  }
9843
9843
  }
9844
9844
  const reportedPaths = new Set(errors.map((e) => e.path));
9845
9845
  for (const [k, v] of Object.entries(schema)) {
9846
9846
  if (typeof v !== "string") continue;
9847
- const fieldPath = `${path31}.${k}`;
9847
+ const fieldPath = `${path36}.${k}`;
9848
9848
  if (reportedPaths.has(fieldPath)) continue;
9849
9849
  for (const token of PLACEHOLDER_TOKENS2) {
9850
9850
  if (v === token) {
@@ -9989,8 +9989,8 @@ function evalInitialStateError2(input) {
9989
9989
  const parsed = evalInitialStateEntry2.safeParse(entries[i]);
9990
9990
  if (!parsed.success) {
9991
9991
  const issue = parsed.error.issues[0];
9992
- const path31 = issue?.path.join(".") || "?";
9993
- return `initial_state[${i}].${path31} is invalid: ${issue?.message ?? "malformed"}`;
9992
+ const path36 = issue?.path.join(".") || "?";
9993
+ return `initial_state[${i}].${path36} is invalid: ${issue?.message ?? "malformed"}`;
9994
9994
  }
9995
9995
  if (seenSlugs.has(parsed.data.slug)) {
9996
9996
  return `initial_state[${i}].slug "${parsed.data.slug}" is declared more than once`;
@@ -10195,10 +10195,10 @@ function refineHubAsCodeEvals2(config, ctx) {
10195
10195
  function refineHubAsCodeEvalAttachments2(config, ctx) {
10196
10196
  const cfg = config;
10197
10197
  const referencedHashes = /* @__PURE__ */ new Set();
10198
- const addTurnIssue = (path31, turn, name) => {
10198
+ const addTurnIssue = (path36, turn, name) => {
10199
10199
  const error = evalTurnAttachmentsError2(turn);
10200
10200
  if (error) {
10201
- ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: path31, message: `${name}: ${error}` });
10201
+ ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: path36, message: `${name}: ${error}` });
10202
10202
  return;
10203
10203
  }
10204
10204
  for (const hash of collectTurnAttachmentHashes2(turn)) referencedHashes.add(hash);
@@ -10344,11 +10344,11 @@ function refineHubAsCodeDelegation2(config, ctx) {
10344
10344
  }
10345
10345
  }
10346
10346
  if (del.context_boundary === void 0) return;
10347
- const path31 = ["agents", agentIndex, "tools", "delegation", delIndex, "context_boundary"];
10347
+ const path36 = ["agents", agentIndex, "tools", "delegation", delIndex, "context_boundary"];
10348
10348
  if (del.type !== "hub") {
10349
10349
  ctx.addIssue({
10350
10350
  code: external_exports.ZodIssueCode.custom,
10351
- path: path31,
10351
+ path: path36,
10352
10352
  message: `context_boundary applies only to \`type: hub\` delegations (got type "${String(del.type)}")`
10353
10353
  });
10354
10354
  return;
@@ -10356,7 +10356,7 @@ function refineHubAsCodeDelegation2(config, ctx) {
10356
10356
  if (!CONTEXT_BOUNDARIES2.includes(del.context_boundary)) {
10357
10357
  ctx.addIssue({
10358
10358
  code: external_exports.ZodIssueCode.custom,
10359
- path: path31,
10359
+ path: path36,
10360
10360
  message: `context_boundary must be one of: ${CONTEXT_BOUNDARIES2.join(", ")}`
10361
10361
  });
10362
10362
  }
@@ -14149,6 +14149,10 @@ function hubsDirLabel(gitRoot) {
14149
14149
  if (!gitRoot) return path.join(WAYAI_LAYOUT.wsDir, WAYAI_LAYOUT.hubsSubdir);
14150
14150
  return path.relative(gitRoot, resolveLayout(gitRoot).hubsDir);
14151
14151
  }
14152
+ function basesDirLabel(gitRoot) {
14153
+ if (!gitRoot) return path.join(WAYAI_LAYOUT.wsDir, WAYAI_LAYOUT.basesSubdir);
14154
+ return path.relative(gitRoot, resolveLayout(gitRoot).basesDir);
14155
+ }
14152
14156
  function warnLayoutOnce(gitRoot) {
14153
14157
  const r = resolveLayout(gitRoot);
14154
14158
  if (r.legacyAlsoPresent) {
@@ -14640,24 +14644,24 @@ import * as path4 from "path";
14640
14644
  import * as readline from "readline";
14641
14645
  function prompt(question) {
14642
14646
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
14643
- return new Promise((resolve5) => {
14647
+ return new Promise((resolve7) => {
14644
14648
  rl.question(question, (answer) => {
14645
14649
  rl.close();
14646
- resolve5(answer.trim());
14650
+ resolve7(answer.trim());
14647
14651
  });
14648
14652
  });
14649
14653
  }
14650
14654
  function confirm(question) {
14651
14655
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
14652
- return new Promise((resolve5) => {
14656
+ return new Promise((resolve7) => {
14653
14657
  rl.question(`${question} [y/N]: `, (answer) => {
14654
14658
  rl.close();
14655
- resolve5(answer.trim().toLowerCase() === "y");
14659
+ resolve7(answer.trim().toLowerCase() === "y");
14656
14660
  });
14657
14661
  });
14658
14662
  }
14659
14663
  function promptSecret(question) {
14660
- return new Promise((resolve5) => {
14664
+ return new Promise((resolve7) => {
14661
14665
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
14662
14666
  const originalWrite = rl._writeToOutput;
14663
14667
  let firstWrite = true;
@@ -14673,18 +14677,18 @@ function promptSecret(question) {
14673
14677
  rl._writeToOutput = originalWrite;
14674
14678
  process.stdout.write("\n");
14675
14679
  rl.close();
14676
- resolve5(answer);
14680
+ resolve7(answer);
14677
14681
  });
14678
14682
  });
14679
14683
  }
14680
14684
  function readStdin() {
14681
- return new Promise((resolve5, reject) => {
14685
+ return new Promise((resolve7, reject) => {
14682
14686
  let data = "";
14683
14687
  process.stdin.setEncoding("utf-8");
14684
14688
  process.stdin.on("data", (chunk) => {
14685
14689
  data += chunk;
14686
14690
  });
14687
- process.stdin.on("end", () => resolve5(data.trim()));
14691
+ process.stdin.on("end", () => resolve7(data.trim()));
14688
14692
  process.stdin.on("error", reject);
14689
14693
  });
14690
14694
  }
@@ -15123,7 +15127,7 @@ var init_registry = __esm({
15123
15127
  disposition: "routed",
15124
15128
  surviving: "pull",
15125
15129
  clause: null,
15126
- shipped: false,
15130
+ shipped: true,
15127
15131
  reason: "One verb, workspace-relative, routing by subtree: `hubs/` targets preview hubs, `bases/` targets preview bases. An invocation spanning both is refused, never merged."
15128
15132
  },
15129
15133
  {
@@ -15131,7 +15135,7 @@ var init_registry = __esm({
15131
15135
  disposition: "routed",
15132
15136
  surviving: "push",
15133
15137
  clause: null,
15134
- shipped: false,
15138
+ shipped: true,
15135
15139
  reason: "Same as `pull`."
15136
15140
  }
15137
15141
  ];
@@ -15150,9 +15154,9 @@ function getVersionCachePath(filename = CLI_CACHE_FILE) {
15150
15154
  }
15151
15155
  function readVersionCache(filename = CLI_CACHE_FILE) {
15152
15156
  try {
15153
- const path31 = getVersionCachePath(filename);
15154
- if (!existsSync4(path31)) return null;
15155
- const parsed = JSON.parse(readFileSync5(path31, "utf-8"));
15157
+ const path36 = getVersionCachePath(filename);
15158
+ if (!existsSync4(path36)) return null;
15159
+ const parsed = JSON.parse(readFileSync5(path36, "utf-8"));
15156
15160
  if (typeof parsed.lastCheck !== "number") return null;
15157
15161
  if (parsed.latest !== null && typeof parsed.latest !== "string") return null;
15158
15162
  return parsed;
@@ -15172,10 +15176,10 @@ function isVersionCacheStale(filename = CLI_CACHE_FILE, maxAgeMs = MAX_AGE_24H_M
15172
15176
  return Date.now() - cache.lastCheck > maxAgeMs;
15173
15177
  }
15174
15178
  function writeVersionCache(filename, cache) {
15175
- const path31 = getVersionCachePath(filename);
15176
- const dir = dirname3(path31);
15179
+ const path36 = getVersionCachePath(filename);
15180
+ const dir = dirname3(path36);
15177
15181
  if (!existsSync4(dir)) mkdirSync(dir, { recursive: true });
15178
- writeFileSync2(path31, JSON.stringify(cache));
15182
+ writeFileSync2(path36, JSON.stringify(cache));
15179
15183
  }
15180
15184
  function touchVersionCache(filename) {
15181
15185
  writeVersionCache(filename, { lastCheck: Date.now(), latest: readVersionCache(filename)?.latest ?? null });
@@ -15214,14 +15218,14 @@ function parseFrontmatterVersion(content) {
15214
15218
  function findInstalledSkills(projectRoot, paths = SKILL_INSTALL_PATHS) {
15215
15219
  const found = [];
15216
15220
  for (const rel of paths) {
15217
- const path31 = join7(projectRoot, rel);
15218
- if (!existsSync5(path31)) continue;
15221
+ const path36 = join7(projectRoot, rel);
15222
+ if (!existsSync5(path36)) continue;
15219
15223
  let version = null;
15220
15224
  try {
15221
- version = parseFrontmatterVersion(readFileSync6(path31, "utf-8"));
15225
+ version = parseFrontmatterVersion(readFileSync6(path36, "utf-8"));
15222
15226
  } catch {
15223
15227
  }
15224
- found.push({ path: path31, version });
15228
+ found.push({ path: path36, version });
15225
15229
  }
15226
15230
  return found;
15227
15231
  }
@@ -15682,7 +15686,7 @@ async function validateToken(apiUrl, token) {
15682
15686
  }
15683
15687
  }
15684
15688
  function startCallbackServer(port, expectedState, timeoutMs = 12e4) {
15685
- return new Promise((resolve5, reject) => {
15689
+ return new Promise((resolve7, reject) => {
15686
15690
  const server = http.createServer((req, res) => {
15687
15691
  const url = new URL(req.url || "/", `http://127.0.0.1:${port}`);
15688
15692
  if (url.pathname === "/callback") {
@@ -15708,7 +15712,7 @@ function startCallbackServer(port, expectedState, timeoutMs = 12e4) {
15708
15712
  res.writeHead(200, { "Content-Type": "text/html" });
15709
15713
  res.end("<html><body><h2>Login successful!</h2><p>You can close this tab and return to your terminal.</p></body></html>");
15710
15714
  server.close();
15711
- resolve5({ code, port });
15715
+ resolve7({ code, port });
15712
15716
  } else {
15713
15717
  res.writeHead(400, { "Content-Type": "text/html" });
15714
15718
  res.end("<html><body><h2>Login failed</h2><p>No authorization code received</p></body></html>");
@@ -15919,10 +15923,10 @@ import * as readline2 from "readline";
15919
15923
  function prompt2(question, defaultValue) {
15920
15924
  const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
15921
15925
  const display = defaultValue ? `${question} [${defaultValue}]: ` : `${question}: `;
15922
- return new Promise((resolve5) => {
15926
+ return new Promise((resolve7) => {
15923
15927
  rl.question(display, (answer) => {
15924
15928
  rl.close();
15925
- resolve5(answer.trim() || defaultValue || "");
15929
+ resolve7(answer.trim() || defaultValue || "");
15926
15930
  });
15927
15931
  });
15928
15932
  }
@@ -16040,8 +16044,8 @@ async function tryOpenBrowser(url) {
16040
16044
  cmd = "xdg-open";
16041
16045
  args2 = [url];
16042
16046
  }
16043
- return new Promise((resolve5) => {
16044
- execFile(cmd, args2, (err) => resolve5(!err));
16047
+ return new Promise((resolve7) => {
16048
+ execFile(cmd, args2, (err) => resolve7(!err));
16045
16049
  });
16046
16050
  } catch {
16047
16051
  return false;
@@ -16801,6 +16805,15 @@ function ensureRealSubdirNoSymlink(root, target, create) {
16801
16805
  }
16802
16806
  return true;
16803
16807
  }
16808
+ function readFileNoFollow(root, abs) {
16809
+ if (!ensureRealSubdirNoSymlink(root, path11.dirname(abs), false)) return null;
16810
+ try {
16811
+ if (!fs9.lstatSync(abs).isFile()) return null;
16812
+ return fs9.readFileSync(abs);
16813
+ } catch {
16814
+ return null;
16815
+ }
16816
+ }
16804
16817
  function writeFileNoFollow(root, abs, data) {
16805
16818
  const parent = path11.dirname(abs);
16806
16819
  if (!ensureRealSubdirNoSymlink(root, parent, true)) return false;
@@ -18051,202 +18064,1414 @@ var init_hub_materializer = __esm({
18051
18064
  }
18052
18065
  });
18053
18066
 
18054
- // src/commands/push.ts
18055
- var push_exports = {};
18056
- __export(push_exports, {
18057
- autoRenameAgentFiles: () => autoRenameAgentFiles,
18058
- createAndPushNewHub: () => createAndPushNewHub,
18059
- printErrors: () => printErrors,
18060
- printLocalFileChanges: () => printLocalFileChanges,
18061
- printSyncResult: () => printSyncResult,
18062
- printWarnings: () => printWarnings,
18063
- pushCommand: () => pushCommand,
18064
- reportUnresolvedPushTarget: () => reportUnresolvedPushTarget,
18065
- selectExistingHub: () => selectExistingHub,
18066
- shouldWarnIgnoredPreviewLabel: () => shouldWarnIgnoredPreviewLabel,
18067
- syncAfterPush: () => syncAfterPush
18067
+ // src/lib/terminal-output.ts
18068
+ import { stripVTControlCharacters } from "util";
18069
+ function sanitizeTerminalText(value) {
18070
+ const normalizedNewlines = value.replace(/\r\n?/g, "\n");
18071
+ return stripVTControlCharacters(normalizedNewlines).replace(
18072
+ /[\u0000-\u0009\u000b-\u001f\u007f-\u009f]/g,
18073
+ ""
18074
+ );
18075
+ }
18076
+ var init_terminal_output = __esm({
18077
+ "src/lib/terminal-output.ts"() {
18078
+ "use strict";
18079
+ }
18080
+ });
18081
+
18082
+ // src/lib/base-id.ts
18083
+ function isValidBaseId(id) {
18084
+ return BASE_ID_RE.test(id);
18085
+ }
18086
+ var BASE_ID_RE;
18087
+ var init_base_id = __esm({
18088
+ "src/lib/base-id.ts"() {
18089
+ "use strict";
18090
+ BASE_ID_RE = /^(?!\.\.?$)[A-Za-z0-9._-]{1,256}$/;
18091
+ }
18068
18092
  });
18093
+
18094
+ // src/lib/base-workspace.ts
18069
18095
  import * as fs14 from "fs";
18070
18096
  import * as path17 from "path";
18071
18097
  import * as yaml6 from "js-yaml";
18072
- function parseArgs4(args2) {
18073
- let autoConfirm = false;
18074
- let hubSelector;
18075
- let label;
18076
- for (let i = 0; i < args2.length; i++) {
18077
- const arg = args2[i];
18078
- if (arg === "--yes" || arg === "-y") {
18079
- autoConfirm = true;
18080
- } else if (arg === "--hub" && args2[i + 1]) {
18081
- hubSelector = args2[++i];
18082
- } else if (arg === "--label" && args2[i + 1]) {
18083
- label = args2[++i];
18084
- }
18098
+ function readBaseMeta(folder) {
18099
+ const bytes = readFileNoFollow(folder, path17.join(folder, BASE_META_FILE));
18100
+ if (bytes === null) return null;
18101
+ let doc;
18102
+ try {
18103
+ doc = yaml6.load(bytes.toString("utf-8"));
18104
+ } catch {
18105
+ return null;
18085
18106
  }
18086
- return { autoConfirm, hubSelector, label };
18087
- }
18088
- function shouldWarnIgnoredPreviewLabel(localLabel, serverLabel) {
18089
- return Boolean(localLabel) && serverLabel !== void 0 && localLabel !== serverLabel;
18107
+ if (!doc || typeof doc !== "object" || Array.isArray(doc)) return null;
18108
+ return doc;
18090
18109
  }
18091
- function printSyncResult(result) {
18092
- const applyErrors = result.apply_errors ?? result.errors;
18093
- if (applyErrors && applyErrors.length > 0) {
18094
- printErrors(applyErrors);
18095
- throw expected(`Sync failed with ${applyErrors.length} error(s). No completion was reported; inspect the errors above.`);
18110
+ function listBaseFolders(basesDir) {
18111
+ let entries;
18112
+ try {
18113
+ entries = fs14.readdirSync(basesDir).filter((entry) => !entry.startsWith("."));
18114
+ } catch {
18115
+ return [];
18096
18116
  }
18097
- console.log(`
18098
- Sync complete. Preview hub: ${result.preview_hub_id}`);
18099
- const c = result.changes;
18100
- const parts = [];
18101
- if (c.hub_updated) parts.push("hub updated");
18102
- if (c.connections_created > 0) parts.push(`${c.connections_created} connection(s) created`);
18103
- if (c.connections_updated > 0) parts.push(`${c.connections_updated} connection(s) updated`);
18104
- if (c.connections_deleted > 0) parts.push(`${c.connections_deleted} connection(s) deleted`);
18105
- if (c.agents_created > 0) parts.push(`${c.agents_created} agent(s) created`);
18106
- if (c.agents_updated > 0) parts.push(`${c.agents_updated} agent(s) updated`);
18107
- if (c.agents_deleted > 0) parts.push(`${c.agents_deleted} agent(s) deleted`);
18108
- if (c.tools_created > 0) parts.push(`${c.tools_created} tool(s) created`);
18109
- if (c.tools_updated > 0) parts.push(`${c.tools_updated} tool(s) updated`);
18110
- if (c.tools_deleted > 0) parts.push(`${c.tools_deleted} tool(s) deleted`);
18111
- if (c.states_created > 0) parts.push(`${c.states_created} state(s) created`);
18112
- if (c.states_updated > 0) parts.push(`${c.states_updated} state(s) updated`);
18113
- if (c.states_deleted > 0) parts.push(`${c.states_deleted} state(s) deleted`);
18114
- if (c.evals_created > 0) parts.push(`${c.evals_created} eval(s) created`);
18115
- if (c.evals_updated > 0) parts.push(`${c.evals_updated} eval(s) updated`);
18116
- if (c.evals_deleted > 0) parts.push(`${c.evals_deleted} eval(s) deleted`);
18117
- if (c.journeys_created > 0) parts.push(`${c.journeys_created} journey(s) created`);
18118
- if (c.journeys_updated > 0) parts.push(`${c.journeys_updated} journey(s) updated`);
18119
- if (c.journeys_deleted > 0) parts.push(`${c.journeys_deleted} journey(s) deleted`);
18120
- if (c.teams_created > 0) parts.push(`${c.teams_created} team(s) created`);
18121
- if (c.teams_updated > 0) parts.push(`${c.teams_updated} team(s) updated`);
18122
- if (c.teams_deleted > 0) parts.push(`${c.teams_deleted} team(s) deleted`);
18123
- if (c.resources_created > 0) parts.push(`${c.resources_created} resource(s) created`);
18124
- if (c.resources_updated > 0) parts.push(`${c.resources_updated} resource(s) updated`);
18125
- if (c.resources_deleted > 0) parts.push(`${c.resources_deleted} resource(s) deleted`);
18126
- if (c.resource_files_uploaded > 0) parts.push(`${c.resource_files_uploaded} resource file(s) uploaded`);
18127
- if (c.resource_files_deleted > 0) parts.push(`${c.resource_files_deleted} resource file(s) deleted`);
18128
- if (c.resource_links_created > 0) parts.push(`${c.resource_links_created} resource link(s) created`);
18129
- if (c.resource_links_updated > 0) parts.push(`${c.resource_links_updated} resource link(s) updated`);
18130
- if (c.resource_links_deleted > 0) parts.push(`${c.resource_links_deleted} resource link(s) deleted`);
18131
- if (c.outbound_contacts_created > 0) parts.push(`${c.outbound_contacts_created} outbound contact(s) created`);
18132
- if (c.outbound_contacts_updated > 0) parts.push(`${c.outbound_contacts_updated} outbound contact(s) updated`);
18133
- if (c.outbound_contacts_deleted > 0) parts.push(`${c.outbound_contacts_deleted} outbound contact(s) deleted`);
18134
- if (c.outbound_lists_created > 0) parts.push(`${c.outbound_lists_created} outbound list(s) created`);
18135
- if (c.outbound_lists_updated > 0) parts.push(`${c.outbound_lists_updated} outbound list(s) updated`);
18136
- if (c.outbound_lists_deleted > 0) parts.push(`${c.outbound_lists_deleted} outbound list(s) deleted`);
18137
- if (c.outbound_schedules_created > 0) parts.push(`${c.outbound_schedules_created} outbound schedule(s) created`);
18138
- if (c.outbound_schedules_updated > 0) parts.push(`${c.outbound_schedules_updated} outbound schedule(s) updated`);
18139
- if (c.outbound_schedules_deleted > 0) parts.push(`${c.outbound_schedules_deleted} outbound schedule(s) deleted`);
18140
- if (parts.length > 0) {
18141
- console.log(`Changes: ${parts.join(", ")}`);
18117
+ const out = [];
18118
+ for (const name of entries.sort()) {
18119
+ const folder = path17.join(basesDir, name);
18120
+ if (!isDirectory(folder)) continue;
18121
+ const meta = readBaseMeta(folder);
18122
+ if (meta) out.push({ folder, meta });
18142
18123
  }
18143
- if (result.warnings && result.warnings.length > 0) {
18144
- printWarnings(result.warnings.map((w) => w.message));
18124
+ return out;
18125
+ }
18126
+ function isProductionFolder(meta) {
18127
+ return meta.environment === "production";
18128
+ }
18129
+ function filterEditableBases(bases) {
18130
+ return bases.filter((b) => !isProductionFolder(b.meta));
18131
+ }
18132
+ function isUnder(parent, child) {
18133
+ const rel = path17.relative(parent, child);
18134
+ return rel === "" || !rel.startsWith("..") && !path17.isAbsolute(rel);
18135
+ }
18136
+ function findEnclosingBaseFolder(basesDir, cwd) {
18137
+ let dir = path17.resolve(cwd);
18138
+ const stop = path17.resolve(basesDir);
18139
+ while (isUnder(stop, dir)) {
18140
+ const meta = readBaseMeta(dir);
18141
+ if (meta) return { folder: dir, meta };
18142
+ const parent = path17.dirname(dir);
18143
+ if (parent === dir) break;
18144
+ dir = parent;
18145
18145
  }
18146
+ return null;
18146
18147
  }
18147
- function printWarnings(warnings) {
18148
- if (warnings.length === 0) return;
18149
- console.log(`
18150
- \x1B[33mWarnings (${warnings.length}):\x1B[0m`);
18151
- for (const w of warnings) {
18152
- console.log(` \x1B[33m! ${w}\x1B[0m`);
18148
+ function folderForSelector(basesDir, selector) {
18149
+ assertValidBaseSelector(selector);
18150
+ return path17.join(basesDir, selector);
18151
+ }
18152
+ function assertValidBaseSelector(selector, source = "base") {
18153
+ if (!isValidBaseId(selector)) {
18154
+ throw expected(
18155
+ `Invalid ${source} "${selector}". Base ids are slugs \u2014 letters, digits, dot, dash and underscore only, with no path separators.`
18156
+ );
18153
18157
  }
18154
18158
  }
18155
- function printErrors(errors) {
18156
- if (errors.length === 0) return;
18157
- console.error(`
18158
- \x1B[31mErrors (${errors.length}):\x1B[0m`);
18159
- for (const error of errors) {
18160
- const message = typeof error === "string" ? error : error.message;
18161
- console.error(` \x1B[31m! ${message}\x1B[0m`);
18159
+ function resolveBaseTarget(gitRoot, selector, cwd = process.cwd()) {
18160
+ const basesDir = resolveBasesDir(gitRoot);
18161
+ if (selector) {
18162
+ const folder = folderForSelector(basesDir, selector);
18163
+ if (!isUnder(basesDir, folder)) {
18164
+ throw expected(`Refusing to target ${folder}: it is outside ${basesDir}.`);
18165
+ }
18166
+ return { folder, exists: hasBaseMetaFile(folder), meta: readBaseMeta(folder) };
18167
+ }
18168
+ const enclosing = findEnclosingBaseFolder(basesDir, cwd);
18169
+ if (enclosing) return { folder: enclosing.folder, exists: true, meta: enclosing.meta };
18170
+ const editable = filterEditableBases(listBaseFolders(basesDir));
18171
+ if (editable.length === 1) {
18172
+ return { folder: editable[0].folder, exists: true, meta: editable[0].meta };
18173
+ }
18174
+ const label = basesDirLabel(gitRoot);
18175
+ if (editable.length === 0) {
18176
+ throw expected(
18177
+ `No base folders found in ${label}/. Pass a base id to fetch one for the first time (e.g. \`wayai pull bases/<base>\`).`
18178
+ );
18162
18179
  }
18180
+ throw expected(
18181
+ [
18182
+ `Multiple bases found in ${label}/. Pass --base <id|folder-name> to choose, or run from inside a base folder:`,
18183
+ ...editable.map((b) => ` ${path17.basename(b.folder)} (${b.meta.base_id ?? "not created yet"})`)
18184
+ ].join("\n")
18185
+ );
18163
18186
  }
18164
- function printLocalFileChanges(delta) {
18165
- if (delta.changed.length === 0 && delta.removed.length === 0) {
18166
- console.log("Local files already in sync.");
18167
- return;
18187
+ function targetBaseId(target, selector) {
18188
+ if (target.meta?.base_id) return target.meta.base_id;
18189
+ if (selector && !selector.includes("/") && !selector.includes(path17.sep)) return selector;
18190
+ return target.exists ? null : path17.basename(target.folder);
18191
+ }
18192
+ function hasBaseMetaFile(folder) {
18193
+ try {
18194
+ return fs14.lstatSync(path17.join(folder, BASE_META_FILE)).isFile();
18195
+ } catch {
18196
+ return false;
18168
18197
  }
18169
- console.log("Local files updated from server:");
18170
- const emit = (paths, sigil) => {
18171
- const sorted = [...paths].sort();
18172
- for (const p of sorted.slice(0, LOCAL_CHANGE_LIST_CAP)) console.log(` ${sigil} ${p}`);
18173
- if (sorted.length > LOCAL_CHANGE_LIST_CAP) {
18174
- console.log(` \u2026and ${sorted.length - LOCAL_CHANGE_LIST_CAP} more ${sigil === "-" ? "removed" : "changed"}`);
18198
+ }
18199
+ var BASE_META_FILE;
18200
+ var init_base_workspace = __esm({
18201
+ "src/lib/base-workspace.ts"() {
18202
+ "use strict";
18203
+ init_layout();
18204
+ init_expected();
18205
+ init_base_id();
18206
+ init_fs_safety();
18207
+ BASE_META_FILE = "base.yaml";
18208
+ }
18209
+ });
18210
+
18211
+ // src/lib/subtree-routing.ts
18212
+ import * as fs15 from "fs";
18213
+ import * as path18 from "path";
18214
+ import * as yaml7 from "js-yaml";
18215
+ function readRepoDefaults(gitRoot) {
18216
+ const file = path18.join(gitRoot, WAYAI_LAYOUT.wsDir, REPO_DEFAULTS_FILE);
18217
+ let doc;
18218
+ try {
18219
+ doc = yaml7.load(fs15.readFileSync(file, "utf-8"));
18220
+ } catch {
18221
+ return {};
18222
+ }
18223
+ if (!doc || typeof doc !== "object") return {};
18224
+ const raw = doc;
18225
+ const str = (v) => {
18226
+ if (typeof v !== "string" || !v.trim()) return void 0;
18227
+ const value = v.trim();
18228
+ if (value.includes("/") || value.includes(path18.sep) || value === "." || value === "..") {
18229
+ console.warn(
18230
+ `Warning: ignoring ${JSON.stringify(value)} in ${WAYAI_LAYOUT.wsDir}/${REPO_DEFAULTS_FILE} \u2014 a default names a hub or base, not a path.`
18231
+ );
18232
+ return void 0;
18175
18233
  }
18234
+ return value;
18176
18235
  };
18177
- emit(delta.removed, "-");
18178
- emit(delta.changed, "~");
18236
+ return { default_hub: str(raw.default_hub), default_base: str(raw.default_base) };
18179
18237
  }
18180
- async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, remoteConfig) {
18181
- const agentsDir = path17.join(hubFolder, "agents");
18182
- let agentsWithIds = [];
18183
- if (fs14.existsSync(agentsDir)) {
18184
- const yamlFiles = fs14.readdirSync(agentsDir).filter((f) => f.endsWith(".yaml"));
18185
- for (const file of yamlFiles) {
18186
- try {
18187
- const content = fs14.readFileSync(path17.join(agentsDir, file), "utf-8");
18188
- const agent = yaml6.load(content);
18189
- if (agent?.id && agent.name) {
18190
- agentsWithIds.push({ id: agent.id, name: agent.name });
18191
- }
18192
- } catch {
18193
- console.warn(` Warning: could not parse agents/${file}, skipping`);
18238
+ function parseRoutingTokens(args2) {
18239
+ const tokens = {};
18240
+ for (let i = 0; i < args2.length; i++) {
18241
+ const arg = args2[i];
18242
+ const eq = arg.indexOf("=");
18243
+ const name = eq === -1 ? arg : arg.slice(0, eq);
18244
+ if (VALUE_FLAGS.has(name)) {
18245
+ const value = eq === -1 ? args2[i + 1] : arg.slice(eq + 1);
18246
+ if (value !== void 0) {
18247
+ if (name === "--hub") tokens.hubFlag ??= value;
18248
+ if (name === "--base") tokens.baseFlag ??= value;
18249
+ if (name === "--org") tokens.orgFlag ??= value;
18250
+ if (eq === -1) i++;
18194
18251
  }
18252
+ continue;
18195
18253
  }
18254
+ if (arg.startsWith("-")) continue;
18255
+ tokens.positional ??= arg;
18196
18256
  }
18197
- if (agentsWithIds.length === 0) {
18198
- const yamlPath = resolveHubYamlPath(hubFolder);
18199
- if (!yamlPath) return;
18200
- const yamlContent = fs14.readFileSync(yamlPath, "utf-8");
18201
- const config = yaml6.load(yamlContent);
18202
- agentsWithIds = (config.agents || []).filter((a) => !!a.id && !!a.name);
18257
+ return tokens;
18258
+ }
18259
+ function firstSegment(p) {
18260
+ const normalized = p.split(path18.sep).join("/");
18261
+ const [head] = normalized.split("/").filter(Boolean);
18262
+ return head ?? p;
18263
+ }
18264
+ function selectorSubtree(layout, selector, cwd) {
18265
+ const parts = selector.split(path18.sep).join("/").split("/").filter(Boolean);
18266
+ const qualified = parts[0] === WAYAI_LAYOUT.wsDir ? parts.slice(1) : parts;
18267
+ if (qualified.length > 1) {
18268
+ if (qualified[0] === WAYAI_LAYOUT.hubsSubdir) return { kind: "hubs", target: qualified[1] };
18269
+ if (qualified[0] === WAYAI_LAYOUT.basesSubdir) return { kind: "bases", target: qualified[1] };
18270
+ }
18271
+ if (!layout) return { kind: "unknown" };
18272
+ const { hubsDir, basesDir } = layout;
18273
+ if (selector.includes("/") || selector.includes(path18.sep)) {
18274
+ const abs = path18.resolve(cwd, selector);
18275
+ if (isUnder(hubsDir, abs)) return { kind: "hubs", target: firstSegment(path18.relative(hubsDir, abs)) };
18276
+ if (isUnder(basesDir, abs)) return { kind: "bases", target: firstSegment(path18.relative(basesDir, abs)) };
18277
+ return { kind: "unknown" };
18278
+ }
18279
+ const inHubs = isDirectory(path18.join(hubsDir, selector));
18280
+ const inBases = isDirectory(path18.join(basesDir, selector));
18281
+ if (inHubs && inBases) return { kind: "both", target: selector };
18282
+ if (inHubs) return { kind: "hubs", target: selector };
18283
+ if (inBases) return { kind: "bases", target: selector };
18284
+ return { kind: "unknown" };
18285
+ }
18286
+ function listCandidates(layout) {
18287
+ const hubs = [
18288
+ ...filterPreviewHubs(scanWorkspaceHubs(layout.hubsDir)).map((h) => h.hubFolder),
18289
+ ...scanNewHubs(layout.hubsDir).map((h) => h.hubFolder)
18290
+ ];
18291
+ const bases = filterEditableBases(listBaseFolders(layout.basesDir)).map((b) => b.folder);
18292
+ return [
18293
+ ...hubs.map((folder) => ({ subtree: "hubs", name: path18.basename(folder) })),
18294
+ ...bases.map((folder) => ({ subtree: "bases", name: path18.basename(folder) }))
18295
+ ];
18296
+ }
18297
+ function mixedInvocationRefusal(verb, hubTarget, baseTarget) {
18298
+ const hub = sanitizeTerminalText(hubTarget);
18299
+ const base = sanitizeTerminalText(baseTarget);
18300
+ return [
18301
+ `Refusing a mixed ${verb}: this invocation spans both subtrees.`,
18302
+ ` ${WAYAI_LAYOUT.hubsSubdir}/ -> ${hub}`,
18303
+ ` ${WAYAI_LAYOUT.basesSubdir}/ -> ${base}`,
18304
+ "",
18305
+ "Run one at a time:",
18306
+ ` wayai ${verb} ${WAYAI_LAYOUT.hubsSubdir}/${hub}`,
18307
+ ` wayai ${verb} ${WAYAI_LAYOUT.basesSubdir}/${base}`
18308
+ ].join("\n");
18309
+ }
18310
+ function routeSubtree(options) {
18311
+ const { verb, args: args2, gitRoot } = options;
18312
+ const cwd = options.cwd ?? process.cwd();
18313
+ const { hubFlag, baseFlag, positional, orgFlag } = parseRoutingTokens(args2);
18314
+ if (orgFlag !== void 0) {
18315
+ return {
18316
+ ok: false,
18317
+ refusal: [
18318
+ `\`wayai ${verb}\` does not take --org: it operates on the organization named by .wayai.yaml at the repo root.`,
18319
+ "",
18320
+ "To act on another organization:",
18321
+ " wayai bases <command> --org <uuid> # the Data surface honors it",
18322
+ " # or run from a checkout whose .wayai.yaml names that organization"
18323
+ ].join("\n")
18324
+ };
18203
18325
  }
18204
- if (agentsWithIds.length === 0) return;
18205
- console.log("Checking for agent renames...");
18206
- let remote = remoteConfig;
18207
- if (!remote) {
18208
- try {
18209
- remote = await client.pull(hubId, organizationId);
18210
- } catch (err) {
18211
- console.warn(` Warning: could not fetch remote state for auto-rename (${err instanceof Error ? err.message : String(err)}). File renames skipped.`);
18212
- return;
18213
- }
18326
+ const layout = gitRoot ? resolveLayout(gitRoot) : null;
18327
+ if (hubFlag !== void 0 && baseFlag !== void 0) {
18328
+ return { ok: false, refusal: mixedInvocationRefusal(verb, hubFlag, baseFlag) };
18214
18329
  }
18215
- const remoteAgentNames = /* @__PURE__ */ new Map();
18216
- for (const agent of remote.agents || []) {
18217
- if (agent.id) {
18218
- remoteAgentNames.set(agent.id, agent.name);
18219
- }
18330
+ const fromPositional = positional !== void 0 ? selectorSubtree(layout, positional, cwd) : void 0;
18331
+ if (fromPositional?.kind === "both") {
18332
+ return {
18333
+ ok: false,
18334
+ refusal: mixedInvocationRefusal(verb, fromPositional.target, fromPositional.target)
18335
+ };
18220
18336
  }
18221
- const renames = [];
18222
- for (const agent of agentsWithIds) {
18223
- const remoteName = remoteAgentNames.get(agent.id);
18224
- if (!remoteName || remoteName === agent.name) continue;
18225
- const oldSlug = slugify(remoteName);
18226
- const newSlug = slugify(agent.name);
18227
- if (oldSlug !== newSlug) {
18228
- renames.push({ oldSlug, newSlug });
18337
+ if (hubFlag !== void 0) {
18338
+ if (fromPositional?.kind === "bases") {
18339
+ return { ok: false, refusal: mixedInvocationRefusal(verb, hubFlag, fromPositional.target) };
18229
18340
  }
18341
+ return { ok: true, subtree: "hubs", selector: hubFlag };
18230
18342
  }
18231
- if (renames.length === 0) return;
18232
- if (!fs14.existsSync(agentsDir)) return;
18233
- for (const file of fs14.readdirSync(agentsDir)) {
18234
- if (file.startsWith("__rename_temp_") && (file.endsWith(".md") || file.endsWith(".yaml"))) {
18235
- console.warn(` Warning: removing orphaned temp file agents/${file}`);
18236
- fs14.unlinkSync(path17.join(agentsDir, file));
18343
+ if (baseFlag !== void 0) {
18344
+ if (fromPositional?.kind === "hubs") {
18345
+ return { ok: false, refusal: mixedInvocationRefusal(verb, fromPositional.target, baseFlag) };
18237
18346
  }
18347
+ return { ok: true, subtree: "bases", selector: baseFlag };
18238
18348
  }
18239
- const renameFileIfExists = (dir, oldName, newName) => {
18240
- const oldPath = path17.join(dir, oldName);
18241
- const newPath = path17.join(dir, newName);
18242
- if (!fs14.existsSync(oldPath)) return false;
18243
- fs14.renameSync(oldPath, newPath);
18244
- return true;
18245
- };
18246
- const oldSlugs = new Set(renames.map((r) => r.oldSlug));
18247
- const newSlugs = new Set(renames.map((r) => r.newSlug));
18248
- const hasConflicts = renames.some((r) => oldSlugs.has(r.newSlug)) || newSlugs.size !== renames.length;
18249
- const completedRenames = [];
18349
+ if (fromPositional?.kind === "hubs" || fromPositional?.kind === "bases") {
18350
+ return { ok: true, subtree: fromPositional.kind, selector: fromPositional.target };
18351
+ }
18352
+ const carried = positional;
18353
+ if (!gitRoot || !layout) return { ok: true, subtree: "hubs", selector: carried };
18354
+ const { hubsDir, basesDir } = layout;
18355
+ if (isUnder(hubsDir, cwd)) return { ok: true, subtree: "hubs", selector: carried };
18356
+ if (isUnder(basesDir, cwd)) return { ok: true, subtree: "bases", selector: carried };
18357
+ const defaults = readRepoDefaults(gitRoot);
18358
+ if (defaults.default_hub && defaults.default_base) {
18359
+ return {
18360
+ ok: false,
18361
+ refusal: mixedInvocationRefusal(verb, defaults.default_hub, defaults.default_base)
18362
+ };
18363
+ }
18364
+ if (defaults.default_hub) return { ok: true, subtree: "hubs", selector: carried ?? defaults.default_hub };
18365
+ if (defaults.default_base) return { ok: true, subtree: "bases", selector: carried ?? defaults.default_base };
18366
+ const candidates = listCandidates(layout);
18367
+ if (candidates.length === 1) {
18368
+ return { ok: true, subtree: candidates[0].subtree, selector: carried };
18369
+ }
18370
+ const hubCandidates = candidates.filter((c) => c.subtree === "hubs");
18371
+ const baseCandidates = candidates.filter((c) => c.subtree === "bases");
18372
+ if (hubCandidates.length > 0 && baseCandidates.length > 0) {
18373
+ return {
18374
+ ok: false,
18375
+ refusal: mixedInvocationRefusal(verb, hubCandidates[0].name, baseCandidates[0].name)
18376
+ };
18377
+ }
18378
+ if (baseCandidates.length > 0) return { ok: true, subtree: "bases", selector: carried };
18379
+ return { ok: true, subtree: "hubs", selector: carried };
18380
+ }
18381
+ function requireSubtree(verb, args2, gitRoot) {
18382
+ const result = routeSubtree({ verb, args: args2, gitRoot });
18383
+ if (!result.ok) {
18384
+ console.error(result.refusal);
18385
+ process.exit(1);
18386
+ }
18387
+ return { subtree: result.subtree, selector: result.selector };
18388
+ }
18389
+ var REPO_DEFAULTS_FILE, VALUE_FLAGS;
18390
+ var init_subtree_routing = __esm({
18391
+ "src/lib/subtree-routing.ts"() {
18392
+ "use strict";
18393
+ init_layout();
18394
+ init_terminal_output();
18395
+ init_workspace();
18396
+ init_base_workspace();
18397
+ REPO_DEFAULTS_FILE = "wayai.yaml";
18398
+ VALUE_FLAGS = /* @__PURE__ */ new Set(["--hub", "--base", "--label", "--org"]);
18399
+ }
18400
+ });
18401
+
18402
+ // src/data/org-context.ts
18403
+ function setDataOrgOverride(orgId) {
18404
+ override = orgId;
18405
+ }
18406
+ function getDataOrgOverride() {
18407
+ return override;
18408
+ }
18409
+ var override;
18410
+ var init_org_context = __esm({
18411
+ "src/data/org-context.ts"() {
18412
+ "use strict";
18413
+ }
18414
+ });
18415
+
18416
+ // src/data/client.ts
18417
+ async function createDataClient(orgId) {
18418
+ const { config, accessToken } = await requireAuth();
18419
+ const api = new ApiClient({ apiUrl: config.api_url, accessToken });
18420
+ const selected = orgId ?? getDataOrgOverride();
18421
+ if (selected !== void 0 && !UUID_RE2.test(selected)) {
18422
+ throw expected(`Invalid --org: ${JSON.stringify(selected)}. Expected an organization UUID.`);
18423
+ }
18424
+ const org = selected ?? readRepoConfig()?.organization_id;
18425
+ return {
18426
+ async request(method, path36, body) {
18427
+ const envelope = await api.dataRequest(method, path36, body, org);
18428
+ return envelope.data;
18429
+ },
18430
+ async requestRaw(method, path36, body) {
18431
+ const body_ = await api.dataRequest(method, path36, body, org);
18432
+ return body_;
18433
+ },
18434
+ async collectPages(makePath) {
18435
+ const all = [];
18436
+ const seen = /* @__PURE__ */ new Set();
18437
+ let cursor;
18438
+ for (let page = 0; page < MAX_PAGES; page++) {
18439
+ const { data, meta } = await api.dataRequest("GET", makePath(cursor), void 0, org);
18440
+ for (const row of data ?? []) all.push(row);
18441
+ cursor = meta?.has_more ? meta.cursor : void 0;
18442
+ if (cursor === void 0) break;
18443
+ if (seen.has(cursor)) break;
18444
+ seen.add(cursor);
18445
+ }
18446
+ return all;
18447
+ },
18448
+ async upload(v1Path, bytes, contentType, headers) {
18449
+ const envelope = await api.dataUpload(v1Path, bytes, contentType, org, headers);
18450
+ return envelope.data;
18451
+ },
18452
+ download(v1Path) {
18453
+ return api.dataDownload(v1Path, org);
18454
+ },
18455
+ url(v1Path) {
18456
+ return api.dataUrl(v1Path, org);
18457
+ }
18458
+ };
18459
+ }
18460
+ function dataErrorEnvelope(err) {
18461
+ if (!(err instanceof ApiError)) return null;
18462
+ try {
18463
+ const parsed = JSON.parse(err.body);
18464
+ return parsed?.error ?? null;
18465
+ } catch {
18466
+ return null;
18467
+ }
18468
+ }
18469
+ function dataErrorCode(err) {
18470
+ const code = dataErrorEnvelope(err)?.code;
18471
+ return typeof code === "string" && code ? code : null;
18472
+ }
18473
+ function dataErrorDetails(err) {
18474
+ const details = dataErrorEnvelope(err)?.details;
18475
+ return details && typeof details === "object" ? details : void 0;
18476
+ }
18477
+ var MAX_PAGES;
18478
+ var init_client = __esm({
18479
+ "src/data/client.ts"() {
18480
+ "use strict";
18481
+ init_auth();
18482
+ init_api_client();
18483
+ init_repo_config();
18484
+ init_utils();
18485
+ init_expected();
18486
+ init_org_context();
18487
+ MAX_PAGES = 1e3;
18488
+ }
18489
+ });
18490
+
18491
+ // src/lib/base-binding.ts
18492
+ var binding2, getBaseBindingPath, readBaseBinding, writeBaseBinding, clearBaseBinding, autoBindBaseIfUnbound, assertBaseMatchesBinding, assertNoBindingBlocksBaseCreation;
18493
+ var init_base_binding = __esm({
18494
+ "src/lib/base-binding.ts"() {
18495
+ "use strict";
18496
+ init_base_id();
18497
+ init_worktree_binding();
18498
+ binding2 = createWorktreeBinding({
18499
+ filename: "wayai-base-binding",
18500
+ isValidId: isValidBaseId,
18501
+ noun: "base",
18502
+ idLabel: "base id (must be a slug)",
18503
+ unbindCommand: "wayai bases unbind",
18504
+ useCommand: "wayai bases use"
18505
+ });
18506
+ getBaseBindingPath = binding2.getBindingPath;
18507
+ readBaseBinding = binding2.readBinding;
18508
+ writeBaseBinding = binding2.writeBinding;
18509
+ clearBaseBinding = binding2.clearBinding;
18510
+ autoBindBaseIfUnbound = binding2.autoBindIfUnbound;
18511
+ assertBaseMatchesBinding = binding2.assertMatchesBinding;
18512
+ assertNoBindingBlocksBaseCreation = binding2.assertNoBindingBlocksCreation;
18513
+ }
18514
+ });
18515
+
18516
+ // src/data/helpers.ts
18517
+ import { readFileSync as readFileSync16 } from "fs";
18518
+ function pathSegment(id, label = "id") {
18519
+ if (!isValidBaseId(id)) {
18520
+ throw expected(
18521
+ `Invalid ${label}: ${JSON.stringify(id)}. Ids are slugs \u2014 letters, digits, dot, dash and underscore only.`
18522
+ );
18523
+ }
18524
+ return encodeURIComponent(id);
18525
+ }
18526
+ function foreignSegment(value, label = "id") {
18527
+ if (value === "." || value === "..") {
18528
+ throw expected(`Invalid ${label}: ${JSON.stringify(value)} is a path traversal segment.`);
18529
+ }
18530
+ return encodeURIComponent(value);
18531
+ }
18532
+ function pathSegments(value, label = "path") {
18533
+ return value.split("/").map((segment) => foreignSegment(segment, label)).join("/");
18534
+ }
18535
+ function parseData(data, flag) {
18536
+ const prefix = flag ? `${flag}: ` : "";
18537
+ const source = data.startsWith("@") ? data.slice(1) : void 0;
18538
+ let text = data;
18539
+ if (source !== void 0) {
18540
+ try {
18541
+ text = readFileSync16(source, "utf-8");
18542
+ } catch (e) {
18543
+ throw expected(`${prefix}${source}: ${e instanceof Error ? e.message : "could not be read"}`);
18544
+ }
18545
+ }
18546
+ try {
18547
+ return JSON.parse(text);
18548
+ } catch (e) {
18549
+ const where = source !== void 0 ? ` in ${source}` : "";
18550
+ throw expected(`${prefix}invalid JSON${where}: ${e instanceof Error ? e.message : String(e)}`);
18551
+ }
18552
+ }
18553
+ function toolsetMcpUrl(slug) {
18554
+ return `https://data-mcp.wayai.pro/t/${slug}/mcp`;
18555
+ }
18556
+ function globals(cmd) {
18557
+ let namespace = cmd;
18558
+ while (namespace.parent?.parent) namespace = namespace.parent;
18559
+ return namespace.opts();
18560
+ }
18561
+ function withBaseOption(command2) {
18562
+ return command2.option("--base <id>", "Base id (or set WAYAI_BASE)");
18563
+ }
18564
+ function baseOptionHolder(cmd) {
18565
+ for (let c = cmd; c; c = c.parent ?? void 0) {
18566
+ if (c.options.some((o) => o.long === "--base")) return c;
18567
+ }
18568
+ return void 0;
18569
+ }
18570
+ function findBase(cmd) {
18571
+ return baseOptionHolder(cmd)?.opts()?.base;
18572
+ }
18573
+ function requireBase(cmd) {
18574
+ const base = findBase(cmd) ?? process.env.WAYAI_BASE ?? "";
18575
+ if (base) return base;
18576
+ console.error("Error: --base is required (or set WAYAI_BASE)");
18577
+ return process.exit(1);
18578
+ }
18579
+ function outputFormat(cmd) {
18580
+ const opts = globals(cmd);
18581
+ return opts.json || opts.output === "json" ? "json" : "table";
18582
+ }
18583
+ function historyQuery(opts) {
18584
+ const qs = new URLSearchParams();
18585
+ if (opts.limit) qs.set("limit", opts.limit);
18586
+ if (opts.offset) qs.set("offset", opts.offset);
18587
+ if (opts.diff) qs.set("diff", "true");
18588
+ const q = qs.toString();
18589
+ return q ? `?${q}` : "";
18590
+ }
18591
+ function splitList(value) {
18592
+ return value.split(",").map((v) => v.trim()).filter((v) => v.length > 0);
18593
+ }
18594
+ function parseByteCount(flag, value) {
18595
+ const n = Number(value);
18596
+ if (!Number.isInteger(n) || n < 0) {
18597
+ throw expected(`${flag} must be a whole number of bytes (0 = unlimited), not ${JSON.stringify(value)}.`);
18598
+ }
18599
+ return n;
18600
+ }
18601
+ async function readSecret(source, label) {
18602
+ const value = resolveSecretSource(source) === "stdin" ? (await readStdin()).trim() : (await promptSecret(`${label}: `)).trim();
18603
+ if (!value) throw expected(`${label} is required.`);
18604
+ return value;
18605
+ }
18606
+ function isInteractive() {
18607
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY);
18608
+ }
18609
+ function parseDuration(input, flag = "duration") {
18610
+ const match = DURATION_RE.exec(input.trim());
18611
+ const value = Number(match?.[1] ?? 0);
18612
+ const unit = match?.[2];
18613
+ const unitMs = unit ? DURATION_UNIT_MS[unit] : void 0;
18614
+ if (!unitMs || value <= 0) {
18615
+ throw expected(
18616
+ `Invalid ${flag} ${JSON.stringify(input)} \u2014 use <number><unit> with unit s/m/h/d (e.g. 10m, 2h, 30d).`
18617
+ );
18618
+ }
18619
+ return value * unitMs;
18620
+ }
18621
+ var DURATION_RE, DURATION_UNIT_MS;
18622
+ var init_helpers = __esm({
18623
+ "src/data/helpers.ts"() {
18624
+ "use strict";
18625
+ init_base_id();
18626
+ init_expected();
18627
+ init_utils();
18628
+ DURATION_RE = /^(\d+)([smhd])$/;
18629
+ DURATION_UNIT_MS = {
18630
+ s: 1e3,
18631
+ m: 6e4,
18632
+ h: 36e5,
18633
+ d: 864e5
18634
+ };
18635
+ }
18636
+ });
18637
+
18638
+ // src/data/config-as-code/types.ts
18639
+ var ENTITY_KINDS, ENTITY_DIRS, DEPRECATED_ENTITY_DIRS;
18640
+ var init_types2 = __esm({
18641
+ "src/data/config-as-code/types.ts"() {
18642
+ "use strict";
18643
+ ENTITY_KINDS = [
18644
+ "record_types",
18645
+ "relationship_types",
18646
+ "inbound_webhooks",
18647
+ "triggers",
18648
+ "toolsets",
18649
+ "actions",
18650
+ "seeds"
18651
+ ];
18652
+ ENTITY_DIRS = {
18653
+ record_types: "record-types",
18654
+ relationship_types: "relationship-types",
18655
+ inbound_webhooks: "inbound-webhooks",
18656
+ triggers: "triggers",
18657
+ toolsets: "toolsets",
18658
+ actions: "actions",
18659
+ seeds: "seeds"
18660
+ };
18661
+ DEPRECATED_ENTITY_DIRS = ["endpoints", "collections", "tools"];
18662
+ }
18663
+ });
18664
+
18665
+ // src/data/config-as-code/config-writer.ts
18666
+ import * as fs16 from "fs";
18667
+ import * as path19 from "path";
18668
+ import * as yaml8 from "js-yaml";
18669
+ function dump4(value) {
18670
+ return yaml8.dump(value, YAML_DUMP_OPTIONS);
18671
+ }
18672
+ function omitUndefined(obj) {
18673
+ const out = {};
18674
+ for (const [k, v] of Object.entries(obj)) {
18675
+ if (v !== void 0) out[k] = v;
18676
+ }
18677
+ return out;
18678
+ }
18679
+ function stripRecordTypeSources(sources) {
18680
+ if (!Array.isArray(sources)) return void 0;
18681
+ return sources.map((raw) => {
18682
+ const source = raw;
18683
+ const auth = source.auth;
18684
+ if (!auth) return source;
18685
+ const { secret: _secret, ...restAuth } = auth;
18686
+ return { ...source, auth: restAuth };
18687
+ });
18688
+ }
18689
+ function toFileObject(kind, entity) {
18690
+ const out = {};
18691
+ for (const key of ENTITY_FIELD_ORDER[kind]) {
18692
+ const value = kind === "record_types" && key === "sources" ? stripRecordTypeSources(entity.sources) : entity[key];
18693
+ if (value !== void 0) out[key] = value;
18694
+ }
18695
+ return out;
18696
+ }
18697
+ function pruneOrphans(folder, dir, keep, log) {
18698
+ if (!ensureRealSubdirNoSymlink(folder, dir, false)) return;
18699
+ let entries;
18700
+ try {
18701
+ entries = fs16.readdirSync(dir);
18702
+ } catch {
18703
+ return;
18704
+ }
18705
+ for (const file of entries) {
18706
+ if (!file.endsWith(".yaml") || keep.has(file)) continue;
18707
+ const abs = path19.join(dir, file);
18708
+ fs16.rmSync(abs);
18709
+ log.removed.push(path19.relative(folder, abs));
18710
+ }
18711
+ }
18712
+ function metaFileObject(meta) {
18713
+ const out = {};
18714
+ for (const key of META_ORDER) {
18715
+ if (meta[key] !== void 0) out[key] = meta[key];
18716
+ }
18717
+ return out;
18718
+ }
18719
+ function writeBaseFolder(folder, meta, config) {
18720
+ const delta = { changed: [], removed: [] };
18721
+ const parent = path19.dirname(folder);
18722
+ fs16.mkdirSync(parent, { recursive: true });
18723
+ if (!ensureRealSubdirNoSymlink(parent, folder, true)) {
18724
+ throw expected(
18725
+ `Refusing to write ${folder}: the path crosses a symlink. Remove it and pull again.`
18726
+ );
18727
+ }
18728
+ writeFileIfChanged(folder, path19.join(folder, BASE_META_FILE), dump4(metaFileObject(meta)), delta);
18729
+ for (const kind of ENTITY_KINDS) {
18730
+ const dir = path19.join(folder, ENTITY_DIRS[kind]);
18731
+ const entities = config[kind] ?? [];
18732
+ const keep = /* @__PURE__ */ new Set();
18733
+ for (const raw of entities) {
18734
+ const entity = raw;
18735
+ const id = String(entity.id);
18736
+ if (!isValidBaseId(id)) {
18737
+ console.warn(` Warning: skipping ${kind} entity with unusable id ${JSON.stringify(id)}.`);
18738
+ continue;
18739
+ }
18740
+ const file = `${id}.yaml`;
18741
+ keep.add(file);
18742
+ writeFileIfChanged(folder, path19.join(dir, file), dump4(toFileObject(kind, entity)), delta);
18743
+ }
18744
+ pruneOrphans(folder, dir, keep, delta);
18745
+ }
18746
+ for (const deprecated of DEPRECATED_ENTITY_DIRS) {
18747
+ const dir = path19.join(folder, deprecated);
18748
+ if (ensureRealSubdirNoSymlink(folder, dir, false)) {
18749
+ fs16.rmSync(dir, { recursive: true, force: true });
18750
+ }
18751
+ }
18752
+ return delta;
18753
+ }
18754
+ function markProductionMirror(folder, baseId) {
18755
+ const file = path19.join(folder, BASE_META_FILE);
18756
+ try {
18757
+ const body = readFileNoFollow(folder, file)?.toString("utf-8");
18758
+ if (body === void 0 || body.startsWith(MIRROR_MARKER_PREFIX)) return;
18759
+ const banner = `${MIRROR_MARKER_PREFIX} "${baseId}". Edits are ignored; \`wayai push\` refuses it. Edit the linked preview instead.
18760
+ `;
18761
+ writeFileNoFollow(folder, file, Buffer.from(banner + body, "utf-8"));
18762
+ } catch {
18763
+ }
18764
+ }
18765
+ function ensureMirrorIgnored(folder) {
18766
+ try {
18767
+ writeFileNoFollow(folder, path19.join(folder, ".gitignore"), Buffer.from(MIRROR_GITIGNORE, "utf-8"));
18768
+ } catch {
18769
+ }
18770
+ }
18771
+ var ENTITY_FIELD_ORDER, META_ORDER, MIRROR_MARKER_PREFIX, MIRROR_GITIGNORE;
18772
+ var init_config_writer = __esm({
18773
+ "src/data/config-as-code/config-writer.ts"() {
18774
+ "use strict";
18775
+ init_expected();
18776
+ init_yaml_writer();
18777
+ init_fs_safety();
18778
+ init_base_workspace();
18779
+ init_base_id();
18780
+ init_types2();
18781
+ ENTITY_FIELD_ORDER = {
18782
+ record_types: ["id", "name", "description", "icon", "color", "json_schema", "ui", "sources"],
18783
+ relationship_types: [
18784
+ "id",
18785
+ "description",
18786
+ "data_schema",
18787
+ "source_record_types",
18788
+ "target_record_types",
18789
+ "cascade"
18790
+ ],
18791
+ inbound_webhooks: [
18792
+ "id",
18793
+ "name",
18794
+ "record_type_scope",
18795
+ "field_mapping",
18796
+ "source_binding",
18797
+ "ingest_auth",
18798
+ "hydration",
18799
+ "enabled"
18800
+ ],
18801
+ triggers: [
18802
+ "id",
18803
+ "name",
18804
+ "action",
18805
+ "url",
18806
+ "events",
18807
+ "record_type_scope",
18808
+ "filter",
18809
+ "skip_inbound_webhook_writes",
18810
+ "skip_cascade_writes",
18811
+ "enabled"
18812
+ ],
18813
+ toolsets: ["id", "name", "description", "actions", "relationships", "batch", "sql_query"],
18814
+ actions: [
18815
+ "id",
18816
+ "record_type",
18817
+ "operation",
18818
+ "steps",
18819
+ "description",
18820
+ "external_source",
18821
+ "writable_fields",
18822
+ "precondition",
18823
+ "binding",
18824
+ "filterable_fields",
18825
+ "expose_filter",
18826
+ "expose_sort",
18827
+ "default_sort",
18828
+ "expose_limit",
18829
+ "default_limit",
18830
+ "expose_offset",
18831
+ "expose_fields",
18832
+ "default_fields",
18833
+ "agent_minimal",
18834
+ "base_filter"
18835
+ ],
18836
+ seeds: ["id", "description", "records", "relationships", "exclusive_record_types"]
18837
+ };
18838
+ META_ORDER = [
18839
+ "base_id",
18840
+ "origin_base_id",
18841
+ "name",
18842
+ "description",
18843
+ "environment",
18844
+ "integrations",
18845
+ "analytics"
18846
+ ];
18847
+ MIRROR_MARKER_PREFIX = "# Read-only mirror of production base";
18848
+ MIRROR_GITIGNORE = "*\n";
18849
+ }
18850
+ });
18851
+
18852
+ // src/data/config-as-code/api.ts
18853
+ function metaFromRecord(record, fallbackId) {
18854
+ return omitUndefined({
18855
+ base_id: record.id ?? fallbackId,
18856
+ origin_base_id: record.origin_base_id ?? void 0,
18857
+ name: record.name,
18858
+ description: record.description,
18859
+ environment: record.environment,
18860
+ integrations: record.integrations,
18861
+ analytics: record.analytics
18862
+ });
18863
+ }
18864
+ function getBaseRecord(client, id) {
18865
+ return client.request("GET", `/v1/bases/${pathSegment(id, "base id")}`);
18866
+ }
18867
+ function getConfig(client, id) {
18868
+ return client.request("GET", `/v1/${pathSegment(id, "base id")}/config`);
18869
+ }
18870
+ function diffConfig(client, id, local) {
18871
+ return client.request("POST", `/v1/${pathSegment(id, "base id")}/config/diff`, local);
18872
+ }
18873
+ function applyConfig(client, id, local) {
18874
+ return client.request("PUT", `/v1/${pathSegment(id, "base id")}/config`, local);
18875
+ }
18876
+ function createPreview(client, originId, opts) {
18877
+ return client.requestRaw("POST", `/v1/${pathSegment(originId, "origin base id")}/preview`, {
18878
+ name: opts.name,
18879
+ ...opts.description ? { description: opts.description } : {},
18880
+ // The tier is create-only, so this call is the ONLY chance to honor a tier
18881
+ // the folder declares. Omitted when absent so the clone default applies.
18882
+ ...opts.analytics ? { analytics: opts.analytics } : {}
18883
+ });
18884
+ }
18885
+ function deleteEntity(client, baseId, kind, id) {
18886
+ return client.request(
18887
+ "DELETE",
18888
+ `/v1/${pathSegment(baseId, "base id")}/${ENTITY_DIRS[kind]}/${pathSegment(id, `${kind} id`)}`
18889
+ );
18890
+ }
18891
+ var init_api = __esm({
18892
+ "src/data/config-as-code/api.ts"() {
18893
+ "use strict";
18894
+ init_helpers();
18895
+ init_config_writer();
18896
+ init_types2();
18897
+ }
18898
+ });
18899
+
18900
+ // src/data/config-as-code/config-parser.ts
18901
+ import * as fs17 from "fs";
18902
+ import * as path20 from "path";
18903
+ import * as yaml9 from "js-yaml";
18904
+ function readEntityDir(folder, dir) {
18905
+ if (!ensureRealSubdirNoSymlink(folder, dir, false)) {
18906
+ throw expected(`Refusing to read ${dir}: it is a symlink, not a config directory.`);
18907
+ }
18908
+ if (!isDirectory(dir)) return [];
18909
+ const out = [];
18910
+ for (const file of fs17.readdirSync(dir).sort()) {
18911
+ if (!file.endsWith(".yaml")) continue;
18912
+ const abs = path20.join(dir, file);
18913
+ const bytes = readFileNoFollow(folder, abs);
18914
+ if (bytes === null) {
18915
+ throw expected(`Refusing to read ${abs}: it is a symlink, not a config file.`);
18916
+ }
18917
+ let parsed;
18918
+ try {
18919
+ parsed = yaml9.load(bytes.toString("utf-8"));
18920
+ } catch (err) {
18921
+ throw expected(`Failed to parse ${abs}: ${err instanceof Error ? err.message : String(err)}`);
18922
+ }
18923
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
18924
+ throw expected(`${abs} is empty or not a YAML object`);
18925
+ }
18926
+ const entity = parsed;
18927
+ const stem = path20.basename(file, ".yaml");
18928
+ if (entity.id === void 0) entity.id = stem;
18929
+ else if (String(entity.id) !== stem) {
18930
+ throw expected(`${abs}: id "${String(entity.id)}" does not match filename "${stem}.yaml"`);
18931
+ }
18932
+ out.push(entity);
18933
+ }
18934
+ return out;
18935
+ }
18936
+ function parseBaseFolder(folder) {
18937
+ const meta = readBaseMeta(folder);
18938
+ if (!meta) {
18939
+ throw expected(
18940
+ hasBaseMetaFile(folder) ? `${path20.join(folder, BASE_META_FILE)} could not be parsed as a YAML mapping. Fix it, or delete it and pull again.` : `No ${BASE_META_FILE} found in ${folder}`
18941
+ );
18942
+ }
18943
+ const read = (kind) => readEntityDir(folder, path20.join(folder, ENTITY_DIRS[kind]));
18944
+ const config = {
18945
+ record_types: read("record_types"),
18946
+ relationship_types: read("relationship_types"),
18947
+ inbound_webhooks: read("inbound_webhooks"),
18948
+ triggers: read("triggers"),
18949
+ toolsets: read("toolsets"),
18950
+ actions: read("actions"),
18951
+ seeds: read("seeds")
18952
+ };
18953
+ return { meta, config };
18954
+ }
18955
+ var init_config_parser = __esm({
18956
+ "src/data/config-as-code/config-parser.ts"() {
18957
+ "use strict";
18958
+ init_expected();
18959
+ init_layout();
18960
+ init_fs_safety();
18961
+ init_base_workspace();
18962
+ init_types2();
18963
+ }
18964
+ });
18965
+
18966
+ // src/data/config-as-code/diff-format.ts
18967
+ function bucket(diff, kind) {
18968
+ return diff[kind];
18969
+ }
18970
+ function isEmptyBucket(b) {
18971
+ return !b || b.added.length === 0 && b.modified.length === 0 && b.removed.length === 0;
18972
+ }
18973
+ function isDiffEmpty(diff) {
18974
+ return ENTITY_KINDS.every((kind) => isEmptyBucket(bucket(diff, kind)));
18975
+ }
18976
+ function collectRemovals(diff) {
18977
+ const out = [];
18978
+ for (const kind of ENTITY_KINDS) {
18979
+ for (const entity of bucket(diff, kind)?.removed ?? []) out.push({ kind, id: entity.id });
18980
+ }
18981
+ return out;
18982
+ }
18983
+ function countChanges(diff) {
18984
+ let added = 0;
18985
+ let modified = 0;
18986
+ let removed = 0;
18987
+ for (const kind of ENTITY_KINDS) {
18988
+ const b = bucket(diff, kind);
18989
+ if (!b) continue;
18990
+ added += b.added.length;
18991
+ modified += b.modified.length;
18992
+ removed += b.removed.length;
18993
+ }
18994
+ return { added, modified, removed };
18995
+ }
18996
+ function renderDiff(diff) {
18997
+ const lines = [];
18998
+ for (const kind of ENTITY_KINDS) {
18999
+ const b = bucket(diff, kind);
19000
+ if (!b || isEmptyBucket(b)) continue;
19001
+ lines.push(`${BOLD}${LABELS[kind]}s${RESET}`);
19002
+ for (const e of b.added) lines.push(`${GREEN} + ${sanitizeTerminalText(e.id)}${RESET}`);
19003
+ for (const m of b.modified) lines.push(`${YELLOW} ~ ${sanitizeTerminalText(m.after.id)}${RESET}`);
19004
+ for (const e of b.removed) lines.push(`${RED} - ${sanitizeTerminalText(e.id)}${RESET}`);
19005
+ }
19006
+ const { added, modified, removed } = countChanges(diff);
19007
+ lines.push("");
19008
+ lines.push(
19009
+ `${GREEN}${added} added${RESET}, ${YELLOW}${modified} modified${RESET}, ${RED}${removed} removed${RESET}`
19010
+ );
19011
+ if (removed > 0) {
19012
+ lines.push(
19013
+ `${RED} ${removed} entit${removed === 1 ? "y" : "ies"} exist on the base but not in your files \u2014 re-run with --prune to delete (record types cascade to their records).${RESET}`
19014
+ );
19015
+ }
19016
+ return lines.join("\n");
19017
+ }
19018
+ var LABELS, GREEN, YELLOW, RED, BOLD, RESET;
19019
+ var init_diff_format = __esm({
19020
+ "src/data/config-as-code/diff-format.ts"() {
19021
+ "use strict";
19022
+ init_terminal_output();
19023
+ init_types2();
19024
+ LABELS = {
19025
+ record_types: "record type",
19026
+ relationship_types: "relationship type",
19027
+ inbound_webhooks: "inbound webhook",
19028
+ triggers: "trigger",
19029
+ toolsets: "toolset",
19030
+ actions: "action",
19031
+ seeds: "seed"
19032
+ };
19033
+ GREEN = "\x1B[32m";
19034
+ YELLOW = "\x1B[33m";
19035
+ RED = "\x1B[31m";
19036
+ BOLD = "\x1B[1m";
19037
+ RESET = "\x1B[0m";
19038
+ }
19039
+ });
19040
+
19041
+ // src/data/config-as-code/sync.ts
19042
+ var sync_exports = {};
19043
+ __export(sync_exports, {
19044
+ pullBase: () => pullBase,
19045
+ pushBase: () => pushBase
19046
+ });
19047
+ import * as path21 from "path";
19048
+ function parseArgs4(args2) {
19049
+ return {
19050
+ autoConfirm: args2.includes("--yes") || args2.includes("-y"),
19051
+ dryRun: args2.includes("--dry-run"),
19052
+ prune: args2.includes("--prune")
19053
+ };
19054
+ }
19055
+ function requireGitRoot(gitRoot) {
19056
+ if (!gitRoot) throw expected("Not inside a git repository.");
19057
+ return gitRoot;
19058
+ }
19059
+ async function writeProductionMirror(client, basesDir, prodId, record) {
19060
+ if (!isValidBaseId(prodId)) {
19061
+ throw expected(`Refusing to mirror base ${JSON.stringify(prodId)}: not a usable base id.`);
19062
+ }
19063
+ const config = await getConfig(client, prodId);
19064
+ const folder = path21.join(basesDir, prodId);
19065
+ writeBaseFolder(folder, { ...metaFromRecord(record, prodId), environment: "production" }, config);
19066
+ markProductionMirror(folder, prodId);
19067
+ ensureMirrorIgnored(folder);
19068
+ return folder;
19069
+ }
19070
+ async function mirrorLinkedProduction(client, basesDir, originId) {
19071
+ try {
19072
+ const record = await getBaseRecord(client, originId);
19073
+ if (record.environment !== "production") return;
19074
+ const folder = await writeProductionMirror(client, basesDir, originId, record);
19075
+ console.log(`Mirrored production base \u2192 ${folder} (read-only, git-ignored)`);
19076
+ } catch (err) {
19077
+ console.warn(
19078
+ `Warning: could not mirror the production base (${err instanceof Error ? err.message : String(err)}). The preview pull is unaffected.`
19079
+ );
19080
+ }
19081
+ }
19082
+ async function pullBase(gitRootOrNull, selector, args2) {
19083
+ const { autoConfirm } = parseArgs4(args2);
19084
+ const gitRoot = requireGitRoot(gitRootOrNull);
19085
+ const target = resolveBaseTarget(gitRoot, selector);
19086
+ const basesDir = resolveBasesDir(gitRoot);
19087
+ const baseId = targetBaseId(target, selector);
19088
+ if (!baseId) {
19089
+ throw expected(
19090
+ `Could not determine the base id for ${target.folder}. Pass the base id explicitly.`
19091
+ );
19092
+ }
19093
+ const client = await createDataClient();
19094
+ console.log("Fetching base configuration...");
19095
+ const record = await getBaseRecord(client, baseId);
19096
+ if (record.environment === "production") {
19097
+ const folder = await writeProductionMirror(client, basesDir, record.id ?? baseId, record);
19098
+ console.log(`Production base mirrored (read-only) \u2192 ${folder}`);
19099
+ return;
19100
+ }
19101
+ assertBaseMatchesBinding(baseId);
19102
+ if (target.exists && !autoConfirm) {
19103
+ const ok = await confirm(
19104
+ `Overwrite local files in ${path21.relative(gitRoot, target.folder)} with the server config for "${sanitizeTerminalText(baseId)}"?`
19105
+ );
19106
+ if (!ok) {
19107
+ console.log("Cancelled.");
19108
+ return;
19109
+ }
19110
+ }
19111
+ const config = await getConfig(client, baseId);
19112
+ const isFirstPull = !target.exists;
19113
+ const delta = writeBaseFolder(target.folder, metaFromRecord(record, baseId), config);
19114
+ console.log(`Base configuration written to ${target.folder}`);
19115
+ console.log(
19116
+ ` ${ENTITY_KINDS.map((kind) => `${(config[kind] ?? []).length} ${kind}`).join(", ")}`
19117
+ );
19118
+ if (!isFirstPull) printLocalFileChanges(delta);
19119
+ console.log(" Secrets are not written. Manage them with `wayai bases secrets`.");
19120
+ autoBindBaseIfUnbound(baseId);
19121
+ if (record.origin_base_id) {
19122
+ await mirrorLinkedProduction(client, basesDir, record.origin_base_id);
19123
+ }
19124
+ }
19125
+ function printLintWarnings(warnings) {
19126
+ if (!warnings || warnings.length === 0) return;
19127
+ const word = warnings.length === 1 ? "suggestion" : "suggestions";
19128
+ console.error(`
19129
+ ${YELLOW}Tool design \u2014 ${warnings.length} ${word} (advisory, not blocking):${RESET}`);
19130
+ for (const w of warnings) {
19131
+ console.error(
19132
+ ` ${sanitizeTerminalText(w.action)} [${sanitizeTerminalText(w.rule)}]
19133
+ ${sanitizeTerminalText(w.message)}`
19134
+ );
19135
+ }
19136
+ }
19137
+ async function createDeclaredPreview(client, target, parsed, autoConfirm) {
19138
+ const { meta, config } = parsed;
19139
+ if (!meta.origin_base_id) {
19140
+ throw expected(
19141
+ "base.yaml needs a base_id (an existing preview) or an origin_base_id (to create one)."
19142
+ );
19143
+ }
19144
+ const name = meta.name ?? path21.basename(target.folder);
19145
+ assertNoBindingBlocksBaseCreation(name);
19146
+ if (!autoConfirm) {
19147
+ const ok = await confirm(
19148
+ `Create a new preview "${sanitizeTerminalText(name)}" from "${sanitizeTerminalText(meta.origin_base_id)}"?`
19149
+ );
19150
+ if (!ok) {
19151
+ console.log("Cancelled.");
19152
+ return null;
19153
+ }
19154
+ }
19155
+ const record = await createPreview(client, meta.origin_base_id, {
19156
+ name,
19157
+ description: meta.description,
19158
+ analytics: meta.analytics
19159
+ });
19160
+ const id = record.id;
19161
+ writeBaseFolder(target.folder, { ...meta, ...metaFromRecord(record, id) }, config);
19162
+ console.log(`Created preview "${sanitizeTerminalText(id)}".`);
19163
+ printWarnings((record.warnings ?? []).map((w) => sanitizeTerminalText(w.message)));
19164
+ autoBindBaseIfUnbound(id);
19165
+ return id;
19166
+ }
19167
+ async function pushBase(gitRootOrNull, selector, args2) {
19168
+ const { autoConfirm, dryRun, prune } = parseArgs4(args2);
19169
+ const gitRoot = requireGitRoot(gitRootOrNull);
19170
+ const target = resolveBaseTarget(gitRoot, selector);
19171
+ if (!target.exists) {
19172
+ throw expected(
19173
+ `No base.yaml in ${target.folder}. Pull an existing preview, or scaffold a folder with origin_base_id set to create one.`
19174
+ );
19175
+ }
19176
+ const parsed = parseBaseFolder(target.folder);
19177
+ const { meta, config } = parsed;
19178
+ if (isProductionFolder(meta)) {
19179
+ throw expected(
19180
+ `${path21.relative(gitRoot, target.folder)} is a read-only production mirror. Push operates on previews \u2014 edit the linked preview and promote with \`wayai bases promote\`.`
19181
+ );
19182
+ }
19183
+ if (!meta.base_id && dryRun) {
19184
+ console.log(
19185
+ `Dry run \u2014 nothing applied. ${path21.relative(gitRoot, target.folder)} has no base_id yet, so a real push would first create a preview from "${sanitizeTerminalText(meta.origin_base_id ?? "<origin_base_id>")}".`
19186
+ );
19187
+ return;
19188
+ }
19189
+ const client = await createDataClient();
19190
+ let baseId = meta.base_id;
19191
+ if (!baseId) {
19192
+ const created = await createDeclaredPreview(client, target, parsed, autoConfirm);
19193
+ if (!created) return;
19194
+ baseId = created;
19195
+ } else {
19196
+ const record = await getBaseRecord(client, baseId);
19197
+ if (record.environment && record.environment !== "preview") {
19198
+ throw expected(
19199
+ `"${sanitizeTerminalText(baseId)}" is a ${sanitizeTerminalText(record.environment)} base. Push operates on previews \u2014 promote with \`wayai bases promote\`.`
19200
+ );
19201
+ }
19202
+ assertBaseMatchesBinding(baseId);
19203
+ }
19204
+ const diff = await diffConfig(client, baseId, config);
19205
+ printLintWarnings(diff.warnings);
19206
+ if (isDiffEmpty(diff)) {
19207
+ console.log(`No changes \u2014 preview "${sanitizeTerminalText(baseId)}" already matches your files.`);
19208
+ if (!dryRun) autoBindBaseIfUnbound(baseId);
19209
+ return;
19210
+ }
19211
+ console.log(renderDiff(diff));
19212
+ if (dryRun) {
19213
+ console.log("\nDry run \u2014 nothing applied.");
19214
+ return;
19215
+ }
19216
+ if (!autoConfirm) {
19217
+ const ok = await confirm(`
19218
+ Apply these changes to preview "${sanitizeTerminalText(baseId)}"?`);
19219
+ if (!ok) {
19220
+ console.log("Cancelled.");
19221
+ return;
19222
+ }
19223
+ }
19224
+ const result = await applyConfig(client, baseId, config);
19225
+ const secretGroups = [
19226
+ ["trigger", result.new_trigger_secrets],
19227
+ ["inbound webhook", result.new_inbound_webhook_secrets]
19228
+ ];
19229
+ if (secretGroups.some(([, map]) => map && Object.keys(map).length > 0)) {
19230
+ console.log(`
19231
+ ${YELLOW}New secrets (shown once \u2014 save them now):${RESET}`);
19232
+ for (const [kind, map] of secretGroups) {
19233
+ for (const [id, secret] of Object.entries(map ?? {})) {
19234
+ console.log(` ${kind} ${sanitizeTerminalText(id)}: ${secret}`);
19235
+ }
19236
+ }
19237
+ }
19238
+ const removals = collectRemovals(diff);
19239
+ if (removals.length > 0) {
19240
+ const word = removals.length === 1 ? "entity" : "entities";
19241
+ if (!prune) {
19242
+ console.log(
19243
+ `
19244
+ ${RED}${removals.length} ${word} not in your files were left on the base. Re-run with --prune to delete.${RESET}`
19245
+ );
19246
+ } else if (autoConfirm || await confirm(
19247
+ `
19248
+ Delete ${removals.length} server ${word} not in your files? Record types cascade to their records.`
19249
+ )) {
19250
+ for (const removal of removals) {
19251
+ await deleteEntity(client, baseId, removal.kind, removal.id);
19252
+ console.log(` - deleted ${removal.kind} ${sanitizeTerminalText(removal.id)}`);
19253
+ }
19254
+ } else {
19255
+ console.log("Skipped deletions.");
19256
+ }
19257
+ }
19258
+ console.log(`
19259
+ Pushed to preview "${sanitizeTerminalText(baseId)}".`);
19260
+ autoBindBaseIfUnbound(baseId);
19261
+ }
19262
+ var init_sync = __esm({
19263
+ "src/data/config-as-code/sync.ts"() {
19264
+ "use strict";
19265
+ init_client();
19266
+ init_utils();
19267
+ init_expected();
19268
+ init_layout();
19269
+ init_terminal_output();
19270
+ init_base_id();
19271
+ init_push();
19272
+ init_base_binding();
19273
+ init_api();
19274
+ init_config_parser();
19275
+ init_config_writer();
19276
+ init_diff_format();
19277
+ init_base_workspace();
19278
+ init_types2();
19279
+ }
19280
+ });
19281
+
19282
+ // src/commands/push.ts
19283
+ var push_exports = {};
19284
+ __export(push_exports, {
19285
+ autoRenameAgentFiles: () => autoRenameAgentFiles,
19286
+ createAndPushNewHub: () => createAndPushNewHub,
19287
+ printErrors: () => printErrors,
19288
+ printLocalFileChanges: () => printLocalFileChanges,
19289
+ printSyncResult: () => printSyncResult,
19290
+ printWarnings: () => printWarnings,
19291
+ pushCommand: () => pushCommand,
19292
+ reportUnresolvedPushTarget: () => reportUnresolvedPushTarget,
19293
+ selectExistingHub: () => selectExistingHub,
19294
+ shouldWarnIgnoredPreviewLabel: () => shouldWarnIgnoredPreviewLabel,
19295
+ syncAfterPush: () => syncAfterPush
19296
+ });
19297
+ import * as fs18 from "fs";
19298
+ import * as path22 from "path";
19299
+ import * as yaml10 from "js-yaml";
19300
+ function parseArgs5(args2) {
19301
+ let autoConfirm = false;
19302
+ let label;
19303
+ for (let i = 0; i < args2.length; i++) {
19304
+ const arg = args2[i];
19305
+ if (arg === "--yes" || arg === "-y") {
19306
+ autoConfirm = true;
19307
+ } else if (arg === "--label" && args2[i + 1]) {
19308
+ label = args2[++i];
19309
+ }
19310
+ }
19311
+ return { autoConfirm, label };
19312
+ }
19313
+ function shouldWarnIgnoredPreviewLabel(localLabel, serverLabel) {
19314
+ return Boolean(localLabel) && serverLabel !== void 0 && localLabel !== serverLabel;
19315
+ }
19316
+ function printSyncResult(result) {
19317
+ const applyErrors = result.apply_errors ?? result.errors;
19318
+ if (applyErrors && applyErrors.length > 0) {
19319
+ printErrors(applyErrors);
19320
+ throw expected(`Sync failed with ${applyErrors.length} error(s). No completion was reported; inspect the errors above.`);
19321
+ }
19322
+ console.log(`
19323
+ Sync complete. Preview hub: ${result.preview_hub_id}`);
19324
+ const c = result.changes;
19325
+ const parts = [];
19326
+ if (c.hub_updated) parts.push("hub updated");
19327
+ if (c.connections_created > 0) parts.push(`${c.connections_created} connection(s) created`);
19328
+ if (c.connections_updated > 0) parts.push(`${c.connections_updated} connection(s) updated`);
19329
+ if (c.connections_deleted > 0) parts.push(`${c.connections_deleted} connection(s) deleted`);
19330
+ if (c.agents_created > 0) parts.push(`${c.agents_created} agent(s) created`);
19331
+ if (c.agents_updated > 0) parts.push(`${c.agents_updated} agent(s) updated`);
19332
+ if (c.agents_deleted > 0) parts.push(`${c.agents_deleted} agent(s) deleted`);
19333
+ if (c.tools_created > 0) parts.push(`${c.tools_created} tool(s) created`);
19334
+ if (c.tools_updated > 0) parts.push(`${c.tools_updated} tool(s) updated`);
19335
+ if (c.tools_deleted > 0) parts.push(`${c.tools_deleted} tool(s) deleted`);
19336
+ if (c.states_created > 0) parts.push(`${c.states_created} state(s) created`);
19337
+ if (c.states_updated > 0) parts.push(`${c.states_updated} state(s) updated`);
19338
+ if (c.states_deleted > 0) parts.push(`${c.states_deleted} state(s) deleted`);
19339
+ if (c.evals_created > 0) parts.push(`${c.evals_created} eval(s) created`);
19340
+ if (c.evals_updated > 0) parts.push(`${c.evals_updated} eval(s) updated`);
19341
+ if (c.evals_deleted > 0) parts.push(`${c.evals_deleted} eval(s) deleted`);
19342
+ if (c.journeys_created > 0) parts.push(`${c.journeys_created} journey(s) created`);
19343
+ if (c.journeys_updated > 0) parts.push(`${c.journeys_updated} journey(s) updated`);
19344
+ if (c.journeys_deleted > 0) parts.push(`${c.journeys_deleted} journey(s) deleted`);
19345
+ if (c.teams_created > 0) parts.push(`${c.teams_created} team(s) created`);
19346
+ if (c.teams_updated > 0) parts.push(`${c.teams_updated} team(s) updated`);
19347
+ if (c.teams_deleted > 0) parts.push(`${c.teams_deleted} team(s) deleted`);
19348
+ if (c.resources_created > 0) parts.push(`${c.resources_created} resource(s) created`);
19349
+ if (c.resources_updated > 0) parts.push(`${c.resources_updated} resource(s) updated`);
19350
+ if (c.resources_deleted > 0) parts.push(`${c.resources_deleted} resource(s) deleted`);
19351
+ if (c.resource_files_uploaded > 0) parts.push(`${c.resource_files_uploaded} resource file(s) uploaded`);
19352
+ if (c.resource_files_deleted > 0) parts.push(`${c.resource_files_deleted} resource file(s) deleted`);
19353
+ if (c.resource_links_created > 0) parts.push(`${c.resource_links_created} resource link(s) created`);
19354
+ if (c.resource_links_updated > 0) parts.push(`${c.resource_links_updated} resource link(s) updated`);
19355
+ if (c.resource_links_deleted > 0) parts.push(`${c.resource_links_deleted} resource link(s) deleted`);
19356
+ if (c.outbound_contacts_created > 0) parts.push(`${c.outbound_contacts_created} outbound contact(s) created`);
19357
+ if (c.outbound_contacts_updated > 0) parts.push(`${c.outbound_contacts_updated} outbound contact(s) updated`);
19358
+ if (c.outbound_contacts_deleted > 0) parts.push(`${c.outbound_contacts_deleted} outbound contact(s) deleted`);
19359
+ if (c.outbound_lists_created > 0) parts.push(`${c.outbound_lists_created} outbound list(s) created`);
19360
+ if (c.outbound_lists_updated > 0) parts.push(`${c.outbound_lists_updated} outbound list(s) updated`);
19361
+ if (c.outbound_lists_deleted > 0) parts.push(`${c.outbound_lists_deleted} outbound list(s) deleted`);
19362
+ if (c.outbound_schedules_created > 0) parts.push(`${c.outbound_schedules_created} outbound schedule(s) created`);
19363
+ if (c.outbound_schedules_updated > 0) parts.push(`${c.outbound_schedules_updated} outbound schedule(s) updated`);
19364
+ if (c.outbound_schedules_deleted > 0) parts.push(`${c.outbound_schedules_deleted} outbound schedule(s) deleted`);
19365
+ if (parts.length > 0) {
19366
+ console.log(`Changes: ${parts.join(", ")}`);
19367
+ }
19368
+ if (result.warnings && result.warnings.length > 0) {
19369
+ printWarnings(result.warnings.map((w) => w.message));
19370
+ }
19371
+ }
19372
+ function printWarnings(warnings) {
19373
+ if (warnings.length === 0) return;
19374
+ console.log(`
19375
+ \x1B[33mWarnings (${warnings.length}):\x1B[0m`);
19376
+ for (const w of warnings) {
19377
+ console.log(` \x1B[33m! ${w}\x1B[0m`);
19378
+ }
19379
+ }
19380
+ function printErrors(errors) {
19381
+ if (errors.length === 0) return;
19382
+ console.error(`
19383
+ \x1B[31mErrors (${errors.length}):\x1B[0m`);
19384
+ for (const error of errors) {
19385
+ const message = typeof error === "string" ? error : error.message;
19386
+ console.error(` \x1B[31m! ${message}\x1B[0m`);
19387
+ }
19388
+ }
19389
+ function printLocalFileChanges(delta) {
19390
+ if (delta.changed.length === 0 && delta.removed.length === 0) {
19391
+ console.log("Local files already in sync.");
19392
+ return;
19393
+ }
19394
+ console.log("Local files updated from server:");
19395
+ const emit = (paths, sigil) => {
19396
+ const sorted = [...paths].sort();
19397
+ for (const p of sorted.slice(0, LOCAL_CHANGE_LIST_CAP)) console.log(` ${sigil} ${p}`);
19398
+ if (sorted.length > LOCAL_CHANGE_LIST_CAP) {
19399
+ console.log(` \u2026and ${sorted.length - LOCAL_CHANGE_LIST_CAP} more ${sigil === "-" ? "removed" : "changed"}`);
19400
+ }
19401
+ };
19402
+ emit(delta.removed, "-");
19403
+ emit(delta.changed, "~");
19404
+ }
19405
+ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, remoteConfig) {
19406
+ const agentsDir = path22.join(hubFolder, "agents");
19407
+ let agentsWithIds = [];
19408
+ if (fs18.existsSync(agentsDir)) {
19409
+ const yamlFiles = fs18.readdirSync(agentsDir).filter((f) => f.endsWith(".yaml"));
19410
+ for (const file of yamlFiles) {
19411
+ try {
19412
+ const content = fs18.readFileSync(path22.join(agentsDir, file), "utf-8");
19413
+ const agent = yaml10.load(content);
19414
+ if (agent?.id && agent.name) {
19415
+ agentsWithIds.push({ id: agent.id, name: agent.name });
19416
+ }
19417
+ } catch {
19418
+ console.warn(` Warning: could not parse agents/${file}, skipping`);
19419
+ }
19420
+ }
19421
+ }
19422
+ if (agentsWithIds.length === 0) {
19423
+ const yamlPath = resolveHubYamlPath(hubFolder);
19424
+ if (!yamlPath) return;
19425
+ const yamlContent = fs18.readFileSync(yamlPath, "utf-8");
19426
+ const config = yaml10.load(yamlContent);
19427
+ agentsWithIds = (config.agents || []).filter((a) => !!a.id && !!a.name);
19428
+ }
19429
+ if (agentsWithIds.length === 0) return;
19430
+ console.log("Checking for agent renames...");
19431
+ let remote = remoteConfig;
19432
+ if (!remote) {
19433
+ try {
19434
+ remote = await client.pull(hubId, organizationId);
19435
+ } catch (err) {
19436
+ console.warn(` Warning: could not fetch remote state for auto-rename (${err instanceof Error ? err.message : String(err)}). File renames skipped.`);
19437
+ return;
19438
+ }
19439
+ }
19440
+ const remoteAgentNames = /* @__PURE__ */ new Map();
19441
+ for (const agent of remote.agents || []) {
19442
+ if (agent.id) {
19443
+ remoteAgentNames.set(agent.id, agent.name);
19444
+ }
19445
+ }
19446
+ const renames = [];
19447
+ for (const agent of agentsWithIds) {
19448
+ const remoteName = remoteAgentNames.get(agent.id);
19449
+ if (!remoteName || remoteName === agent.name) continue;
19450
+ const oldSlug = slugify(remoteName);
19451
+ const newSlug = slugify(agent.name);
19452
+ if (oldSlug !== newSlug) {
19453
+ renames.push({ oldSlug, newSlug });
19454
+ }
19455
+ }
19456
+ if (renames.length === 0) return;
19457
+ if (!fs18.existsSync(agentsDir)) return;
19458
+ for (const file of fs18.readdirSync(agentsDir)) {
19459
+ if (file.startsWith("__rename_temp_") && (file.endsWith(".md") || file.endsWith(".yaml"))) {
19460
+ console.warn(` Warning: removing orphaned temp file agents/${file}`);
19461
+ fs18.unlinkSync(path22.join(agentsDir, file));
19462
+ }
19463
+ }
19464
+ const renameFileIfExists = (dir, oldName, newName) => {
19465
+ const oldPath = path22.join(dir, oldName);
19466
+ const newPath = path22.join(dir, newName);
19467
+ if (!fs18.existsSync(oldPath)) return false;
19468
+ fs18.renameSync(oldPath, newPath);
19469
+ return true;
19470
+ };
19471
+ const oldSlugs = new Set(renames.map((r) => r.oldSlug));
19472
+ const newSlugs = new Set(renames.map((r) => r.newSlug));
19473
+ const hasConflicts = renames.some((r) => oldSlugs.has(r.newSlug)) || newSlugs.size !== renames.length;
19474
+ const completedRenames = [];
18250
19475
  const extensions = [".yaml", ".md"];
18251
19476
  if (hasConflicts) {
18252
19477
  const tempRenames = [];
@@ -18273,9 +19498,9 @@ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, re
18273
19498
  }
18274
19499
  } else {
18275
19500
  for (const { oldSlug, newSlug } of renames) {
18276
- const hasOldFile = extensions.some((ext) => fs14.existsSync(path17.join(agentsDir, `${oldSlug}${ext}`)));
19501
+ const hasOldFile = extensions.some((ext) => fs18.existsSync(path22.join(agentsDir, `${oldSlug}${ext}`)));
18277
19502
  if (!hasOldFile) continue;
18278
- const hasNewFile = extensions.some((ext) => fs14.existsSync(path17.join(agentsDir, `${newSlug}${ext}`)));
19503
+ const hasNewFile = extensions.some((ext) => fs18.existsSync(path22.join(agentsDir, `${newSlug}${ext}`)));
18279
19504
  if (hasNewFile) {
18280
19505
  console.warn(` Warning: skipping rename agents/${oldSlug}.* \u2192 agents/${newSlug}.* (target already exists)`);
18281
19506
  continue;
@@ -18290,7 +19515,7 @@ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, re
18290
19515
  if (completedRenames.length === 0) return;
18291
19516
  const mainYamlPath = resolveHubYamlPath(hubFolder);
18292
19517
  if (mainYamlPath) {
18293
- const mainYamlContent = fs14.readFileSync(mainYamlPath, "utf-8");
19518
+ const mainYamlContent = fs18.readFileSync(mainYamlPath, "utf-8");
18294
19519
  const substitutionMap = /* @__PURE__ */ new Map();
18295
19520
  for (const { oldSlug, newSlug } of completedRenames) {
18296
19521
  substitutionMap.set(`agents/${oldSlug}.md`, `agents/${newSlug}.md`);
@@ -18301,8 +19526,8 @@ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, re
18301
19526
  (_match, prefix, pathMatch) => `${prefix}${substitutionMap.get(pathMatch) ?? pathMatch}`
18302
19527
  );
18303
19528
  if (updatedYaml !== mainYamlContent) {
18304
- fs14.writeFileSync(mainYamlPath, updatedYaml, "utf-8");
18305
- console.log(` Updated instructions paths in ${path17.basename(mainYamlPath)}`);
19529
+ fs18.writeFileSync(mainYamlPath, updatedYaml, "utf-8");
19530
+ console.log(` Updated instructions paths in ${path22.basename(mainYamlPath)}`);
18306
19531
  }
18307
19532
  }
18308
19533
  }
@@ -18370,7 +19595,7 @@ async function pushSingleHub(client, hubId, hubFolder, autoConfirm, organization
18370
19595
  function selectExistingHub(workspaceDir, allHubs, selector, wsLabel) {
18371
19596
  if (selector) {
18372
19597
  const match = allHubs.find(
18373
- (h) => h.hubId === selector || path17.basename(h.hubFolder) === selector
19598
+ (h) => h.hubId === selector || path22.basename(h.hubFolder) === selector
18374
19599
  );
18375
19600
  if (!match) {
18376
19601
  console.error(`No hub matching --hub ${selector} found in ${wsLabel}/.`);
@@ -18413,7 +19638,7 @@ New hub: "${newHub.hubName}" (${hubType})`);
18413
19638
  process.exit(1);
18414
19639
  }
18415
19640
  console.log(`Hub created: ${createdHub.hub_name} (${hubId})`);
18416
- const content = fs14.readFileSync(hubYamlPath, "utf-8");
19641
+ const content = fs18.readFileSync(hubYamlPath, "utf-8");
18417
19642
  const hasVersion = content.match(/^version:\s/m);
18418
19643
  let updated;
18419
19644
  if (hasVersion) {
@@ -18429,7 +19654,7 @@ hub_id: "${hubId}"
18429
19654
  hub_environment: preview
18430
19655
  ${content}`;
18431
19656
  }
18432
- fs14.writeFileSync(hubYamlPath, updated, "utf-8");
19657
+ fs18.writeFileSync(hubYamlPath, updated, "utf-8");
18433
19658
  autoBindIfUnbound(hubId);
18434
19659
  await pushSingleHub(client, hubId, newHub.hubFolder, opts.autoConfirm, opts.organizationId, { skipAgentRename: true });
18435
19660
  }
@@ -18438,7 +19663,7 @@ function reportUnresolvedPushTarget(reason, existingHubs, newHubs, selector, wsL
18438
19663
  if (existingHubs.length > 0) {
18439
19664
  console.error(`No pushable hub found in ${wsLabel}/ \u2014 only read-only production mirror folder(s). Edit the linked preview hub, pull one, or create a new hub with \`wayai create\`:`);
18440
19665
  for (const h of existingHubs) {
18441
- console.error(` ${path17.basename(h.hubFolder)} (${h.hubId}, production mirror)`);
19666
+ console.error(` ${path22.basename(h.hubFolder)} (${h.hubId}, production mirror)`);
18442
19667
  }
18443
19668
  } else {
18444
19669
  console.error(`No hub folders found. Create hub files in ${wsLabel}/<hub>/hub.yaml with \`hub: { name: ... }\` and run \`wayai push\` (or \`wayai create\`).`);
@@ -18446,34 +19671,41 @@ function reportUnresolvedPushTarget(reason, existingHubs, newHubs, selector, wsL
18446
19671
  process.exit(1);
18447
19672
  }
18448
19673
  if (reason === "selector_miss") {
18449
- console.error(`No hub matching --hub ${selector} found in ${wsLabel}/. Available:`);
19674
+ console.error(`No hub matching "${selector}" found in ${wsLabel}/. Available:`);
18450
19675
  } else {
18451
19676
  console.error(`Multiple hub folders found in ${wsLabel}/. Pass --hub <uuid|folder-name> to choose, or run from inside a hub folder:`);
18452
19677
  }
18453
19678
  for (const h of existingHubs) {
18454
- console.error(` ${path17.basename(h.hubFolder)} (${h.hubId})`);
19679
+ console.error(` ${path22.basename(h.hubFolder)} (${h.hubId})`);
18455
19680
  }
18456
19681
  for (const h of newHubs) {
18457
- console.error(` ${path17.basename(h.hubFolder)} (new \u2014 "${h.hubName}")`);
19682
+ console.error(` ${path22.basename(h.hubFolder)} (new \u2014 "${h.hubName}")`);
18458
19683
  }
18459
19684
  process.exit(1);
18460
19685
  }
18461
19686
  async function pushCommand(args2) {
18462
- const { autoConfirm, hubSelector, label } = parseArgs4(args2);
19687
+ const gitRoot = findGitRoot();
19688
+ const route = requireSubtree("push", args2, gitRoot);
19689
+ if (gitRoot) warnLayoutOnce(gitRoot);
19690
+ if (route.subtree === "bases") {
19691
+ const { pushBase: pushBase2 } = await Promise.resolve().then(() => (init_sync(), sync_exports));
19692
+ await pushBase2(gitRoot, route.selector, args2);
19693
+ return;
19694
+ }
19695
+ const { autoConfirm, label } = parseArgs5(args2);
19696
+ const hubSelector = route.selector;
18463
19697
  const repoConfig = requireRepoConfig();
18464
19698
  const { organization_id: organizationId } = repoConfig;
18465
19699
  const { config, accessToken } = await requireAuth();
18466
19700
  const client = new ApiClient({ apiUrl: config.api_url, accessToken });
18467
19701
  const workspaceDir = resolveWorkspaceDir();
18468
- const gitRoot = findGitRoot();
18469
19702
  const wsLabel = hubsDirLabel(gitRoot);
18470
- if (gitRoot) warnLayoutOnce(gitRoot);
18471
19703
  if (gitRoot) {
18472
19704
  for (const file of ensureWorkspaceFiles(gitRoot)) {
18473
19705
  console.error(`Created ${file}`);
18474
19706
  }
18475
19707
  }
18476
- if (!fs14.existsSync(workspaceDir)) {
19708
+ if (!fs18.existsSync(workspaceDir)) {
18477
19709
  console.error(`No ${wsLabel}/ directory found. Run \`wayai pull\` first or create hub files in ${wsLabel}/<hub>/hub.yaml.`);
18478
19710
  process.exit(1);
18479
19711
  }
@@ -18492,8 +19724,8 @@ async function pushCommand(args2) {
18492
19724
  if (label) {
18493
19725
  console.warn("Note: --label is only used when creating a new hub. To change an existing hub's label, use `wayai relabel`.");
18494
19726
  }
18495
- console.log(`Target hub: ${path17.basename(existing.hubFolder)} (${existing.hubId})`);
18496
- assertHubMatchesBinding(existing.hubId, path17.basename(existing.hubFolder));
19727
+ console.log(`Target hub: ${path22.basename(existing.hubFolder)} (${existing.hubId})`);
19728
+ assertHubMatchesBinding(existing.hubId, path22.basename(existing.hubFolder));
18497
19729
  await pushSingleHub(client, existing.hubId, existing.hubFolder, autoConfirm, organizationId);
18498
19730
  return;
18499
19731
  }
@@ -18517,6 +19749,7 @@ var init_push = __esm({
18517
19749
  init_workspace_files();
18518
19750
  init_repo_config();
18519
19751
  init_hub_binding();
19752
+ init_subtree_routing();
18520
19753
  LOCAL_CHANGE_LIST_CAP = 20;
18521
19754
  }
18522
19755
  });
@@ -18527,33 +19760,23 @@ __export(pull_exports, {
18527
19760
  connectionsEqual: () => connectionsEqual,
18528
19761
  pullCommand: () => pullCommand,
18529
19762
  resolveHubTarget: () => resolveHubTarget,
18530
- writeProductionMirror: () => writeProductionMirror
19763
+ writeProductionMirror: () => writeProductionMirror2
18531
19764
  });
18532
- import * as fs15 from "fs";
18533
- import * as path18 from "path";
18534
- function parseArgs5(args2) {
18535
- let autoConfirm = false;
18536
- let hubSelector;
18537
- for (let i = 0; i < args2.length; i++) {
18538
- const arg = args2[i];
18539
- if (arg === "--yes" || arg === "-y") {
18540
- autoConfirm = true;
18541
- } else if (arg === "--hub" && args2[i + 1]) {
18542
- hubSelector = args2[++i];
18543
- }
18544
- }
18545
- return { autoConfirm, hubSelector };
19765
+ import * as fs19 from "fs";
19766
+ import * as path23 from "path";
19767
+ function parseArgs6(args2) {
19768
+ return { autoConfirm: args2.includes("--yes") || args2.includes("-y") };
18546
19769
  }
18547
19770
  function resolveHubTarget(workspaceDir, selector) {
18548
19771
  const wsLabel = hubsDirLabel(findGitRoot());
18549
19772
  const allHubs = scanWorkspaceHubs(workspaceDir);
18550
19773
  if (selector) {
18551
19774
  const match = allHubs.find(
18552
- (h) => h.hubId === selector || path18.basename(h.hubFolder) === selector
19775
+ (h) => h.hubId === selector || path23.basename(h.hubFolder) === selector
18553
19776
  );
18554
19777
  if (match) return { hubId: match.hubId, hubFolder: match.hubFolder };
18555
19778
  if (UUID_RE2.test(selector)) return { hubId: selector, hubFolder: null };
18556
- console.error(`No hub matching --hub ${selector} found in ${wsLabel}/. Pass a UUID for first-time pulls.`);
19779
+ console.error(`No hub matching "${selector}" found in ${wsLabel}/. Pass a UUID for first-time pulls.`);
18557
19780
  process.exit(1);
18558
19781
  }
18559
19782
  const enclosing = findEnclosingHubFolder(workspaceDir);
@@ -18566,19 +19789,26 @@ function resolveHubTarget(workspaceDir, selector) {
18566
19789
  }
18567
19790
  console.error(`Multiple hubs found in ${wsLabel}/. Pass --hub <uuid|folder-name> to choose, or run from inside a hub folder:`);
18568
19791
  for (const h of previewHubs) {
18569
- console.error(` ${path18.basename(h.hubFolder)} (${h.hubId})`);
19792
+ console.error(` ${path23.basename(h.hubFolder)} (${h.hubId})`);
18570
19793
  }
18571
19794
  process.exit(1);
18572
19795
  }
18573
19796
  async function pullCommand(args2) {
18574
- const { autoConfirm, hubSelector } = parseArgs5(args2);
19797
+ const gitRoot = findGitRoot();
19798
+ const route = requireSubtree("pull", args2, gitRoot);
19799
+ if (gitRoot) warnLayoutOnce(gitRoot);
19800
+ if (route.subtree === "bases") {
19801
+ const { pullBase: pullBase2 } = await Promise.resolve().then(() => (init_sync(), sync_exports));
19802
+ await pullBase2(gitRoot, route.selector, args2);
19803
+ return;
19804
+ }
19805
+ const { autoConfirm } = parseArgs6(args2);
19806
+ const hubSelector = route.selector;
18575
19807
  const repoConfig = requireRepoConfig();
18576
19808
  const { organization_id: organizationId } = repoConfig;
18577
19809
  const { config, accessToken } = await requireAuth();
18578
19810
  const client = new ApiClient({ apiUrl: config.api_url, accessToken });
18579
19811
  const workspaceDir = resolveWorkspaceDir();
18580
- const gitRoot = findGitRoot();
18581
- if (gitRoot) warnLayoutOnce(gitRoot);
18582
19812
  if (gitRoot) {
18583
19813
  for (const file of ensureWorkspaceFiles(gitRoot)) {
18584
19814
  console.error(`Created ${file}`);
@@ -18588,7 +19818,7 @@ async function pullCommand(args2) {
18588
19818
  console.log("Fetching hub configuration...");
18589
19819
  const payload = await client.pull(hubId, organizationId);
18590
19820
  if (payload.hub_environment === "production") {
18591
- const folder = await writeProductionMirror(workspaceDir, payload);
19821
+ const folder = await writeProductionMirror2(workspaceDir, payload);
18592
19822
  console.log(`Production hub mirrored (read-only) \u2192 ${folder}`);
18593
19823
  return;
18594
19824
  }
@@ -18604,7 +19834,7 @@ async function pullCommand(args2) {
18604
19834
  payload.preview_label,
18605
19835
  payload.branch_name
18606
19836
  );
18607
- fs15.mkdirSync(path18.dirname(hubFolder), { recursive: true });
19837
+ fs19.mkdirSync(path23.dirname(hubFolder), { recursive: true });
18608
19838
  console.log("Writing hub configuration...");
18609
19839
  await materializeHubFolder(hubFolder, payload);
18610
19840
  const finalFolder = autoRenameHubFolder(hubFolder, payload.hub.name, payload.hub_environment, payload.hub_id, payload.preview_label, payload.branch_name);
@@ -18653,34 +19883,34 @@ async function pullCommand(args2) {
18653
19883
  }
18654
19884
  if (wroteFiles) autoBindIfUnbound(hubId);
18655
19885
  if (payload.production_hub_id) {
18656
- await mirrorLinkedProduction(client, workspaceDir, payload.production_hub_id, organizationId);
19886
+ await mirrorLinkedProduction2(client, workspaceDir, payload.production_hub_id, organizationId);
18657
19887
  }
18658
19888
  }
18659
- async function writeProductionMirror(workspaceDir, prodPayload) {
19889
+ async function writeProductionMirror2(workspaceDir, prodPayload) {
18660
19890
  const folder = resolveHubFolder(workspaceDir, prodPayload.hub_id, prodPayload.hub.name, "production", null, null);
18661
- fs15.mkdirSync(path18.dirname(folder), { recursive: true });
19891
+ fs19.mkdirSync(path23.dirname(folder), { recursive: true });
18662
19892
  await materializeHubFolder(folder, prodPayload, { seedAgentContext: false });
18663
19893
  const finalFolder = autoRenameHubFolder(folder, prodPayload.hub.name, "production", prodPayload.hub_id, null, null);
18664
19894
  prependMirrorMarker(finalFolder, prodPayload.hub_id);
18665
19895
  return finalFolder;
18666
19896
  }
18667
- async function mirrorLinkedProduction(client, workspaceDir, productionHubId, organizationId) {
19897
+ async function mirrorLinkedProduction2(client, workspaceDir, productionHubId, organizationId) {
18668
19898
  try {
18669
19899
  const prodPayload = await client.pull(productionHubId, organizationId);
18670
- const folder = await writeProductionMirror(workspaceDir, prodPayload);
19900
+ const folder = await writeProductionMirror2(workspaceDir, prodPayload);
18671
19901
  console.log(`Mirrored production hub \u2192 ${folder} (read-only)`);
18672
19902
  } catch (err) {
18673
19903
  console.warn(`Warning: could not mirror production hub (${err instanceof Error ? err.message : String(err)}). Preview pull is unaffected.`);
18674
19904
  }
18675
19905
  }
18676
19906
  function prependMirrorMarker(hubFolder, productionHubId) {
18677
- const hubYaml = path18.join(hubFolder, "hub.yaml");
19907
+ const hubYaml = path23.join(hubFolder, "hub.yaml");
18678
19908
  try {
18679
- const content = fs15.readFileSync(hubYaml, "utf-8");
18680
- if (content.startsWith(MIRROR_MARKER_PREFIX)) return;
18681
- const marker = `${MIRROR_MARKER_PREFIX} ${productionHubId}. Edits are ignored; push is blocked. Edit the linked preview hub instead.
19909
+ const content = fs19.readFileSync(hubYaml, "utf-8");
19910
+ if (content.startsWith(MIRROR_MARKER_PREFIX2)) return;
19911
+ const marker = `${MIRROR_MARKER_PREFIX2} ${productionHubId}. Edits are ignored; push is blocked. Edit the linked preview hub instead.
18682
19912
  `;
18683
- fs15.writeFileSync(hubYaml, marker + content, "utf-8");
19913
+ fs19.writeFileSync(hubYaml, marker + content, "utf-8");
18684
19914
  } catch {
18685
19915
  }
18686
19916
  }
@@ -18697,7 +19927,7 @@ function connectionsEqual(a, b) {
18697
19927
  }
18698
19928
  return true;
18699
19929
  }
18700
- var MIRROR_MARKER_PREFIX;
19930
+ var MIRROR_MARKER_PREFIX2;
18701
19931
  var init_pull = __esm({
18702
19932
  "src/commands/pull.ts"() {
18703
19933
  "use strict";
@@ -18714,7 +19944,8 @@ var init_pull = __esm({
18714
19944
  init_workspace_files();
18715
19945
  init_repo_config();
18716
19946
  init_hub_binding();
18717
- MIRROR_MARKER_PREFIX = "# Read-only mirror of production hub";
19947
+ init_subtree_routing();
19948
+ MIRROR_MARKER_PREFIX2 = "# Read-only mirror of production hub";
18718
19949
  }
18719
19950
  });
18720
19951
 
@@ -18723,9 +19954,9 @@ var create_exports = {};
18723
19954
  __export(create_exports, {
18724
19955
  createCommand: () => createCommand
18725
19956
  });
18726
- import * as path19 from "path";
18727
- import * as fs16 from "fs";
18728
- function parseArgs6(args2) {
19957
+ import * as path24 from "path";
19958
+ import * as fs20 from "fs";
19959
+ function parseArgs7(args2) {
18729
19960
  let autoConfirm = false;
18730
19961
  let folderSelector;
18731
19962
  let label;
@@ -18742,7 +19973,7 @@ function parseArgs6(args2) {
18742
19973
  return { autoConfirm, folderSelector, label };
18743
19974
  }
18744
19975
  async function createCommand(args2) {
18745
- const { autoConfirm, folderSelector, label } = parseArgs6(args2);
19976
+ const { autoConfirm, folderSelector, label } = parseArgs7(args2);
18746
19977
  const repoConfig = requireRepoConfig();
18747
19978
  const { organization_id: organizationId } = repoConfig;
18748
19979
  const { config, accessToken } = await requireAuth();
@@ -18751,7 +19982,7 @@ async function createCommand(args2) {
18751
19982
  const gitRoot = findGitRoot();
18752
19983
  const wsLabel = hubsDirLabel(gitRoot);
18753
19984
  if (gitRoot) warnLayoutOnce(gitRoot);
18754
- if (!fs16.existsSync(workspaceDir)) {
19985
+ if (!fs20.existsSync(workspaceDir)) {
18755
19986
  console.error(`No ${wsLabel}/ directory found. Create hub files in ${wsLabel}/<hub>/hub.yaml with \`hub: { name: ... }\` first.`);
18756
19987
  process.exit(1);
18757
19988
  }
@@ -18760,7 +19991,7 @@ async function createCommand(args2) {
18760
19991
  const resolution = resolveNewHubForCreate(workspaceDir, existingHubs, newHubs, folderSelector);
18761
19992
  if (!resolution.ok) {
18762
19993
  if (resolution.reason === "exists") {
18763
- const folder = path19.basename(resolution.existing.hubFolder);
19994
+ const folder = path24.basename(resolution.existing.hubFolder);
18764
19995
  console.error(`Hub "${folder}" already exists (${resolution.existing.hubId}). Use \`wayai push --hub ${folder}\` to update it.`);
18765
19996
  process.exit(1);
18766
19997
  }
@@ -18774,7 +20005,7 @@ async function createCommand(args2) {
18774
20005
  }
18775
20006
  console.error(`Multiple new hub folders found in ${wsLabel}/. Pass the folder name (\`wayai create <folder>\`) or run from inside one:`);
18776
20007
  for (const h of newHubs) {
18777
- console.error(` ${path19.basename(h.hubFolder)} (new \u2014 "${h.hubName}")`);
20008
+ console.error(` ${path24.basename(h.hubFolder)} (new \u2014 "${h.hubName}")`);
18778
20009
  }
18779
20010
  process.exit(1);
18780
20011
  }
@@ -18798,9 +20029,9 @@ var init_create = __esm({
18798
20029
  var diff_exports = {};
18799
20030
  __export(diff_exports, {
18800
20031
  diffCommand: () => diffCommand,
18801
- parseArgs: () => parseArgs7
20032
+ parseArgs: () => parseArgs8
18802
20033
  });
18803
- function parseArgs7(args2) {
20034
+ function parseArgs8(args2) {
18804
20035
  let production = false;
18805
20036
  let hubSelector;
18806
20037
  for (let i = 0; i < args2.length; i++) {
@@ -18814,7 +20045,7 @@ function parseArgs7(args2) {
18814
20045
  return { production, hubSelector };
18815
20046
  }
18816
20047
  async function diffCommand(args2) {
18817
- const { production, hubSelector } = parseArgs7(args2);
20048
+ const { production, hubSelector } = parseArgs8(args2);
18818
20049
  const repoConfig = requireRepoConfig();
18819
20050
  const { organization_id: organizationId } = repoConfig;
18820
20051
  const { config, accessToken } = await requireAuth();
@@ -18885,9 +20116,9 @@ var replicate_exports = {};
18885
20116
  __export(replicate_exports, {
18886
20117
  replicateCommand: () => replicateCommand
18887
20118
  });
18888
- import * as fs17 from "fs";
18889
- import * as path20 from "path";
18890
- function parseArgs8(args2) {
20119
+ import * as fs21 from "fs";
20120
+ import * as path25 from "path";
20121
+ function parseArgs9(args2) {
18891
20122
  let label;
18892
20123
  let hubSelector;
18893
20124
  for (let i = 0; i < args2.length; i++) {
@@ -18903,7 +20134,7 @@ function parseArgs8(args2) {
18903
20134
  return { label, hubSelector };
18904
20135
  }
18905
20136
  async function replicateCommand(args2) {
18906
- const { label, hubSelector } = parseArgs8(args2);
20137
+ const { label, hubSelector } = parseArgs9(args2);
18907
20138
  const normalizedLabel = label?.trim() || void 0;
18908
20139
  if (normalizedLabel && normalizedLabel.length > PREVIEW_LABEL_MAX_LENGTH) {
18909
20140
  console.error(`--label must be ${PREVIEW_LABEL_MAX_LENGTH} characters or fewer.`);
@@ -18932,8 +20163,8 @@ async function replicateCommand(args2) {
18932
20163
  payload.preview_label,
18933
20164
  payload.branch_name
18934
20165
  );
18935
- const folderPreExisted = fs17.existsSync(hubFolder);
18936
- fs17.mkdirSync(path20.dirname(hubFolder), { recursive: true });
20166
+ const folderPreExisted = fs21.existsSync(hubFolder);
20167
+ fs21.mkdirSync(path25.dirname(hubFolder), { recursive: true });
18937
20168
  const delta = await materializeHubFolder(hubFolder, payload);
18938
20169
  hubFolder = autoRenameHubFolder(
18939
20170
  hubFolder,
@@ -18945,8 +20176,8 @@ async function replicateCommand(args2) {
18945
20176
  );
18946
20177
  autoBindIfUnbound(previewHubId);
18947
20178
  if (folderPreExisted) printLocalFileChanges(delta);
18948
- console.log(`Preview written to ${path20.basename(hubFolder)}`);
18949
- console.log(` Switch to it with: wayai use ${path20.basename(hubFolder)}`);
20179
+ console.log(`Preview written to ${path25.basename(hubFolder)}`);
20180
+ console.log(` Switch to it with: wayai use ${path25.basename(hubFolder)}`);
18950
20181
  }
18951
20182
  var init_replicate = __esm({
18952
20183
  "src/commands/replicate.ts"() {
@@ -18969,8 +20200,8 @@ var relabel_exports = {};
18969
20200
  __export(relabel_exports, {
18970
20201
  relabelCommand: () => relabelCommand
18971
20202
  });
18972
- import * as path21 from "path";
18973
- function parseArgs9(args2) {
20203
+ import * as path26 from "path";
20204
+ function parseArgs10(args2) {
18974
20205
  let label;
18975
20206
  let clear = false;
18976
20207
  let hubSelector;
@@ -18987,7 +20218,7 @@ function parseArgs9(args2) {
18987
20218
  return { label, clear, hubSelector };
18988
20219
  }
18989
20220
  async function relabelCommand(args2) {
18990
- const { label, clear, hubSelector } = parseArgs9(args2);
20221
+ const { label, clear, hubSelector } = parseArgs10(args2);
18991
20222
  if (!clear && (label === void 0 || label.trim() === "")) {
18992
20223
  console.error("Usage: wayai relabel <label> [--hub <uuid|folder>] (or --clear to remove the label)");
18993
20224
  process.exit(1);
@@ -19013,7 +20244,7 @@ async function relabelCommand(args2) {
19013
20244
  } else {
19014
20245
  console.error(`Multiple hubs found in ${wsLabel}/. Pass --hub <uuid|folder-name> to choose, or run from inside a hub folder:`);
19015
20246
  for (const h of previewHubs) {
19016
- console.error(` ${path21.basename(h.hubFolder)} (${h.hubId})`);
20247
+ console.error(` ${path26.basename(h.hubFolder)} (${h.hubId})`);
19017
20248
  }
19018
20249
  }
19019
20250
  process.exit(1);
@@ -19022,7 +20253,7 @@ async function relabelCommand(args2) {
19022
20253
  console.log("This is a read-only production mirror \u2014 production hubs have no preview label. Relabel the linked preview hub instead.");
19023
20254
  return;
19024
20255
  }
19025
- assertHubMatchesBinding(target.hubId, path21.basename(target.hubFolder));
20256
+ assertHubMatchesBinding(target.hubId, path26.basename(target.hubFolder));
19026
20257
  console.log(normalizedLabel ? `Setting preview label to "${normalizedLabel}"...` : "Clearing preview label...");
19027
20258
  const { data } = await client.relabelPreview(target.hubId, normalizedLabel);
19028
20259
  const row = data[0];
@@ -19038,7 +20269,7 @@ async function relabelCommand(args2) {
19038
20269
  );
19039
20270
  console.log(serverLabel ? `Preview label set to "${serverLabel}".` : "Preview label cleared.");
19040
20271
  if (finalFolder !== target.hubFolder) {
19041
- console.log(`Hub folder is now ${path21.basename(finalFolder)}`);
20272
+ console.log(`Hub folder is now ${path26.basename(finalFolder)}`);
19042
20273
  }
19043
20274
  }
19044
20275
  var init_relabel = __esm({
@@ -19059,13 +20290,13 @@ var init_relabel = __esm({
19059
20290
  // src/commands/publish.ts
19060
20291
  var publish_exports = {};
19061
20292
  __export(publish_exports, {
19062
- parseArgs: () => parseArgs10,
20293
+ parseArgs: () => parseArgs11,
19063
20294
  publishCommand: () => publishCommand,
19064
20295
  renderHubDiff: () => renderHubDiff,
19065
20296
  runPublish: () => runPublish
19066
20297
  });
19067
- import * as path22 from "path";
19068
- function parseArgs10(args2) {
20298
+ import * as path27 from "path";
20299
+ function parseArgs11(args2) {
19069
20300
  let autoConfirm = false;
19070
20301
  let hubSelector;
19071
20302
  for (let i = 0; i < args2.length; i++) {
@@ -19159,7 +20390,7 @@ Published. Production hub: ${data.production_hub_id}`);
19159
20390
  return "synced";
19160
20391
  }
19161
20392
  async function publishCommand(args2) {
19162
- const { autoConfirm, hubSelector } = parseArgs10(args2);
20393
+ const { autoConfirm, hubSelector } = parseArgs11(args2);
19163
20394
  const repoConfig = requireRepoConfig();
19164
20395
  const { organization_id: organizationId } = repoConfig;
19165
20396
  const { config, accessToken } = await requireAuth();
@@ -19178,7 +20409,7 @@ async function publishCommand(args2) {
19178
20409
  return;
19179
20410
  }
19180
20411
  }
19181
- assertHubMatchesBinding(hubId, hubFolder ? path22.basename(hubFolder) : void 0);
20412
+ assertHubMatchesBinding(hubId, hubFolder ? path27.basename(hubFolder) : void 0);
19182
20413
  await runPublish(client, { hubId, localConfig, organizationId, autoConfirm });
19183
20414
  }
19184
20415
  var STATUS_STYLE;
@@ -19211,7 +20442,7 @@ var use_exports = {};
19211
20442
  __export(use_exports, {
19212
20443
  useCommand: () => useCommand
19213
20444
  });
19214
- import * as path23 from "path";
20445
+ import * as path28 from "path";
19215
20446
  async function useCommand(args2) {
19216
20447
  const target = args2[0];
19217
20448
  if (!target || target.startsWith("-")) {
@@ -19233,7 +20464,7 @@ async function useCommand(args2) {
19233
20464
  const match = findHubByFolderName(workspaceDir, target);
19234
20465
  if (!match) {
19235
20466
  const newHubs = scanNewHubs(workspaceDir);
19236
- const pending = newHubs.find((h) => path23.basename(h.hubFolder) === target);
20467
+ const pending = newHubs.find((h) => path28.basename(h.hubFolder) === target);
19237
20468
  if (pending) {
19238
20469
  console.error(
19239
20470
  `"${target}" is a new hub that hasn't been created on the platform yet, so it has no id to bind to.
@@ -19244,10 +20475,10 @@ Create it first \u2014 the worktree binds automatically afterward:
19244
20475
  }
19245
20476
  console.error(`No hub matching "${target}" found in ${wsLabel}/. Pass a UUID or a folder name from:`);
19246
20477
  for (const h of scanWorkspaceHubs(workspaceDir)) {
19247
- console.error(` ${path23.basename(h.hubFolder)} (${h.hubId})`);
20478
+ console.error(` ${path28.basename(h.hubFolder)} (${h.hubId})`);
19248
20479
  }
19249
20480
  for (const h of newHubs) {
19250
- console.error(` ${path23.basename(h.hubFolder)} (new \u2014 "${h.hubName}", run \`wayai create ${path23.basename(h.hubFolder)}\`)`);
20481
+ console.error(` ${path28.basename(h.hubFolder)} (new \u2014 "${h.hubName}", run \`wayai create ${path28.basename(h.hubFolder)}\`)`);
19251
20482
  }
19252
20483
  process.exit(1);
19253
20484
  }
@@ -19286,11 +20517,11 @@ __export(migrate_exports, {
19286
20517
  migrateCommand: () => migrateCommand
19287
20518
  });
19288
20519
  import { execFileSync as execFileSync3 } from "child_process";
19289
- import * as fs18 from "fs";
19290
- import * as path24 from "path";
20520
+ import * as fs22 from "fs";
20521
+ import * as path29 from "path";
19291
20522
  function isTracked(gitRoot, p) {
19292
20523
  try {
19293
- execFileSync3("git", ["ls-files", "--error-unmatch", "--", path24.relative(gitRoot, p)], {
20524
+ execFileSync3("git", ["ls-files", "--error-unmatch", "--", path29.relative(gitRoot, p)], {
19294
20525
  cwd: gitRoot,
19295
20526
  stdio: ["pipe", "pipe", "pipe"]
19296
20527
  });
@@ -19300,10 +20531,10 @@ function isTracked(gitRoot, p) {
19300
20531
  }
19301
20532
  }
19302
20533
  function moveDir(gitRoot, from, to) {
19303
- fs18.mkdirSync(path24.dirname(to), { recursive: true });
20534
+ fs22.mkdirSync(path29.dirname(to), { recursive: true });
19304
20535
  if (isTracked(gitRoot, from)) {
19305
20536
  try {
19306
- execFileSync3("git", ["mv", path24.relative(gitRoot, from), path24.relative(gitRoot, to)], {
20537
+ execFileSync3("git", ["mv", path29.relative(gitRoot, from), path29.relative(gitRoot, to)], {
19307
20538
  cwd: gitRoot,
19308
20539
  stdio: ["pipe", "pipe", "pipe"]
19309
20540
  });
@@ -19311,7 +20542,7 @@ function moveDir(gitRoot, from, to) {
19311
20542
  } catch {
19312
20543
  }
19313
20544
  }
19314
- fs18.renameSync(from, to);
20545
+ fs22.renameSync(from, to);
19315
20546
  return "fs";
19316
20547
  }
19317
20548
  async function migrateCommand(_args) {
@@ -19320,12 +20551,12 @@ async function migrateCommand(_args) {
19320
20551
  console.error("Not inside a git repository.");
19321
20552
  process.exit(1);
19322
20553
  }
19323
- const rel = (p) => path24.relative(gitRoot, p);
19324
- const newWs = path24.join(gitRoot, WAYAI_LAYOUT.wsDir);
19325
- const legacyWs = path24.join(gitRoot, WAYAI_LAYOUT.legacy.wsDir);
19326
- const legacyOrg = path24.join(gitRoot, WAYAI_LAYOUT.legacy.orgAtRoot);
19327
- const newHubs = path24.join(newWs, WAYAI_LAYOUT.hubsSubdir);
19328
- const newOrg = path24.join(newWs, WAYAI_LAYOUT.orgSubdir);
20554
+ const rel = (p) => path29.relative(gitRoot, p);
20555
+ const newWs = path29.join(gitRoot, WAYAI_LAYOUT.wsDir);
20556
+ const legacyWs = path29.join(gitRoot, WAYAI_LAYOUT.legacy.wsDir);
20557
+ const legacyOrg = path29.join(gitRoot, WAYAI_LAYOUT.legacy.orgAtRoot);
20558
+ const newHubs = path29.join(newWs, WAYAI_LAYOUT.hubsSubdir);
20559
+ const newOrg = path29.join(newWs, WAYAI_LAYOUT.orgSubdir);
19329
20560
  const hasLegacyWs = isDirectory(legacyWs);
19330
20561
  const hasLegacyOrg = isDirectory(legacyOrg);
19331
20562
  if (!hasLegacyWs && !hasLegacyOrg) {
@@ -19399,12 +20630,12 @@ var send_message_exports = {};
19399
20630
  __export(send_message_exports, {
19400
20631
  sendMessageCommand: () => sendMessageCommand
19401
20632
  });
19402
- import * as fs19 from "fs";
19403
- import * as path25 from "path";
20633
+ import * as fs23 from "fs";
20634
+ import * as path30 from "path";
19404
20635
  function statAttachment(filePath) {
19405
20636
  let stat2;
19406
20637
  try {
19407
- stat2 = fs19.statSync(filePath);
20638
+ stat2 = fs23.statSync(filePath);
19408
20639
  } catch {
19409
20640
  console.error(`Error: file not found: ${filePath}`);
19410
20641
  process.exit(1);
@@ -19416,11 +20647,11 @@ function statAttachment(filePath) {
19416
20647
  return { filePath, size: stat2.size };
19417
20648
  }
19418
20649
  function readAttachment(filePath, size) {
19419
- const fileName = path25.basename(filePath);
19420
- const ext = path25.extname(fileName).replace(/^\./, "");
20650
+ const fileName = path30.basename(filePath);
20651
+ const ext = path30.extname(fileName).replace(/^\./, "");
19421
20652
  return {
19422
20653
  file_name: fileName,
19423
- file_binary: fs19.readFileSync(filePath).toString("base64"),
20654
+ file_binary: fs23.readFileSync(filePath).toString("base64"),
19424
20655
  file_size: size,
19425
20656
  ...ext && { file_extension: ext }
19426
20657
  };
@@ -19467,7 +20698,7 @@ async function sendMessageCommand(args2) {
19467
20698
  }
19468
20699
  const stats = filePaths.map(statAttachment);
19469
20700
  const filesTotal = stats.reduce((sum, s) => sum + base64Length(s.size), 0);
19470
- const fileDetail = () => stats.map((s) => `${path25.basename(s.filePath)} ${asMb(s.size)} MB`).join(", ");
20701
+ const fileDetail = () => stats.map((s) => `${path30.basename(s.filePath)} ${asMb(s.size)} MB`).join(", ");
19471
20702
  if (filesTotal > MAX_MESSAGE_BODY_BYTES) {
19472
20703
  console.error(
19473
20704
  `Error: ${fileDetail()} encode to ~${asMb(filesTotal)} MB, over the ${asMb(MAX_MESSAGE_BODY_BYTES)} MB per-request limit.`
@@ -19475,10 +20706,10 @@ async function sendMessageCommand(args2) {
19475
20706
  console.error("Base64 inflates a file by about a third, so ~7 MB of files is the practical ceiling.");
19476
20707
  process.exit(1);
19477
20708
  }
19478
- const audioStats = stats.filter((s) => isAudioAttachmentFileName(path25.basename(s.filePath)));
20709
+ const audioStats = stats.filter((s) => isAudioAttachmentFileName(path30.basename(s.filePath)));
19479
20710
  if (audioStats.length > 1) {
19480
20711
  console.error(
19481
- `Error: at most one audio file per message (got ${audioStats.length}: ${audioStats.map((s) => path25.basename(s.filePath)).join(", ")}).`
20712
+ `Error: at most one audio file per message (got ${audioStats.length}: ${audioStats.map((s) => path30.basename(s.filePath)).join(", ")}).`
19482
20713
  );
19483
20714
  console.error("Audio is transcribed via the hub's STT connection, and only one file per message is transcribed.");
19484
20715
  process.exit(1);
@@ -19486,7 +20717,7 @@ async function sendMessageCommand(args2) {
19486
20717
  const oversizeAudio = audioStats.find((s) => base64Length(s.size) > MAX_AUDIO_FILE_BASE64_BYTES);
19487
20718
  if (oversizeAudio) {
19488
20719
  console.error(
19489
- `Error: ${path25.basename(oversizeAudio.filePath)} (${asMb(oversizeAudio.size)} MB) is over the ~${asMb(MAX_AUDIO_FILE_BASE64_BYTES * 3 / 4)} MB audio limit for transcription.`
20720
+ `Error: ${path30.basename(oversizeAudio.filePath)} (${asMb(oversizeAudio.size)} MB) is over the ~${asMb(MAX_AUDIO_FILE_BASE64_BYTES * 3 / 4)} MB audio limit for transcription.`
19490
20721
  );
19491
20722
  process.exit(1);
19492
20723
  }
@@ -20363,10 +21594,10 @@ var init_delete_history = __esm({
20363
21594
  // src/commands/sync-skills.ts
20364
21595
  var sync_skills_exports = {};
20365
21596
  __export(sync_skills_exports, {
20366
- parseArgs: () => parseArgs11,
21597
+ parseArgs: () => parseArgs12,
20367
21598
  syncSkillsCommand: () => syncSkillsCommand
20368
21599
  });
20369
- function parseArgs11(args2) {
21600
+ function parseArgs12(args2) {
20370
21601
  let connectionId;
20371
21602
  const idx = args2.indexOf("--connection-id");
20372
21603
  if (idx !== -1 && args2[idx + 1]) {
@@ -20389,7 +21620,7 @@ function printSyncResults(response) {
20389
21620
  }
20390
21621
  async function syncSkillsCommand(args2) {
20391
21622
  const hubId = resolveActiveHubId(args2);
20392
- const { connectionId } = parseArgs11(args2);
21623
+ const { connectionId } = parseArgs12(args2);
20393
21624
  requireRepoConfig();
20394
21625
  const { config, accessToken } = await requireAuth();
20395
21626
  const client = new ApiClient({ apiUrl: config.api_url, accessToken });
@@ -20414,10 +21645,10 @@ var init_sync_skills = __esm({
20414
21645
  // src/commands/sync-mcp.ts
20415
21646
  var sync_mcp_exports = {};
20416
21647
  __export(sync_mcp_exports, {
20417
- parseArgs: () => parseArgs12,
21648
+ parseArgs: () => parseArgs13,
20418
21649
  syncMcpCommand: () => syncMcpCommand
20419
21650
  });
20420
- function parseArgs12(args2) {
21651
+ function parseArgs13(args2) {
20421
21652
  let connection;
20422
21653
  let check = false;
20423
21654
  for (let i = 0; i < args2.length; i++) {
@@ -20432,7 +21663,7 @@ function parseArgs12(args2) {
20432
21663
  }
20433
21664
  async function syncMcpCommand(args2) {
20434
21665
  const hubId = resolveActiveHubId(args2);
20435
- const { connection, check } = parseArgs12(args2);
21666
+ const { connection, check } = parseArgs13(args2);
20436
21667
  if (!connection) {
20437
21668
  console.error("Usage: wayai sync-mcp --connection <name> [--hub <uuid|folder-name>] [--check]");
20438
21669
  console.error("");
@@ -20711,8 +21942,8 @@ function installEvalSignalHandlers(input) {
20711
21942
  let signalCount = 0;
20712
21943
  let disposed = false;
20713
21944
  let settle;
20714
- const settled = new Promise((resolve5) => {
20715
- settle = resolve5;
21945
+ const settled = new Promise((resolve7) => {
21946
+ settle = resolve7;
20716
21947
  });
20717
21948
  const listeners = /* @__PURE__ */ new Map();
20718
21949
  const dispose = () => {
@@ -21062,7 +22293,7 @@ Timeout after ${timeoutSeconds}s${queuedSeconds > 0 ? ` (${queuedSeconds}s of it
21062
22293
  process.exit(1);
21063
22294
  }
21064
22295
  function sleep(ms) {
21065
- return new Promise((resolve5) => setTimeout(resolve5, ms));
22296
+ return new Promise((resolve7) => setTimeout(resolve7, ms));
21066
22297
  }
21067
22298
  function parseRunNumbers(raw) {
21068
22299
  if (!raw || raw.startsWith("--")) {
@@ -21332,15 +22563,15 @@ var eval_capture_exports = {};
21332
22563
  __export(eval_capture_exports, {
21333
22564
  evalCaptureCommand: () => evalCaptureCommand
21334
22565
  });
21335
- import * as fs20 from "fs";
21336
- import * as path26 from "path";
21337
- import * as yaml7 from "js-yaml";
22566
+ import * as fs24 from "fs";
22567
+ import * as path31 from "path";
22568
+ import * as yaml11 from "js-yaml";
21338
22569
  function isValidSetName(name) {
21339
22570
  if (name.length === 0 || name === "." || name === "..") return false;
21340
22571
  if (name.startsWith(".")) return false;
21341
22572
  return !/[\/\\\0]/.test(name);
21342
22573
  }
21343
- function parseArgs13(args2) {
22574
+ function parseArgs14(args2) {
21344
22575
  if (args2.length === 0 || args2[0].startsWith("-")) {
21345
22576
  console.error("Usage: wayai eval capture <conversation_id> [--set <name>] [--name <eval_name>] [--instructions <text>]");
21346
22577
  process.exit(1);
@@ -21386,7 +22617,7 @@ function parseArgs13(args2) {
21386
22617
  }
21387
22618
  async function evalCaptureCommand(args2) {
21388
22619
  const hubId = resolveActiveHubId(args2);
21389
- const parsed = parseArgs13(args2);
22620
+ const parsed = parseArgs14(args2);
21390
22621
  const { config, accessToken } = await requireAuth();
21391
22622
  requireRepoConfig();
21392
22623
  const client = new ApiClient({ apiUrl: config.api_url, accessToken });
@@ -21399,15 +22630,15 @@ async function evalCaptureCommand(args2) {
21399
22630
  const setFolderName = targetSetName;
21400
22631
  const scenarioName = parsed.evalName ?? `Capture ${parsed.conversationId.slice(0, 8)}`;
21401
22632
  const slug = slugify(scenarioName);
21402
- const evalsDir = path26.join(hubFolder, "evals");
21403
- const targetDir = path26.join(evalsDir, setFolderName);
21404
- const targetPath = path26.join(targetDir, `${slug}.yaml`);
21405
- if (!targetPath.startsWith(evalsDir + path26.sep)) {
21406
- console.error(`Resolved path "${path26.relative(hubFolder, targetPath)}" escapes evals/. Aborting.`);
22633
+ const evalsDir = path31.join(hubFolder, "evals");
22634
+ const targetDir = path31.join(evalsDir, setFolderName);
22635
+ const targetPath = path31.join(targetDir, `${slug}.yaml`);
22636
+ if (!targetPath.startsWith(evalsDir + path31.sep)) {
22637
+ console.error(`Resolved path "${path31.relative(hubFolder, targetPath)}" escapes evals/. Aborting.`);
21407
22638
  process.exit(1);
21408
22639
  }
21409
- if (fs20.existsSync(targetPath)) {
21410
- console.error(`File already exists: ${path26.relative(hubFolder, targetPath)}. Use --name to choose a different name.`);
22640
+ if (fs24.existsSync(targetPath)) {
22641
+ console.error(`File already exists: ${path31.relative(hubFolder, targetPath)}. Use --name to choose a different name.`);
21411
22642
  process.exit(1);
21412
22643
  }
21413
22644
  console.log("Resolving scenario set...");
@@ -21439,9 +22670,9 @@ async function evalCaptureCommand(args2) {
21439
22670
  ...captured.evaluator_instructions ? { evaluator_instructions: captured.evaluator_instructions } : {}
21440
22671
  };
21441
22672
  const yamlObj = buildEvalYamlObject(evalEntry, slug);
21442
- fs20.mkdirSync(targetDir, { recursive: true });
21443
- fs20.writeFileSync(targetPath, yaml7.dump(yamlObj, YAML_DUMP_OPTIONS), "utf-8");
21444
- const relPath = path26.relative(process.cwd(), targetPath);
22673
+ fs24.mkdirSync(targetDir, { recursive: true });
22674
+ fs24.writeFileSync(targetPath, yaml11.dump(yamlObj, YAML_DUMP_OPTIONS), "utf-8");
22675
+ const relPath = path31.relative(process.cwd(), targetPath);
21445
22676
  console.log(`
21446
22677
  Wrote ${relPath}`);
21447
22678
  console.log("Run `wayai pull` to refresh the agent display name, then commit. The scenario is already on the platform.");
@@ -21463,7 +22694,7 @@ var journey_capture_exports = {};
21463
22694
  __export(journey_capture_exports, {
21464
22695
  journeyCaptureCommand: () => journeyCaptureCommand
21465
22696
  });
21466
- function parseArgs14(args2) {
22697
+ function parseArgs15(args2) {
21467
22698
  if (args2.length === 0 || args2[0].startsWith("-")) {
21468
22699
  console.error("Usage: wayai eval journey capture <conversation_id> [--name <journey_name>] [--instructions <text>]");
21469
22700
  process.exit(1);
@@ -21498,7 +22729,7 @@ function parseArgs14(args2) {
21498
22729
  }
21499
22730
  async function journeyCaptureCommand(args2) {
21500
22731
  const hubId = resolveActiveHubId(args2);
21501
- const parsed = parseArgs14(args2);
22732
+ const parsed = parseArgs15(args2);
21502
22733
  const { config, accessToken } = await requireAuth();
21503
22734
  requireRepoConfig();
21504
22735
  const client = new ApiClient({ apiUrl: config.api_url, accessToken });
@@ -22426,9 +23657,9 @@ var init_credential_utils = __esm({
22426
23657
  var create_credential_exports = {};
22427
23658
  __export(create_credential_exports, {
22428
23659
  createCredentialCommand: () => createCredentialCommand,
22429
- parseArgs: () => parseArgs15
23660
+ parseArgs: () => parseArgs16
22430
23661
  });
22431
- function parseArgs15(args2) {
23662
+ function parseArgs16(args2) {
22432
23663
  let name;
22433
23664
  let type;
22434
23665
  let orgId;
@@ -22456,7 +23687,7 @@ function parseArgs15(args2) {
22456
23687
  return { name, type, orgId, description, tags: splitTagRefs(tags), environment, stdin };
22457
23688
  }
22458
23689
  async function createCredentialCommand(args2) {
22459
- const parsed = parseArgs15(args2);
23690
+ const parsed = parseArgs16(args2);
22460
23691
  if (!parsed.name) {
22461
23692
  console.error("Missing required flag: --name <credential-name>");
22462
23693
  console.error('Usage: wayai create-credential --name "openai-key" --type "Bearer Token"');
@@ -22563,10 +23794,10 @@ var init_create_credential = __esm({
22563
23794
  // src/commands/update-credential.ts
22564
23795
  var update_credential_exports = {};
22565
23796
  __export(update_credential_exports, {
22566
- parseArgs: () => parseArgs16,
23797
+ parseArgs: () => parseArgs17,
22567
23798
  updateCredentialCommand: () => updateCredentialCommand
22568
23799
  });
22569
- function parseArgs16(args2) {
23800
+ function parseArgs17(args2) {
22570
23801
  let name;
22571
23802
  let rename;
22572
23803
  let orgId;
@@ -22599,7 +23830,7 @@ function parseArgs16(args2) {
22599
23830
  return { name, rename, orgId, description, tags: splitTagRefs(tags), hasTagFlag, environment, stdin, secretPrompt };
22600
23831
  }
22601
23832
  async function updateCredentialCommand(args2) {
22602
- const parsed = parseArgs16(args2);
23833
+ const parsed = parseArgs17(args2);
22603
23834
  if (!parsed.name) {
22604
23835
  console.error("Missing required flag: --name <credential-name>");
22605
23836
  console.error('Usage: wayai update-credential --name "my-key" --stdin');
@@ -22712,10 +23943,10 @@ var init_update_credential = __esm({
22712
23943
  // src/commands/set-connection-credential.ts
22713
23944
  var set_connection_credential_exports = {};
22714
23945
  __export(set_connection_credential_exports, {
22715
- parseArgs: () => parseArgs17,
23946
+ parseArgs: () => parseArgs18,
22716
23947
  setConnectionCredentialCommand: () => setConnectionCredentialCommand
22717
23948
  });
22718
- function parseArgs17(args2) {
23949
+ function parseArgs18(args2) {
22719
23950
  let connection;
22720
23951
  let orgCredential;
22721
23952
  let field;
@@ -22738,7 +23969,7 @@ function usage2(msg) {
22738
23969
  }
22739
23970
  async function setConnectionCredentialCommand(args2) {
22740
23971
  const hubId = resolveActiveHubId(args2);
22741
- const parsed = parseArgs17(args2);
23972
+ const parsed = parseArgs18(args2);
22742
23973
  if (!parsed.connection) usage2("Missing required flag: --connection <name|id>");
22743
23974
  const orgMode = !!parsed.orgCredential;
22744
23975
  const directMode = !!parsed.field;
@@ -22807,23 +24038,23 @@ var init_set_connection_credential = __esm({
22807
24038
  });
22808
24039
 
22809
24040
  // src/lib/org-workspace.ts
22810
- import * as fs21 from "fs";
22811
- import * as path27 from "path";
22812
- import * as yaml8 from "js-yaml";
24041
+ import * as fs25 from "fs";
24042
+ import * as path32 from "path";
24043
+ import * as yaml12 from "js-yaml";
22813
24044
  function getOrgDir(gitRoot) {
22814
24045
  return resolveLayout(gitRoot).orgDir;
22815
24046
  }
22816
24047
  function orgManifestExists(orgDir) {
22817
- return fs21.existsSync(path27.join(orgDir, ORG_MANIFEST_NAME));
24048
+ return fs25.existsSync(path32.join(orgDir, ORG_MANIFEST_NAME));
22818
24049
  }
22819
24050
  function parseOrgResources(orgDir) {
22820
- const manifestPath = path27.join(orgDir, ORG_MANIFEST_NAME);
24051
+ const manifestPath = path32.join(orgDir, ORG_MANIFEST_NAME);
22821
24052
  let manifest = {};
22822
- if (fs21.existsSync(manifestPath)) {
22823
- manifest = yaml8.load(fs21.readFileSync(manifestPath, "utf-8")) ?? {};
24053
+ if (fs25.existsSync(manifestPath)) {
24054
+ manifest = yaml12.load(fs25.readFileSync(manifestPath, "utf-8")) ?? {};
22824
24055
  }
22825
24056
  const rawResources = Array.isArray(manifest.resources) ? manifest.resources : [];
22826
- const resourcesDir = path27.join(orgDir, "resources");
24057
+ const resourcesDir = path32.join(orgDir, "resources");
22827
24058
  const resources = rawResources.map((res) => {
22828
24059
  const resource = { name: res.name };
22829
24060
  if (res.id) resource.id = res.id;
@@ -22835,8 +24066,8 @@ function parseOrgResources(orgDir) {
22835
24066
  if (res.environment) resource.environment = res.environment;
22836
24067
  if (Array.isArray(res.tags)) resource.tags = res.tags;
22837
24068
  if (Array.isArray(res.folders)) resource.folders = res.folders;
22838
- const resDir = path27.join(resourcesDir, slugify(resource.name));
22839
- if (fs21.existsSync(resDir)) {
24069
+ const resDir = path32.join(resourcesDir, slugify(resource.name));
24070
+ if (fs25.existsSync(resDir)) {
22840
24071
  const files = scanResourceFiles(resDir, "");
22841
24072
  if (files.length > 0) resource.files = files;
22842
24073
  }
@@ -22845,28 +24076,28 @@ function parseOrgResources(orgDir) {
22845
24076
  return { version: 1, resources };
22846
24077
  }
22847
24078
  function writeOrgResources(orgDir, payload) {
22848
- fs21.mkdirSync(orgDir, { recursive: true });
24079
+ fs25.mkdirSync(orgDir, { recursive: true });
22849
24080
  const resources = payload.resources ?? [];
22850
24081
  const manifestResources = resources.map((r) => {
22851
24082
  const { files: _files, ...rest } = r;
22852
24083
  return rest;
22853
24084
  });
22854
- fs21.writeFileSync(
22855
- path27.join(orgDir, ORG_MANIFEST_NAME),
22856
- yaml8.dump({ version: 1, resources: manifestResources }, YAML_DUMP_OPTIONS),
24085
+ fs25.writeFileSync(
24086
+ path32.join(orgDir, ORG_MANIFEST_NAME),
24087
+ yaml12.dump({ version: 1, resources: manifestResources }, YAML_DUMP_OPTIONS),
22857
24088
  "utf-8"
22858
24089
  );
22859
- const resourcesDir = path27.join(orgDir, "resources");
24090
+ const resourcesDir = path32.join(orgDir, "resources");
22860
24091
  const currentSlugs = /* @__PURE__ */ new Set();
22861
24092
  for (const resource of resources) {
22862
24093
  const resSlug = slugify(resource.name);
22863
24094
  currentSlugs.add(resSlug);
22864
- writeResourceFileTree(path27.join(resourcesDir, resSlug), resource.files || [], orgDir);
24095
+ writeResourceFileTree(path32.join(resourcesDir, resSlug), resource.files || [], orgDir);
22865
24096
  }
22866
- if (fs21.existsSync(resourcesDir)) {
22867
- for (const entry of fs21.readdirSync(resourcesDir, { withFileTypes: true })) {
24097
+ if (fs25.existsSync(resourcesDir)) {
24098
+ for (const entry of fs25.readdirSync(resourcesDir, { withFileTypes: true })) {
22868
24099
  if (entry.isDirectory() && !currentSlugs.has(entry.name)) {
22869
- fs21.rmSync(path27.join(resourcesDir, entry.name), { recursive: true, force: true });
24100
+ fs25.rmSync(path32.join(resourcesDir, entry.name), { recursive: true, force: true });
22870
24101
  }
22871
24102
  }
22872
24103
  }
@@ -22875,7 +24106,7 @@ async function downloadOrgBinaryFiles(orgDir, payload) {
22875
24106
  let count = 0;
22876
24107
  for (const resource of payload.resources ?? []) {
22877
24108
  if (!resource.files) continue;
22878
- const resDir = path27.join(orgDir, "resources", slugify(resource.name));
24109
+ const resDir = path32.join(orgDir, "resources", slugify(resource.name));
22879
24110
  count += await downloadBinaryFiles(resDir, resource.files, orgDir);
22880
24111
  }
22881
24112
  if (count > 0) console.log(`Downloaded ${count} binary resource file(s).`);
@@ -23063,9 +24294,9 @@ var init_org = __esm({
23063
24294
  var list_exports = {};
23064
24295
  __export(list_exports, {
23065
24296
  listCommand: () => listCommand,
23066
- parseArgs: () => parseArgs18
24297
+ parseArgs: () => parseArgs19
23067
24298
  });
23068
- function parseArgs18(args2) {
24299
+ function parseArgs19(args2) {
23069
24300
  let orgId;
23070
24301
  let json = false;
23071
24302
  for (let i = 0; i < args2.length; i++) {
@@ -23078,7 +24309,7 @@ function parseArgs18(args2) {
23078
24309
  return { orgId, json };
23079
24310
  }
23080
24311
  async function listCommand(args2) {
23081
- const { orgId, json } = parseArgs18(args2);
24312
+ const { orgId, json } = parseArgs19(args2);
23082
24313
  const { config, accessToken } = await requireAuth();
23083
24314
  const client = new ApiClient({ apiUrl: config.api_url, accessToken });
23084
24315
  const { organizations } = await client.organizations();
@@ -23171,8 +24402,8 @@ var init_report_edit_args = __esm({
23171
24402
  });
23172
24403
 
23173
24404
  // src/lib/file-map.ts
23174
- import * as fs22 from "fs";
23175
- import * as path28 from "path";
24405
+ import * as fs26 from "fs";
24406
+ import * as path33 from "path";
23176
24407
  function isSafeRelPath(rel) {
23177
24408
  if (rel.length === 0 || rel.length > 300) return false;
23178
24409
  if (rel.startsWith("/") || rel.includes("\\")) return false;
@@ -23187,9 +24418,9 @@ function writeFileMap(targetDir, files) {
23187
24418
  if (!isSafeRelPath(rel)) {
23188
24419
  throw new Error(`Refusing to write unsafe path: ${rel}`);
23189
24420
  }
23190
- const abs = path28.join(targetDir, rel);
23191
- fs22.mkdirSync(path28.dirname(abs), { recursive: true });
23192
- fs22.writeFileSync(abs, body, "utf-8");
24421
+ const abs = path33.join(targetDir, rel);
24422
+ fs26.mkdirSync(path33.dirname(abs), { recursive: true });
24423
+ fs26.writeFileSync(abs, body, "utf-8");
23193
24424
  written.push(rel);
23194
24425
  }
23195
24426
  return written;
@@ -23205,8 +24436,8 @@ var admin_exports = {};
23205
24436
  __export(admin_exports, {
23206
24437
  adminCommand: () => adminCommand
23207
24438
  });
23208
- import * as fs23 from "fs";
23209
- import * as path29 from "path";
24439
+ import * as fs27 from "fs";
24440
+ import * as path34 from "path";
23210
24441
  async function adminCommand(args2) {
23211
24442
  const [group, ...afterGroup] = args2;
23212
24443
  if (!group) {
@@ -23507,7 +24738,7 @@ async function runArchiveRead(positional, flagArgs) {
23507
24738
  exitOnApiError(err);
23508
24739
  throw err;
23509
24740
  }
23510
- fs23.writeFileSync(outPath, zip);
24741
+ fs27.writeFileSync(outPath, zip);
23511
24742
  console.log(`Wrote ${zip.byteLength} bytes to ${outPath}`);
23512
24743
  return;
23513
24744
  }
@@ -23649,13 +24880,13 @@ async function runSkillInstall(positional) {
23649
24880
  throw err;
23650
24881
  }
23651
24882
  const root = findGitRoot() ?? process.cwd();
23652
- const present = HARNESS_SKILL_DIRS.filter((dir) => fs23.existsSync(path29.join(root, dir)));
24883
+ const present = HARNESS_SKILL_DIRS.filter((dir) => fs27.existsSync(path34.join(root, dir)));
23653
24884
  const targets = present.length > 0 ? present : HARNESS_SKILL_DIRS;
23654
24885
  const fileCount = Object.keys(res.files).length;
23655
24886
  const relDirs = targets.map((harness) => {
23656
- const targetDir = path29.join(root, harness, "skills", name);
24887
+ const targetDir = path34.join(root, harness, "skills", name);
23657
24888
  writeFileMap(targetDir, res.files);
23658
- return `${path29.relative(root, targetDir)}/`;
24889
+ return `${path34.relative(root, targetDir)}/`;
23659
24890
  });
23660
24891
  console.log(`Installed skill "${name}" (${fileCount} file${fileCount === 1 ? "" : "s"}) \u2192 ${relDirs.join(", ")}`);
23661
24892
  console.log("Reload your agent (e.g. restart Claude Code) to pick up the skill.");
@@ -24480,24 +25711,9 @@ var init_admin = __esm({
24480
25711
  init_skill_version();
24481
25712
  init_file_map();
24482
25713
  init_contracts();
24483
- VALID_TYPES = dataExplorerDebugDoType.options;
24484
- VALID_ANALYTICS_TABLES = dataExplorerDebugAnalyticsTable.options;
24485
- VALID_NOTICE_SEVERITIES = ["critical", "warn", "info"];
24486
- }
24487
- });
24488
-
24489
- // src/lib/terminal-output.ts
24490
- import { stripVTControlCharacters } from "util";
24491
- function sanitizeTerminalText(value) {
24492
- const normalizedNewlines = value.replace(/\r\n?/g, "\n");
24493
- return stripVTControlCharacters(normalizedNewlines).replace(
24494
- /[\u0000-\u0009\u000b-\u001f\u007f-\u009f]/g,
24495
- ""
24496
- );
24497
- }
24498
- var init_terminal_output = __esm({
24499
- "src/lib/terminal-output.ts"() {
24500
- "use strict";
25714
+ VALID_TYPES = dataExplorerDebugDoType.options;
25715
+ VALID_ANALYTICS_TABLES = dataExplorerDebugAnalyticsTable.options;
25716
+ VALID_NOTICE_SEVERITIES = ["critical", "warn", "info"];
24501
25717
  }
24502
25718
  });
24503
25719
 
@@ -24963,91 +26179,6 @@ var init_update = __esm({
24963
26179
  }
24964
26180
  });
24965
26181
 
24966
- // src/data/org-context.ts
24967
- function setDataOrgOverride(orgId) {
24968
- override = orgId;
24969
- }
24970
- function getDataOrgOverride() {
24971
- return override;
24972
- }
24973
- var override;
24974
- var init_org_context = __esm({
24975
- "src/data/org-context.ts"() {
24976
- "use strict";
24977
- }
24978
- });
24979
-
24980
- // src/data/client.ts
24981
- async function createDataClient(orgId) {
24982
- const { config, accessToken } = await requireAuth();
24983
- const api = new ApiClient({ apiUrl: config.api_url, accessToken });
24984
- const selected = orgId ?? getDataOrgOverride();
24985
- if (selected !== void 0 && !UUID_RE2.test(selected)) {
24986
- throw expected(`Invalid --org: ${JSON.stringify(selected)}. Expected an organization UUID.`);
24987
- }
24988
- const org = selected ?? readRepoConfig()?.organization_id;
24989
- return {
24990
- async request(method, path31, body) {
24991
- const envelope = await api.dataRequest(method, path31, body, org);
24992
- return envelope.data;
24993
- },
24994
- async collectPages(makePath) {
24995
- const all = [];
24996
- const seen = /* @__PURE__ */ new Set();
24997
- let cursor;
24998
- for (let page = 0; page < MAX_PAGES; page++) {
24999
- const { data, meta } = await api.dataRequest("GET", makePath(cursor), void 0, org);
25000
- for (const row of data ?? []) all.push(row);
25001
- cursor = meta?.has_more ? meta.cursor : void 0;
25002
- if (cursor === void 0) break;
25003
- if (seen.has(cursor)) break;
25004
- seen.add(cursor);
25005
- }
25006
- return all;
25007
- },
25008
- async upload(v1Path, bytes, contentType, headers) {
25009
- const envelope = await api.dataUpload(v1Path, bytes, contentType, org, headers);
25010
- return envelope.data;
25011
- },
25012
- download(v1Path) {
25013
- return api.dataDownload(v1Path, org);
25014
- },
25015
- url(v1Path) {
25016
- return api.dataUrl(v1Path, org);
25017
- }
25018
- };
25019
- }
25020
- function dataErrorEnvelope(err) {
25021
- if (!(err instanceof ApiError)) return null;
25022
- try {
25023
- const parsed = JSON.parse(err.body);
25024
- return parsed?.error ?? null;
25025
- } catch {
25026
- return null;
25027
- }
25028
- }
25029
- function dataErrorCode(err) {
25030
- const code = dataErrorEnvelope(err)?.code;
25031
- return typeof code === "string" && code ? code : null;
25032
- }
25033
- function dataErrorDetails(err) {
25034
- const details = dataErrorEnvelope(err)?.details;
25035
- return details && typeof details === "object" ? details : void 0;
25036
- }
25037
- var MAX_PAGES;
25038
- var init_client = __esm({
25039
- "src/data/client.ts"() {
25040
- "use strict";
25041
- init_auth();
25042
- init_api_client();
25043
- init_repo_config();
25044
- init_utils();
25045
- init_expected();
25046
- init_org_context();
25047
- MAX_PAGES = 1e3;
25048
- }
25049
- });
25050
-
25051
26182
  // src/data/output.ts
25052
26183
  function printOutput(data, format) {
25053
26184
  if (format === "json") {
@@ -25148,140 +26279,6 @@ var init_output = __esm({
25148
26279
  }
25149
26280
  });
25150
26281
 
25151
- // src/lib/base-id.ts
25152
- function isValidBaseId(id) {
25153
- return BASE_ID_RE.test(id);
25154
- }
25155
- var BASE_ID_RE;
25156
- var init_base_id = __esm({
25157
- "src/lib/base-id.ts"() {
25158
- "use strict";
25159
- BASE_ID_RE = /^(?!\.\.?$)[A-Za-z0-9._-]{1,256}$/;
25160
- }
25161
- });
25162
-
25163
- // src/data/helpers.ts
25164
- import { readFileSync as readFileSync19 } from "fs";
25165
- function pathSegment(id, label = "id") {
25166
- if (!isValidBaseId(id)) {
25167
- throw expected(
25168
- `Invalid ${label}: ${JSON.stringify(id)}. Ids are slugs \u2014 letters, digits, dot, dash and underscore only.`
25169
- );
25170
- }
25171
- return encodeURIComponent(id);
25172
- }
25173
- function foreignSegment(value, label = "id") {
25174
- if (value === "." || value === "..") {
25175
- throw expected(`Invalid ${label}: ${JSON.stringify(value)} is a path traversal segment.`);
25176
- }
25177
- return encodeURIComponent(value);
25178
- }
25179
- function pathSegments(value, label = "path") {
25180
- return value.split("/").map((segment) => foreignSegment(segment, label)).join("/");
25181
- }
25182
- function parseData(data, flag) {
25183
- const prefix = flag ? `${flag}: ` : "";
25184
- const source = data.startsWith("@") ? data.slice(1) : void 0;
25185
- let text = data;
25186
- if (source !== void 0) {
25187
- try {
25188
- text = readFileSync19(source, "utf-8");
25189
- } catch (e) {
25190
- throw expected(`${prefix}${source}: ${e instanceof Error ? e.message : "could not be read"}`);
25191
- }
25192
- }
25193
- try {
25194
- return JSON.parse(text);
25195
- } catch (e) {
25196
- const where = source !== void 0 ? ` in ${source}` : "";
25197
- throw expected(`${prefix}invalid JSON${where}: ${e instanceof Error ? e.message : String(e)}`);
25198
- }
25199
- }
25200
- function toolsetMcpUrl(slug) {
25201
- return `https://data-mcp.wayai.pro/t/${slug}/mcp`;
25202
- }
25203
- function globals(cmd) {
25204
- let namespace = cmd;
25205
- while (namespace.parent?.parent) namespace = namespace.parent;
25206
- return namespace.opts();
25207
- }
25208
- function withBaseOption(command2) {
25209
- return command2.option("--base <id>", "Base id (or set WAYAI_BASE)");
25210
- }
25211
- function baseOptionHolder(cmd) {
25212
- for (let c = cmd; c; c = c.parent ?? void 0) {
25213
- if (c.options.some((o) => o.long === "--base")) return c;
25214
- }
25215
- return void 0;
25216
- }
25217
- function findBase(cmd) {
25218
- return baseOptionHolder(cmd)?.opts()?.base;
25219
- }
25220
- function requireBase(cmd) {
25221
- const base = findBase(cmd) ?? process.env.WAYAI_BASE ?? "";
25222
- if (base) return base;
25223
- console.error("Error: --base is required (or set WAYAI_BASE)");
25224
- return process.exit(1);
25225
- }
25226
- function outputFormat(cmd) {
25227
- const opts = globals(cmd);
25228
- return opts.json || opts.output === "json" ? "json" : "table";
25229
- }
25230
- function historyQuery(opts) {
25231
- const qs = new URLSearchParams();
25232
- if (opts.limit) qs.set("limit", opts.limit);
25233
- if (opts.offset) qs.set("offset", opts.offset);
25234
- if (opts.diff) qs.set("diff", "true");
25235
- const q = qs.toString();
25236
- return q ? `?${q}` : "";
25237
- }
25238
- function splitList(value) {
25239
- return value.split(",").map((v) => v.trim()).filter((v) => v.length > 0);
25240
- }
25241
- function parseByteCount(flag, value) {
25242
- const n = Number(value);
25243
- if (!Number.isInteger(n) || n < 0) {
25244
- throw expected(`${flag} must be a whole number of bytes (0 = unlimited), not ${JSON.stringify(value)}.`);
25245
- }
25246
- return n;
25247
- }
25248
- async function readSecret(source, label) {
25249
- const value = resolveSecretSource(source) === "stdin" ? (await readStdin()).trim() : (await promptSecret(`${label}: `)).trim();
25250
- if (!value) throw expected(`${label} is required.`);
25251
- return value;
25252
- }
25253
- function isInteractive() {
25254
- return Boolean(process.stdin.isTTY && process.stdout.isTTY);
25255
- }
25256
- function parseDuration(input, flag = "duration") {
25257
- const match = DURATION_RE.exec(input.trim());
25258
- const value = Number(match?.[1] ?? 0);
25259
- const unit = match?.[2];
25260
- const unitMs = unit ? DURATION_UNIT_MS[unit] : void 0;
25261
- if (!unitMs || value <= 0) {
25262
- throw expected(
25263
- `Invalid ${flag} ${JSON.stringify(input)} \u2014 use <number><unit> with unit s/m/h/d (e.g. 10m, 2h, 30d).`
25264
- );
25265
- }
25266
- return value * unitMs;
25267
- }
25268
- var DURATION_RE, DURATION_UNIT_MS;
25269
- var init_helpers = __esm({
25270
- "src/data/helpers.ts"() {
25271
- "use strict";
25272
- init_base_id();
25273
- init_expected();
25274
- init_utils();
25275
- DURATION_RE = /^(\d+)([smhd])$/;
25276
- DURATION_UNIT_MS = {
25277
- s: 1e3,
25278
- m: 6e4,
25279
- h: 36e5,
25280
- d: 864e5
25281
- };
25282
- }
25283
- });
25284
-
25285
26282
  // src/data/commands/actions.ts
25286
26283
  import { Command } from "commander";
25287
26284
  function buildActionsCommand() {
@@ -25355,7 +26352,7 @@ var init_actions = __esm({
25355
26352
 
25356
26353
  // src/data/commands/attachments.ts
25357
26354
  import { Command as Command2 } from "commander";
25358
- import { readFileSync as readFileSync20 } from "fs";
26355
+ import { readFileSync as readFileSync21 } from "fs";
25359
26356
  function findAttachmentByFilename(attachments, filename) {
25360
26357
  return attachments.find((a) => a.key.endsWith(`/${filename}`)) ?? null;
25361
26358
  }
@@ -25396,7 +26393,7 @@ function buildAttachmentsCommand() {
25396
26393
  printOutput(data, outputFormat(this));
25397
26394
  return;
25398
26395
  }
25399
- const body = readFileSync20(opts.file);
26396
+ const body = readFileSync21(opts.file);
25400
26397
  await client.upload(uploadPathFrom(data?.upload_url), body, opts.contentType);
25401
26398
  printOutput({ ...data, uploaded: true }, outputFormat(this));
25402
26399
  });
@@ -25876,16 +26873,16 @@ var init_providers = __esm({
25876
26873
 
25877
26874
  // src/data/commands/report.ts
25878
26875
  import { Command as Command6 } from "commander";
25879
- import { readFileSync as readFileSync21 } from "fs";
25880
- import { dirname as dirname9, join as join27 } from "path";
26876
+ import { readFileSync as readFileSync22 } from "fs";
26877
+ import { dirname as dirname11, join as join32 } from "path";
25881
26878
  import { fileURLToPath as fileURLToPath2 } from "url";
25882
26879
  function resolveCliVersion() {
25883
26880
  for (const candidate of [
25884
- join27(here, "..", "package.json"),
25885
- join27(here, "..", "..", "..", "package.json")
26881
+ join32(here, "..", "package.json"),
26882
+ join32(here, "..", "..", "..", "package.json")
25886
26883
  ]) {
25887
26884
  try {
25888
- const version = JSON.parse(readFileSync21(candidate, "utf-8")).version;
26885
+ const version = JSON.parse(readFileSync22(candidate, "utf-8")).version;
25889
26886
  if (typeof version === "string" && version) return version;
25890
26887
  } catch {
25891
26888
  }
@@ -26081,13 +27078,13 @@ var init_report2 = __esm({
26081
27078
  init_terminal_output();
26082
27079
  init_workspace();
26083
27080
  init_skill_version();
26084
- here = dirname9(fileURLToPath2(import.meta.url));
27081
+ here = dirname11(fileURLToPath2(import.meta.url));
26085
27082
  }
26086
27083
  });
26087
27084
 
26088
27085
  // src/data/commands/secrets.ts
26089
27086
  import { Command as Command7 } from "commander";
26090
- import { readFileSync as readFileSync22 } from "fs";
27087
+ import { readFileSync as readFileSync23 } from "fs";
26091
27088
  function withValueSourceOptions(cmd, what) {
26092
27089
  return cmd.option(
26093
27090
  "--file <path>",
@@ -26100,7 +27097,7 @@ async function resolveValue(opts, label) {
26100
27097
  throw expected("--file cannot be combined with --value-stdin or --value-prompt \u2014 pass one.");
26101
27098
  }
26102
27099
  try {
26103
- return readFileSync22(opts.file).toString("base64");
27100
+ return readFileSync23(opts.file).toString("base64");
26104
27101
  } catch (e) {
26105
27102
  throw expected(`--file ${opts.file}: ${e instanceof Error ? e.message : "could not be read"}`);
26106
27103
  }
@@ -26197,7 +27194,7 @@ var init_secrets = __esm({
26197
27194
 
26198
27195
  // src/data/commands/sql.ts
26199
27196
  import { Command as Command8 } from "commander";
26200
- import { readFileSync as readFileSync23 } from "fs";
27197
+ import { readFileSync as readFileSync24 } from "fs";
26201
27198
  function buildBasesSqlCommand() {
26202
27199
  return withBaseOption(new Command8("sql")).description("Execute a read-only SQL query against base data").argument("[query]", "SQL query (SELECT only)").option("--file <path>", "Read SQL from a file instead of the argument").option(
26203
27200
  "--param <kv...>",
@@ -26207,7 +27204,7 @@ function buildBasesSqlCommand() {
26207
27204
  let query;
26208
27205
  if (opts.file) {
26209
27206
  try {
26210
- query = readFileSync23(opts.file, "utf-8").trim();
27207
+ query = readFileSync24(opts.file, "utf-8").trim();
26211
27208
  } catch (e) {
26212
27209
  throw expected(`--file ${opts.file}: ${e instanceof Error ? e.message : "could not be read"}`);
26213
27210
  }
@@ -26342,16 +27339,16 @@ MCP URL: ${toolsetMcpUrl(slug)}`);
26342
27339
  ).option("--force", "Revoke even if the token appears to be in live use").action(async function(tokenId, opts) {
26343
27340
  const client = await createDataClient();
26344
27341
  const id = pathSegment(tokenId, "token id");
26345
- const path31 = (force) => `/v1/tokens/${id}${force ? "?force=true" : ""}`;
27342
+ const path36 = (force) => `/v1/tokens/${id}${force ? "?force=true" : ""}`;
26346
27343
  const format = outputFormat(this);
26347
27344
  const revoked = (forced) => printOutput({ token_id: tokenId, revoked: true, forced }, format);
26348
27345
  if (opts.force) {
26349
- await client.request("DELETE", path31(true));
27346
+ await client.request("DELETE", path36(true));
26350
27347
  revoked(true);
26351
27348
  return;
26352
27349
  }
26353
27350
  try {
26354
- await client.request("DELETE", path31(false));
27351
+ await client.request("DELETE", path36(false));
26355
27352
  revoked(false);
26356
27353
  } catch (err) {
26357
27354
  if (!(err instanceof ApiError) || err.status !== 409 || dataErrorDetails(err)?.requires_force !== true) {
@@ -26366,7 +27363,7 @@ MCP URL: ${toolsetMcpUrl(slug)}`);
26366
27363
  console.error("Aborted.");
26367
27364
  return process.exit(1);
26368
27365
  }
26369
- await client.request("DELETE", path31(true));
27366
+ await client.request("DELETE", path36(true));
26370
27367
  revoked(true);
26371
27368
  }
26372
27369
  });
@@ -26485,39 +27482,12 @@ Output:
26485
27482
  }
26486
27483
  });
26487
27484
 
26488
- // src/lib/base-binding.ts
26489
- var binding2, getBaseBindingPath, readBaseBinding, writeBaseBinding, clearBaseBinding, autoBindBaseIfUnbound, assertBaseMatchesBinding, assertNoBindingBlocksBaseCreation;
26490
- var init_base_binding = __esm({
26491
- "src/lib/base-binding.ts"() {
26492
- "use strict";
26493
- init_base_id();
26494
- init_worktree_binding();
26495
- binding2 = createWorktreeBinding({
26496
- filename: "wayai-base-binding",
26497
- isValidId: isValidBaseId,
26498
- noun: "base",
26499
- idLabel: "base id (must be a slug)",
26500
- unbindCommand: "wayai bases unbind",
26501
- useCommand: "wayai bases use"
26502
- });
26503
- getBaseBindingPath = binding2.getBindingPath;
26504
- readBaseBinding = binding2.readBinding;
26505
- writeBaseBinding = binding2.writeBinding;
26506
- clearBaseBinding = binding2.clearBinding;
26507
- autoBindBaseIfUnbound = binding2.autoBindIfUnbound;
26508
- assertBaseMatchesBinding = binding2.assertMatchesBinding;
26509
- assertNoBindingBlocksBaseCreation = binding2.assertNoBindingBlocksCreation;
26510
- }
26511
- });
26512
-
26513
27485
  // src/data/commands/bases.ts
26514
27486
  import { Command as Command10 } from "commander";
26515
- import * as fs24 from "fs";
26516
- import * as path30 from "path";
26517
- import * as yaml9 from "js-yaml";
26518
- function pageOf(path31, cursor) {
26519
- if (!cursor) return path31;
26520
- return `${path31}${path31.includes("?") ? "&" : "?"}cursor=${encodeURIComponent(cursor)}`;
27487
+ import * as path35 from "path";
27488
+ function pageOf(path36, cursor) {
27489
+ if (!cursor) return path36;
27490
+ return `${path36}${path36.includes("?") ? "&" : "?"}cursor=${encodeURIComponent(cursor)}`;
26521
27491
  }
26522
27492
  function parseEnum(flag, value, allowed) {
26523
27493
  if (value === void 0) return void 0;
@@ -26658,9 +27628,9 @@ function buildBasesCommand() {
26658
27628
  });
26659
27629
  bases.command("list-previews <origin-id>").description("List preview bases cloned from a base (production or preview)").action(async function(originId) {
26660
27630
  const client = await createDataClient();
26661
- const path31 = `/v1/${pathSegment(originId, "origin base id")}/previews`;
27631
+ const path36 = `/v1/${pathSegment(originId, "origin base id")}/previews`;
26662
27632
  printOutput(
26663
- await client.collectPages((cursor) => pageOf(path31, cursor)),
27633
+ await client.collectPages((cursor) => pageOf(path36, cursor)),
26664
27634
  outputFormat(this)
26665
27635
  );
26666
27636
  });
@@ -26693,9 +27663,9 @@ function buildBasesCommand() {
26693
27663
  });
26694
27664
  bases.command("promotions <production-id>").description("List promotion history for a production base").action(async function(productionId) {
26695
27665
  const client = await createDataClient();
26696
- const path31 = `/v1/${pathSegment(productionId, "production base id")}/promotions`;
27666
+ const path36 = `/v1/${pathSegment(productionId, "production base id")}/promotions`;
26697
27667
  printOutput(
26698
- await client.collectPages((cursor) => pageOf(path31, cursor)),
27668
+ await client.collectPages((cursor) => pageOf(path36, cursor)),
26699
27669
  outputFormat(this)
26700
27670
  );
26701
27671
  });
@@ -26745,19 +27715,11 @@ function buildBasesCommand() {
26745
27715
  }
26746
27716
  function resolveSelectorToBaseId(selector) {
26747
27717
  const gitRoot = findGitRoot();
26748
- if (!gitRoot || selector.includes("/") || selector.includes(path30.sep)) return selector;
27718
+ if (!gitRoot || selector.includes("/") || selector.includes(path35.sep)) return selector;
26749
27719
  if (!isValidBaseId(selector)) return selector;
26750
- const metaPath = path30.join(resolveBasesDir(gitRoot), selector, BASE_META_FILE);
26751
- let meta;
26752
- try {
26753
- meta = yaml9.load(fs24.readFileSync(metaPath, "utf-8"));
26754
- } catch {
26755
- return selector;
26756
- }
26757
- const id = meta?.[BASE_ID_FIELD];
27720
+ const id = readBaseMeta(path35.join(resolveBasesDir(gitRoot), selector))?.base_id;
26758
27721
  return typeof id === "string" && isValidBaseId(id) ? id : selector;
26759
27722
  }
26760
- var BASE_META_FILE, BASE_ID_FIELD;
26761
27723
  var init_bases = __esm({
26762
27724
  "src/data/commands/bases.ts"() {
26763
27725
  "use strict";
@@ -26775,11 +27737,10 @@ var init_bases = __esm({
26775
27737
  init_terminal_output();
26776
27738
  init_workspace();
26777
27739
  init_layout();
27740
+ init_base_workspace();
26778
27741
  init_base_binding();
26779
27742
  init_base_id();
26780
27743
  init_expected();
26781
- BASE_META_FILE = "base.yaml";
26782
- BASE_ID_FIELD = "base_id";
26783
27744
  }
26784
27745
  });
26785
27746
 
@@ -26844,7 +27805,7 @@ var init_file_types = __esm({
26844
27805
  // src/data/commands/files.ts
26845
27806
  import { Command as Command12 } from "commander";
26846
27807
  import { readFileSync as readFileSync25, writeFileSync as writeFileSync16 } from "fs";
26847
- import { basename as basename14 } from "path";
27808
+ import { basename as basename18 } from "path";
26848
27809
  function renderFileDiff(fileType, filePath, from, to, d) {
26849
27810
  console.log(sanitizeTerminalText(`${fileType}/${filePath}: v${from} \u2192 v${to}`));
26850
27811
  const md = d.metadata_delta;
@@ -26876,7 +27837,7 @@ function renderFileDiff(fileType, filePath, from, to, d) {
26876
27837
  }
26877
27838
  function downloadTarget(remotePath, to) {
26878
27839
  if (to) return to;
26879
- const derived = basename14(remotePath);
27840
+ const derived = basename18(remotePath);
26880
27841
  if (derived === "" || derived === "." || derived === "..") {
26881
27842
  throw expected(
26882
27843
  `Cannot derive a local filename from "${remotePath}" \u2014 pass --to <local> to name it.`
@@ -27252,8 +28213,8 @@ function buildRecordsCommand() {
27252
28213
  const body = { data: parseData(opts.data) };
27253
28214
  if (opts.externalId) body.external_id = opts.externalId;
27254
28215
  if (opts.externalSource) body.external_source = opts.externalSource;
27255
- const path31 = opts.id ? `/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${pathSegment(opts.id, "--id")}` : `/v1/${base}/records/${pathSegment(recordType2, "record_type")}`;
27256
- printOutput(await client.request("PUT", path31, body), outputFormat(this));
28216
+ const path36 = opts.id ? `/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${pathSegment(opts.id, "--id")}` : `/v1/${base}/records/${pathSegment(recordType2, "record_type")}`;
28217
+ printOutput(await client.request("PUT", path36, body), outputFormat(this));
27257
28218
  });
27258
28219
  records.command("query <record_type>").description("List/search records: exact filters + fuzzy `search`, sorting, pagination").option(
27259
28220
  "--external-source <source>",
@@ -27288,9 +28249,9 @@ function buildRecordsCommand() {
27288
28249
  ).action(async function(recordType2, id, opts) {
27289
28250
  const base = pathSegment(requireBase(this), "--base");
27290
28251
  const client = await createDataClient();
27291
- let path31 = `/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${recordKey(id, opts.externalSource)}`;
27292
- if (opts.externalSource) path31 += `?external_source=${encodeURIComponent(opts.externalSource)}`;
27293
- printOutput(await client.request("GET", path31), outputFormat(this));
28252
+ let path36 = `/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${recordKey(id, opts.externalSource)}`;
28253
+ if (opts.externalSource) path36 += `?external_source=${encodeURIComponent(opts.externalSource)}`;
28254
+ printOutput(await client.request("GET", path36), outputFormat(this));
27294
28255
  });
27295
28256
  records.command("delete <record_type> <id>").description(
27296
28257
  "Delete a record by internal ID, or by external_id (pass --external-source to scope it)"
@@ -27304,11 +28265,11 @@ function buildRecordsCommand() {
27304
28265
  }
27305
28266
  const base = pathSegment(requireBase(this), "--base");
27306
28267
  const client = await createDataClient();
27307
- let path31 = `/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${recordKey(id, opts.externalSource)}`;
28268
+ let path36 = `/v1/${base}/records/${pathSegment(recordType2, "record_type")}/${recordKey(id, opts.externalSource)}`;
27308
28269
  if (opts.externalSource) {
27309
- path31 += `?external_source=${encodeURIComponent(opts.externalSource)}&external_id=${encodeURIComponent(id)}`;
28270
+ path36 += `?external_source=${encodeURIComponent(opts.externalSource)}&external_id=${encodeURIComponent(id)}`;
27310
28271
  }
27311
- await client.request("DELETE", path31);
28272
+ await client.request("DELETE", path36);
27312
28273
  console.log("Deleted");
27313
28274
  });
27314
28275
  records.command("history <id>").description(
@@ -27473,8 +28434,8 @@ function buildRelationshipsCommand() {
27473
28434
  if (opts.data) body.data = parseData(opts.data);
27474
28435
  const base = pathSegment(requireBase(this), "--base");
27475
28436
  const client = await createDataClient();
27476
- const path31 = opts.id ? `/v1/${base}/relationships/${pathSegment(opts.id, "--id")}` : `/v1/${base}/relationships`;
27477
- printOutput(await client.request("PUT", path31, body), outputFormat(this));
28437
+ const path36 = opts.id ? `/v1/${base}/relationships/${pathSegment(opts.id, "--id")}` : `/v1/${base}/relationships`;
28438
+ printOutput(await client.request("PUT", path36, body), outputFormat(this));
27478
28439
  });
27479
28440
  relationships.command("get <id>").description(
27480
28441
  "Get a relationship by ID (or by its external key: pass the external_id with --rel-type)"
@@ -27707,8 +28668,8 @@ function buildToolsetsCommand() {
27707
28668
  toolsets.command("get <slug>").description("Get a toolset").option("--resolved", "Include resolved record_type schemas").action(async function(slug, opts) {
27708
28669
  const base = pathSegment(requireBase(this), "--base");
27709
28670
  const client = await createDataClient();
27710
- const path31 = opts.resolved ? `/v1/${base}/toolsets/${pathSegment(slug, "toolset slug")}/resolved` : `/v1/${base}/toolsets/${pathSegment(slug, "toolset slug")}`;
27711
- printOutput(await client.request("GET", path31), outputFormat(this));
28671
+ const path36 = opts.resolved ? `/v1/${base}/toolsets/${pathSegment(slug, "toolset slug")}/resolved` : `/v1/${base}/toolsets/${pathSegment(slug, "toolset slug")}`;
28672
+ printOutput(await client.request("GET", path36), outputFormat(this));
27712
28673
  });
27713
28674
  toolsets.command("list").description("List all toolsets").action(async function() {
27714
28675
  const base = pathSegment(requireBase(this), "--base");
@@ -27943,7 +28904,7 @@ init_utils();
27943
28904
  init_registry();
27944
28905
  import { readFileSync as readFileSync26 } from "fs";
27945
28906
  import { fileURLToPath as fileURLToPath3 } from "url";
27946
- import { dirname as dirname10, join as join29 } from "path";
28907
+ import { dirname as dirname12, join as join34 } from "path";
27947
28908
 
27948
28909
  // src/lib/version-refresh.ts
27949
28910
  init_version_cache();
@@ -27951,7 +28912,7 @@ init_skill_version();
27951
28912
  import { exec } from "child_process";
27952
28913
  var REFRESH_TIMEOUT_MS = 1e4;
27953
28914
  function refreshCliCache() {
27954
- return new Promise((resolve5) => {
28915
+ return new Promise((resolve7) => {
27955
28916
  exec("npm view @wayai/cli version", { timeout: REFRESH_TIMEOUT_MS }, (err, stdout) => {
27956
28917
  if (!err) {
27957
28918
  const latest = stdout.trim();
@@ -27962,7 +28923,7 @@ function refreshCliCache() {
27962
28923
  }
27963
28924
  }
27964
28925
  }
27965
- resolve5();
28926
+ resolve7();
27966
28927
  });
27967
28928
  });
27968
28929
  }
@@ -27988,8 +28949,8 @@ async function refreshSkillCache() {
27988
28949
  }
27989
28950
  async function refreshAdminSkillCache() {
27990
28951
  let timer;
27991
- const deadline = new Promise((resolve5) => {
27992
- timer = setTimeout(resolve5, REFRESH_TIMEOUT_MS);
28952
+ const deadline = new Promise((resolve7) => {
28953
+ timer = setTimeout(resolve7, REFRESH_TIMEOUT_MS);
27993
28954
  });
27994
28955
  await Promise.race([deadline, fetchAndCacheAdminSkillVersion().catch(() => {
27995
28956
  })]);
@@ -28098,8 +29059,8 @@ Run \`wayai admin skill install\` to update.`);
28098
29059
  }
28099
29060
 
28100
29061
  // src/index.ts
28101
- var __dirname = dirname10(fileURLToPath3(import.meta.url));
28102
- var pkg = JSON.parse(readFileSync26(join29(__dirname, "..", "package.json"), "utf-8"));
29062
+ var __dirname = dirname12(fileURLToPath3(import.meta.url));
29063
+ var pkg = JSON.parse(readFileSync26(join34(__dirname, "..", "package.json"), "utf-8"));
28103
29064
  var [, , command, ...args] = process.argv;
28104
29065
  var isBackgroundRefresh = command === REFRESH_COMMAND;
28105
29066
  if (!isBackgroundRefresh) initSentry(command, pkg.version);
@@ -28338,8 +29299,8 @@ Commands:
28338
29299
  create-credential Create an organization credential (API key, token, etc.)
28339
29300
  update-credential Update / rotate an organization credential (by name)
28340
29301
  set-connection-credential Set a connection's credential directly (org link or --field/--stdin), preview or production
28341
- pull Fetch hub config and write local files (also mirrors the linked production hub read-only)
28342
- push Parse local files, show diff, sync to preview (creates hub if new)
29302
+ pull Fetch config and write local files \u2014 \`hubs/<hub>\` or \`bases/<base>\` (also mirrors the linked production hub/base read-only)
29303
+ push Parse local files, show diff, sync to preview \u2014 \`hubs/<hub>\` or \`bases/<base>\` (creates the hub/base if new)
28343
29304
  create [folder] Explicitly create a new hub from an idless folder, then push (--label to name the preview)
28344
29305
  diff Dry-run diff of local files vs the platform (--production diffs vs the linked production hub)
28345
29306
  replicate Clone a hub into a new sibling preview (--label to name it)
@@ -28378,6 +29339,7 @@ ${await dataHelpBlock()}
28378
29339
  Flags:
28379
29340
  --yes, -y Skip confirmation prompts (useful for CI and scripting)
28380
29341
  --hub <uuid|name> Target hub when the workspace has more than one (push, pull, diff, replicate, relabel, publish)
29342
+ --base <id|name> Target base for pull/push \u2014 routes the invocation to the \`bases/\` subtree (never combined with --hub)
28381
29343
  --production Diff local preview files against the linked production hub (diff)
28382
29344
  --label <name> Preview label \u2014 for the new sibling (replicate) or a brand-new hub (create, or push on create)
28383
29345
  --clear Remove the preview label (relabel)