@erdoai/cli 0.100.0 → 0.101.0

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.
Files changed (2) hide show
  1. package/dist/index.js +32 -5
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1072,17 +1072,20 @@ var ErdoClient = class {
1072
1072
  const qs = q.toString();
1073
1073
  return this.request("GET", `/v1/datasets${qs ? `?${qs}` : ""}`);
1074
1074
  }
1075
- // The org's dataset vocabulary: every purpose in use, its description, and
1076
- // the dataset that established it (the canonical write target for that role).
1075
+ // The org's dataset vocabulary: every purpose in use, its current dataset,
1076
+ // and the declared producer contract on that same dataset.
1077
1077
  // scope="managed" reads the same across every client organization a manager
1078
1078
  // account operates; each entry then names its organization and its
1079
- // established_by slug is org-qualified, so it can be queried as-is.
1079
+ // current dataset slug is org-qualified, so it can be queried as-is.
1080
1080
  listDatasetPurposes(params) {
1081
1081
  const q = new URLSearchParams();
1082
1082
  if (params?.scope) q.set("scope", params.scope);
1083
1083
  const qs = q.toString();
1084
1084
  return this.request("GET", `/v1/datasets-purposes${qs ? `?${qs}` : ""}`);
1085
1085
  }
1086
+ ensureDataset(input) {
1087
+ return this.request("POST", "/v1/datasets-ensure", input);
1088
+ }
1086
1089
  // Correct which dataset carries a purpose. Pass `purpose` to set one,
1087
1090
  // `clear_purpose` to remove it; moving a purpose is clearing it from the old
1088
1091
  // dataset and setting it on the right one. Setting a purpose the org already
@@ -6097,7 +6100,7 @@ datasetsCmd.command("list").description("List datasets").option(
6097
6100
  }
6098
6101
  });
6099
6102
  datasetsCmd.command("purposes").description(
6100
- "List the org's dataset purposes \u2014 the vocabulary of dataset roles in use (e.g. leads, page events). The established_by slug is the canonical dataset for that role: write there rather than creating a sibling (one purpose = one dataset per org)."
6103
+ "List the org's dataset purposes \u2014 the vocabulary of dataset roles in use (e.g. leads, page events). Each purpose resolves to the current dataset and its declared schema: write there rather than creating a sibling (one purpose = one dataset per org)."
6101
6104
  ).option(
6102
6105
  "--scope <own|managed>",
6103
6106
  "whose vocabulary to read: own (default) or managed, which reads every client organization a manager account operates and prints the organization alongside each purpose"
@@ -6114,7 +6117,7 @@ datasetsCmd.command("purposes").description(
6114
6117
  return;
6115
6118
  }
6116
6119
  for (const p of purposes) {
6117
- const target = p.established_by_dataset_slug ?? p.established_by_dataset_id;
6120
+ const target = p.dataset_count > 1 ? `(split: ${p.dataset_count} datasets)` : p.dataset_slug ?? p.dataset_id ?? "(unbound)";
6118
6121
  const count = `${p.dataset_count} dataset${p.dataset_count === 1 ? "" : "s"}`;
6119
6122
  console.log(
6120
6123
  scope === "managed" ? `${p.organization_slug ?? "-"} ${p.purpose} ${target} ${count} ${p.description}` : `${p.purpose} ${target} ${count} ${p.description}`
@@ -6124,6 +6127,30 @@ datasetsCmd.command("purposes").description(
6124
6127
  fail(e);
6125
6128
  }
6126
6129
  });
6130
+ datasetsCmd.command("ensure <purpose>").description(
6131
+ "Create or reuse the one dataset for a purpose and verify its declared producer contract. Refuses legacy splits and incompatible populated datasets instead of choosing silently."
6132
+ ).requiredOption("--schema <file>", "JSON file containing { columns: [...] } or a columns array").option("--name <name>", "dataset name when creation is required").option("--description <text>", "dataset description when creation is required").option("--purpose-description <text>", "what writes and reads this purpose").option("--preferred-dataset <slug>", "existing bound dataset slug or id to adopt").option("--email-column <name>", "for a leads purpose: which declared column holds the email (default email)").option("--phone-column <name>", "for a leads purpose: which declared column holds the phone (default phone)").action(async (purpose, opts) => {
6133
+ try {
6134
+ const parsed = JSON.parse(readFileSync4(opts.schema, "utf8"));
6135
+ const declaredSchema = Array.isArray(parsed) ? { columns: parsed } : parsed;
6136
+ if (!declaredSchema || !Array.isArray(declaredSchema.columns)) {
6137
+ throw new Error('--schema must contain a JSON columns array or {"columns": [...]} object');
6138
+ }
6139
+ const result = await new ErdoClient().ensureDataset({
6140
+ purpose,
6141
+ ...opts.name ? { name: opts.name } : {},
6142
+ ...opts.description ? { description: opts.description } : {},
6143
+ ...opts.purposeDescription ? { purpose_description: opts.purposeDescription } : {},
6144
+ ...opts.preferredDataset ? { preferred_dataset: opts.preferredDataset } : {},
6145
+ ...opts.emailColumn ? { email_column: opts.emailColumn } : {},
6146
+ ...opts.phoneColumn ? { phone_column: opts.phoneColumn } : {},
6147
+ declared_schema: declaredSchema
6148
+ });
6149
+ console.log(`${result.slug} ${result.created ? "created" : "reused"} ${result.purpose}`);
6150
+ } catch (e) {
6151
+ fail(e);
6152
+ }
6153
+ });
6127
6154
  datasetsCmd.command("set-purpose <slug> [purpose]").description(
6128
6155
  "Set (or with --clear, remove) the dataset's purpose \u2014 the org-vocabulary role `datasets purposes` reports. Use it to CORRECT a purpose that names the wrong dataset: one purpose maps to one dataset per org, so a purpose left on the wrong one points everything that resolves through the vocabulary at the wrong rows. Moving a purpose is two calls \u2014 clear it from the old dataset, set it on the right one. Setting a purpose the org already uses elsewhere succeeds and prints a warning naming what it now shadows."
6129
6156
  ).option("--clear", "remove the dataset's purpose instead of setting one").option(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@erdoai/cli",
3
- "version": "0.100.0",
3
+ "version": "0.101.0",
4
4
  "description": "Erdo CLI — drive datasets, pages, and evals from the terminal or CI",
5
5
  "type": "module",
6
6
  "bin": {