@erdoai/cli 0.117.0 → 0.118.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.
- package/dist/index.js +88 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1149,6 +1149,13 @@ var ErdoClient = class {
|
|
|
1149
1149
|
const qs = q.toString();
|
|
1150
1150
|
return this.request("GET", `/v1/datasets-purposes${qs ? `?${qs}` : ""}`);
|
|
1151
1151
|
}
|
|
1152
|
+
// Reads the declared write contract through the slug-addressed fetch route's
|
|
1153
|
+
// declared_schema view. That route is the one a dataset-scoped API key can
|
|
1154
|
+
// reach (and is confined to its own datasets there); the dataset-details
|
|
1155
|
+
// route is not, because its response also names other datasets.
|
|
1156
|
+
getDatasetDeclaredSchema(slug) {
|
|
1157
|
+
return this.request("POST", `/v1/datasets/${encodeURIComponent(slug)}/fetch`, { view: "declared_schema" });
|
|
1158
|
+
}
|
|
1152
1159
|
// Create an empty dataset with its declared columns. The server refuses a
|
|
1153
1160
|
// create without a schema unless the purpose's columns are platform-defined.
|
|
1154
1161
|
createDataset(input) {
|
|
@@ -1583,6 +1590,15 @@ var ErdoClient = class {
|
|
|
1583
1590
|
);
|
|
1584
1591
|
}
|
|
1585
1592
|
// --- knowledge ---
|
|
1593
|
+
getKnowledge(id) {
|
|
1594
|
+
return this.request("GET", `/v1/knowledge/${encodeURIComponent(id)}`);
|
|
1595
|
+
}
|
|
1596
|
+
updateKnowledge(id, input) {
|
|
1597
|
+
return this.request("POST", `/v1/knowledge/${encodeURIComponent(id)}/actions`, {
|
|
1598
|
+
action: "update",
|
|
1599
|
+
...input
|
|
1600
|
+
});
|
|
1601
|
+
}
|
|
1586
1602
|
listKnowledge(visibility, options) {
|
|
1587
1603
|
const params = new URLSearchParams();
|
|
1588
1604
|
if (visibility) params.set("visibility", visibility);
|
|
@@ -1719,6 +1735,7 @@ var ErdoClient = class {
|
|
|
1719
1735
|
// what the evidence said afterwards. Referenced by slug, never UUID.
|
|
1720
1736
|
listDecisions(opts) {
|
|
1721
1737
|
const params = new URLSearchParams();
|
|
1738
|
+
if (opts.organization_slug) params.set("organization_slug", opts.organization_slug);
|
|
1722
1739
|
if (opts.workstream_slug) params.set("workstream_slug", opts.workstream_slug);
|
|
1723
1740
|
if (opts.source) params.set("source", opts.source);
|
|
1724
1741
|
if (opts.decision_class) params.set("decision_class", opts.decision_class);
|
|
@@ -4254,7 +4271,7 @@ function renderReportEffect(e) {
|
|
|
4254
4271
|
console.log(` outcome: ${e.outcome_label}`);
|
|
4255
4272
|
}
|
|
4256
4273
|
}
|
|
4257
|
-
decisionsCmd.command("list").description("List decisions, newest first").option("--workstream <slug>", "only decisions filed under this workstream/Strategy").option(
|
|
4274
|
+
decisionsCmd.command("list").description("List decisions, newest first").option("--organization <slug>", "read an authorized client organization (default: active organization)").option("--workstream <slug>", "only decisions filed under this workstream/Strategy").option(
|
|
4258
4275
|
"--source <source>",
|
|
4259
4276
|
"producer family: approval | escalation | engine_gate | allocator | experiment | workstream_commitment"
|
|
4260
4277
|
).option("--class <class>", "decision class, e.g. paid_media.ad_group.pause").option("--subject-kind <kind>", "only decisions about this kind of subject").option("--subject-ref <id>", "only decisions about this exact subject").option(
|
|
@@ -4267,6 +4284,7 @@ decisionsCmd.command("list").description("List decisions, newest first").option(
|
|
|
4267
4284
|
async (opts) => {
|
|
4268
4285
|
try {
|
|
4269
4286
|
const res = await new ErdoClient().listDecisions({
|
|
4287
|
+
organization_slug: opts.organization,
|
|
4270
4288
|
workstream_slug: opts.workstream,
|
|
4271
4289
|
source: opts.source,
|
|
4272
4290
|
decision_class: opts.class,
|
|
@@ -6747,10 +6765,36 @@ Read one with: erdo datasets fetch ${res.dataset_slug} --revision <id> --sql "SE
|
|
|
6747
6765
|
}
|
|
6748
6766
|
});
|
|
6749
6767
|
datasetsCmd.command("schema <slug>").alias("describe").description(
|
|
6750
|
-
"Show
|
|
6751
|
-
).option("--json", "print the raw JSON result instead of a table").action(async (slug, opts) => {
|
|
6768
|
+
"Show physical columns by default, or the declared write contract with --declared. Physical columns are the names and types you can reference in `datasets fetch --sql`, read from the stored `data` table itself (DuckDB DESCRIBE) so they are what is actually there, not what was declared. For a database or warehouse dataset, DESCRIBE its real table names instead: `datasets fetch <slug> --sql 'DESCRIBE <table>'`."
|
|
6769
|
+
).option("--json", "print the raw JSON result instead of a table").option("--declared", "read the declared write contract (column names, type hints, required flags, semantic roles) instead of the physical columns").action(async (slug, opts) => {
|
|
6752
6770
|
try {
|
|
6753
|
-
const
|
|
6771
|
+
const client = new ErdoClient();
|
|
6772
|
+
if (opts.declared) {
|
|
6773
|
+
const res2 = await client.getDatasetDeclaredSchema(slug);
|
|
6774
|
+
if (!res2 || typeof res2 !== "object" || res2.view !== "declared_schema")
|
|
6775
|
+
throw new Error("Invalid dataset schema response: the server did not answer the declared_schema view");
|
|
6776
|
+
const schema = res2.declared_schema;
|
|
6777
|
+
if (schema != null && (!Array.isArray(schema.columns) || schema.columns.some((column) => !column || typeof column.name !== "string" || !column.name.trim())))
|
|
6778
|
+
throw new Error("Invalid dataset schema response: declared columns are malformed");
|
|
6779
|
+
if (opts.json) {
|
|
6780
|
+
print(res2);
|
|
6781
|
+
return;
|
|
6782
|
+
}
|
|
6783
|
+
if (schema == null) {
|
|
6784
|
+
console.log(`${slug} has no declared column contract. Use datasets schema ${slug} to inspect physical columns.`);
|
|
6785
|
+
return;
|
|
6786
|
+
}
|
|
6787
|
+
if (!schema.columns.length) {
|
|
6788
|
+
console.log(`${slug}'s declared column contract contains no columns.`);
|
|
6789
|
+
return;
|
|
6790
|
+
}
|
|
6791
|
+
printAlignedTable(
|
|
6792
|
+
["column", "type", "required", "semantic role", "description"],
|
|
6793
|
+
schema.columns.map((column) => [column.name, column.type || "", column.required ? "yes" : "no", column.semantic_role || "", column.description || ""])
|
|
6794
|
+
);
|
|
6795
|
+
return;
|
|
6796
|
+
}
|
|
6797
|
+
const res = await client.fetchDatasetContents(slug, { sql_query: "DESCRIBE data" });
|
|
6754
6798
|
if (opts.json) {
|
|
6755
6799
|
print(res);
|
|
6756
6800
|
return;
|
|
@@ -8050,7 +8094,7 @@ pipelinesCmd.command("get <slug>").description("Show one event pipeline \u2014 s
|
|
|
8050
8094
|
});
|
|
8051
8095
|
pipelinesCmd.command("update <slug>").description(
|
|
8052
8096
|
"Update an event pipeline's editable fields \u2014 omitted fields keep their current values (merge). Use get first for the current transform/actions; --transform-js/--pipeline accept @file"
|
|
8053
|
-
).option("--name <name>", "new name").option("--description <description>", "new description").option("--state <state>", "new state: active, disabled, or proposed").option("--transform-js <jsOr@file>", "new transform \u2014 function transform(event) { \u2026 } (or @path to a file)").option("--turnstile <jsonOr@file>", `optional managed form protection settings; use @file for widget credentials, or '{"enabled":false}' to disable`).option(
|
|
8097
|
+
).option("--sample-payload <jsonOr@file>", "complete representative event used to validate and initialize target contracts; JSON or @path").option("--name <name>", "new name").option("--description <description>", "new description").option("--state <state>", "new state: active, disabled, or proposed").option("--transform-js <jsOr@file>", "new transform \u2014 function transform(event) { \u2026 } (or @path to a file)").option("--turnstile <jsonOr@file>", `optional managed form protection settings; use @file for widget credentials, or '{"enabled":false}' to disable`).option(
|
|
8054
8098
|
"--pipeline <jsonOr@file>",
|
|
8055
8099
|
`replacement ordered actions array as JSON (or @path to a file), e.g. '[{"type":"dataset.write","key_column":"email","dataset_slug":"acme-leads"}]'`
|
|
8056
8100
|
).action(
|
|
@@ -8083,10 +8127,18 @@ pipelinesCmd.command("update <slug>").description(
|
|
|
8083
8127
|
fail(new Error(`--pipeline must be a JSON array of actions: ${e instanceof Error ? e.message : String(e)}`));
|
|
8084
8128
|
}
|
|
8085
8129
|
}
|
|
8130
|
+
const sampleRaw = readMaybeFile(opts.samplePayload);
|
|
8131
|
+
if (sampleRaw !== void 0) {
|
|
8132
|
+
try {
|
|
8133
|
+
body.sample_payload = JSON.parse(sampleRaw);
|
|
8134
|
+
} catch {
|
|
8135
|
+
fail(new Error("--sample-payload must be valid JSON"));
|
|
8136
|
+
}
|
|
8137
|
+
}
|
|
8086
8138
|
if (Object.keys(body).length === 0) {
|
|
8087
8139
|
fail(
|
|
8088
8140
|
new Error(
|
|
8089
|
-
"nothing to update \u2014 pass at least one of --name, --description, --state, --transform-js, --pipeline, --turnstile"
|
|
8141
|
+
"nothing to update \u2014 pass at least one of --name, --description, --state, --transform-js, --pipeline, --turnstile, --sample-payload"
|
|
8090
8142
|
)
|
|
8091
8143
|
);
|
|
8092
8144
|
}
|
|
@@ -8134,6 +8186,36 @@ pipelinesCmd.command("executions <slug>").description("Show an event pipeline's
|
|
|
8134
8186
|
}
|
|
8135
8187
|
});
|
|
8136
8188
|
var knowledgeCmd = program.command("knowledge").description("Knowledge objects");
|
|
8189
|
+
knowledgeCmd.command("get <id>").description("Get one full typed Knowledge object, including links and related objects").action(async (id) => {
|
|
8190
|
+
try {
|
|
8191
|
+
print(await new ErdoClient().getKnowledge(id));
|
|
8192
|
+
} catch (e) {
|
|
8193
|
+
fail(e);
|
|
8194
|
+
}
|
|
8195
|
+
});
|
|
8196
|
+
knowledgeCmd.command("update <id>").description("Update a Knowledge object while preserving fields omitted from the command").option("--body <value>", "new body text, or @file; pass an empty value to clear the body").option("--config <file>", "JSON object file containing the complete replacement config, or @file").option("--title <title>", "new title").action(async (id, opts) => {
|
|
8197
|
+
try {
|
|
8198
|
+
if (opts.title === void 0 && opts.body === void 0 && opts.config === void 0) {
|
|
8199
|
+
throw new Error("provide at least one of --title, --body, or --config");
|
|
8200
|
+
}
|
|
8201
|
+
if (opts.title !== void 0 && !opts.title.trim()) {
|
|
8202
|
+
throw new Error("title must not be empty");
|
|
8203
|
+
}
|
|
8204
|
+
const replacementConfig = opts.config === void 0 ? void 0 : readJSONObject(opts.config.startsWith("@") ? opts.config.slice(1) : opts.config, "--config");
|
|
8205
|
+
const replacementBody = opts.body === void 0 ? void 0 : readMaybeFile(opts.body) ?? "";
|
|
8206
|
+
const client = new ErdoClient();
|
|
8207
|
+
const current = await client.getKnowledge(id);
|
|
8208
|
+
const object = current.object;
|
|
8209
|
+
print(await client.updateKnowledge(id, {
|
|
8210
|
+
title: opts.title ?? object.title,
|
|
8211
|
+
body_markdown: replacementBody ?? object.body_markdown,
|
|
8212
|
+
config_json: replacementConfig ?? object.config_json,
|
|
8213
|
+
expected_updated_at: object.updated_at
|
|
8214
|
+
}));
|
|
8215
|
+
} catch (e) {
|
|
8216
|
+
fail(e);
|
|
8217
|
+
}
|
|
8218
|
+
});
|
|
8137
8219
|
knowledgeCmd.command("list").description("List knowledge objects").option(
|
|
8138
8220
|
"--public",
|
|
8139
8221
|
"only entries opted into anonymous external surfaces (website widgets)"
|