@wayai/cli 0.3.148 → 0.3.150

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
@@ -18503,13 +18503,20 @@ var init_terminal_output = __esm({
18503
18503
 
18504
18504
  // src/lib/base-id.ts
18505
18505
  function isValidBaseId(id) {
18506
- return BASE_ID_RE.test(id);
18506
+ return id.length > 0 && id.length <= BASE_ID_MAX_LENGTH && BASE_ID_RE.test(id);
18507
18507
  }
18508
- var BASE_ID_RE;
18508
+ function isPathSafeId(id) {
18509
+ return PATH_SAFE_ID_RE.test(id);
18510
+ }
18511
+ var BASE_ID_MAX_LENGTH, BASE_ID_RE, BASE_ID_RULE, PATH_SAFE_ID_RE, PATH_SAFE_ID_RULE;
18509
18512
  var init_base_id = __esm({
18510
18513
  "src/lib/base-id.ts"() {
18511
18514
  "use strict";
18512
- BASE_ID_RE = /^(?!\.\.?$)[A-Za-z0-9._-]{1,256}$/;
18515
+ BASE_ID_MAX_LENGTH = 128;
18516
+ BASE_ID_RE = /^[A-Za-z0-9_][A-Za-z0-9_-]*$/;
18517
+ BASE_ID_RULE = `letters, digits, \`-\` and \`_\`, starting with a letter, digit or \`_\`, ${BASE_ID_MAX_LENGTH} characters or fewer`;
18518
+ PATH_SAFE_ID_RE = /^(?!\.\.?$)[A-Za-z0-9._-]{1,256}$/;
18519
+ PATH_SAFE_ID_RULE = "letters, digits, dot, dash and underscore, with no path separators, not `.` or `..` alone, 256 characters or fewer";
18513
18520
  }
18514
18521
  });
18515
18522
 
@@ -18572,9 +18579,9 @@ function folderForSelector(basesDir, selector) {
18572
18579
  return path17.join(basesDir, selector);
18573
18580
  }
18574
18581
  function assertValidBaseSelector(selector, source = "base") {
18575
- if (!isValidBaseId(selector)) {
18582
+ if (!isPathSafeId(selector)) {
18576
18583
  throw expected(
18577
- `Invalid ${source} "${selector}". Base ids are slugs \u2014 letters, digits, dot, dash and underscore only, with no path separators.`
18584
+ `Invalid ${source} "${selector}". A base selector is one folder name \u2014 ${PATH_SAFE_ID_RULE}.`
18578
18585
  );
18579
18586
  }
18580
18587
  }
@@ -18942,9 +18949,16 @@ var init_base_binding = __esm({
18942
18949
  init_worktree_binding();
18943
18950
  binding2 = createWorktreeBinding({
18944
18951
  filename: "wayai-base-binding",
18945
- isValidId: isValidBaseId,
18952
+ // `isPathSafeId`, not the API's base-id rule. The tripwire's duty is that a
18953
+ // garbled or multi-line file read as unbound, which this grammar delivers;
18954
+ // applying the mint rule instead would refuse to bind a base whose stored id
18955
+ // predates it — a base the API still serves — and so lock the CLI out of the
18956
+ // one workflow that could migrate off it.
18957
+ isValidId: isPathSafeId,
18946
18958
  noun: "base",
18947
- idLabel: "base id (must be a slug)",
18959
+ // States what is actually checked. "must be a slug" described no rule the
18960
+ // reader could act on, and naming the API's rule here would name the wrong one.
18961
+ idLabel: `base id (${PATH_SAFE_ID_RULE})`,
18948
18962
  unbindCommand: "wayai bases unbind",
18949
18963
  useCommand: "wayai bases use"
18950
18964
  });
@@ -18961,10 +18975,14 @@ var init_base_binding = __esm({
18961
18975
  // src/data/helpers.ts
18962
18976
  import { readFileSync as readFileSync16 } from "fs";
18963
18977
  function pathSegment(id, label = "id") {
18978
+ if (!isPathSafeId(id)) {
18979
+ throw expected(`Invalid ${label}: ${JSON.stringify(id)}. An id may use ${PATH_SAFE_ID_RULE}.`);
18980
+ }
18981
+ return encodeURIComponent(id);
18982
+ }
18983
+ function basePathSegment(id, label = "base id") {
18964
18984
  if (!isValidBaseId(id)) {
18965
- throw expected(
18966
- `Invalid ${label}: ${JSON.stringify(id)}. Ids are slugs \u2014 letters, digits, dot, dash and underscore only.`
18967
- );
18985
+ throw expected(`Invalid ${label}: ${JSON.stringify(id)}. Base ids are slugs \u2014 ${BASE_ID_RULE}.`);
18968
18986
  }
18969
18987
  return encodeURIComponent(id);
18970
18988
  }
@@ -19178,7 +19196,7 @@ function writeBaseFolder(folder, meta, config) {
19178
19196
  for (const raw of entities) {
19179
19197
  const entity = raw;
19180
19198
  const id = String(entity.id);
19181
- if (!isValidBaseId(id)) {
19199
+ if (!isPathSafeId(id)) {
19182
19200
  console.warn(` Warning: skipping ${kind} entity with unusable id ${JSON.stringify(id)}.`);
19183
19201
  continue;
19184
19202
  }
@@ -19502,7 +19520,7 @@ function requireGitRoot(gitRoot) {
19502
19520
  return gitRoot;
19503
19521
  }
19504
19522
  async function writeProductionMirror(client, basesDir, prodId, record) {
19505
- if (!isValidBaseId(prodId)) {
19523
+ if (!isPathSafeId(prodId)) {
19506
19524
  throw expected(`Refusing to mirror base ${JSON.stringify(prodId)}: not a usable base id.`);
19507
19525
  }
19508
19526
  const config = await getConfig(client, prodId);
@@ -28135,18 +28153,19 @@ function buildBasesCommand() {
28135
28153
  "Default IANA timezone for datetime canonicalization (e.g. America/Sao_Paulo); a record type's own timezone overrides it"
28136
28154
  ).option(
28137
28155
  "--environment <env>",
28138
- "production (default) | preview. Fixed at creation, and no id can change environment later. For a base you intend to keep, take the default so the durable id belongs to production, then get a linked preview with create-preview and promote from it. Pass preview only for an ephemeral or eval base under a derived id: a preview created here has no production origin, cannot be given one later, and so can never be promoted directly"
28156
+ "production (default) | preview. Fixed for the life of a base and not changeable on one that exists \u2014 but not welded to the id: once a base is permanently deleted and that deletion completes, the id is free and can be created again in either environment, so a preview you prototyped on can become the production base under the same slug. For a base you intend to keep, take the default so the durable id belongs to production, then get a linked preview with create-preview and promote from it. Pass preview for an ephemeral or eval base under a derived id: a preview created here has no production origin, cannot be given one later, and so can never be promoted directly"
28139
28157
  ).action(async function(id, opts) {
28140
28158
  const environment = parseEnum("--environment", opts.environment, [
28141
28159
  "production",
28142
28160
  "preview"
28143
28161
  ]);
28162
+ const target = basePathSegment(id);
28144
28163
  const client = await createDataClient();
28145
28164
  const body = { name: opts.name, description: opts.description };
28146
28165
  if (environment) body.environment = environment;
28147
28166
  if (opts.tags) body.tags = await resolveBaseTags(opts.tags, client);
28148
28167
  if (opts.timezone) body.settings = { timezone: opts.timezone };
28149
- printOutput(await client.request("PUT", `/v1/bases/${pathSegment(id)}`, body), outputFormat(this));
28168
+ printOutput(await client.request("PUT", `/v1/bases/${target}`, body), outputFormat(this));
28150
28169
  });
28151
28170
  bases.command("update <id>").description(
28152
28171
  "Update a base's mutable config (display name, description, tags, default timezone/settings). The id/slug is immutable."
@@ -28169,6 +28188,7 @@ function buildBasesCommand() {
28169
28188
  "Nothing to update. Provide at least one of --name, --description, --tags, --timezone, --settings, --integrations."
28170
28189
  );
28171
28190
  }
28191
+ const target = basePathSegment(id);
28172
28192
  const client = await createDataClient();
28173
28193
  const body = {};
28174
28194
  if (opts.name !== void 0) body.name = opts.name;
@@ -28189,20 +28209,21 @@ function buildBasesCommand() {
28189
28209
  }
28190
28210
  settings = parsed;
28191
28211
  } else {
28192
- const existing = await client.request("GET", `/v1/bases/${pathSegment(id)}`);
28212
+ const existing = await client.request("GET", `/v1/bases/${target}`);
28193
28213
  settings = { ...existing?.settings ?? {} };
28194
28214
  }
28195
28215
  if (opts.timezone !== void 0) settings.timezone = opts.timezone;
28196
28216
  body.settings = settings;
28197
28217
  }
28198
- printOutput(await client.request("PUT", `/v1/bases/${pathSegment(id)}`, body), outputFormat(this));
28218
+ printOutput(await client.request("PUT", `/v1/bases/${target}`, body), outputFormat(this));
28199
28219
  });
28200
28220
  bases.command("rename <id>").description(
28201
28221
  "Rename a base's display name (the id/slug is immutable \u2014 it scopes token grants, MCP endpoints, and references)"
28202
28222
  ).requiredOption("--name <name>", "New display name").action(async function(id, opts) {
28223
+ const target = basePathSegment(id);
28203
28224
  const client = await createDataClient();
28204
28225
  printOutput(
28205
- await client.request("PUT", `/v1/bases/${pathSegment(id)}`, { name: opts.name }),
28226
+ await client.request("PUT", `/v1/bases/${target}`, { name: opts.name }),
28206
28227
  outputFormat(this)
28207
28228
  );
28208
28229
  });
@@ -28210,10 +28231,11 @@ function buildBasesCommand() {
28210
28231
  "--tags <tags>",
28211
28232
  "Comma-separated organization tag names (e.g. clinica-medica,billing). An empty value clears them"
28212
28233
  ).action(async function(id, opts) {
28234
+ const target = basePathSegment(id);
28213
28235
  const client = await createDataClient();
28214
28236
  const tags = await resolveBaseTags(opts.tags, client);
28215
28237
  printOutput(
28216
- await client.request("PUT", `/v1/bases/${pathSegment(id)}`, { tags }),
28238
+ await client.request("PUT", `/v1/bases/${target}`, { tags }),
28217
28239
  outputFormat(this)
28218
28240
  );
28219
28241
  });
@@ -28244,6 +28266,11 @@ function buildBasesCommand() {
28244
28266
  const integrations = parseEnum("--integrations", opts.integrations, ["enabled", "disabled"]);
28245
28267
  const client = await createDataClient();
28246
28268
  printOutput(
28269
+ // `pathSegment`, not `basePathSegment`: the id at fault here is the
28270
+ // ORIGIN's, which is immutable and not the caller's to re-spell. The API's
28271
+ // `assertDerivablePreviewId` answers that case with the remedy instead of
28272
+ // the charset, and refusing locally would replace it with a rule the
28273
+ // caller cannot act on.
28247
28274
  await client.request("POST", `/v1/${pathSegment(originId, "origin base id")}/preview`, {
28248
28275
  name: opts.name,
28249
28276
  description: opts.description,
@@ -28357,9 +28384,9 @@ function buildBasesCommand() {
28357
28384
  function resolveSelectorToBaseId(selector) {
28358
28385
  const gitRoot = findGitRoot();
28359
28386
  if (!gitRoot || selector.includes("/") || selector.includes(path35.sep)) return selector;
28360
- if (!isValidBaseId(selector)) return selector;
28387
+ if (!isPathSafeId(selector)) return selector;
28361
28388
  const id = readBaseMeta(path35.join(resolveBasesDir(gitRoot), selector))?.base_id;
28362
- return typeof id === "string" && isValidBaseId(id) ? id : selector;
28389
+ return typeof id === "string" && isPathSafeId(id) ? id : selector;
28363
28390
  }
28364
28391
  var init_bases = __esm({
28365
28392
  "src/data/commands/bases.ts"() {