dataiku-sdk 3.6.1 → 3.8.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/README.md +14 -6
- package/bin/bun-version.js +14 -0
- package/bin/dss.js +11 -15
- package/dist/build-metadata.json +1 -1
- package/dist/packages/types/src/index.d.ts +114 -5
- package/dist/packages/types/src/index.js +75 -2
- package/dist/src/cli/coerce.d.ts +2 -0
- package/dist/src/cli/coerce.js +20 -16
- package/dist/src/cli/command-syntax.json +3369 -144
- package/dist/src/cli/commands/analysis.js +19 -1
- package/dist/src/cli/commands/bundle.js +22 -0
- package/dist/src/cli/commands/connection.js +26 -2
- package/dist/src/cli/commands/data-quality.js +33 -1
- package/dist/src/cli/commands/dataset.js +76 -9
- package/dist/src/cli/commands/discussion.js +15 -0
- package/dist/src/cli/commands/doctor.js +1 -1
- package/dist/src/cli/commands/flow-zone.js +241 -46
- package/dist/src/cli/commands/flow.d.ts +5 -0
- package/dist/src/cli/commands/flow.js +57 -0
- package/dist/src/cli/commands/future.js +8 -0
- package/dist/src/cli/commands/index.js +6 -0
- package/dist/src/cli/commands/job.js +44 -6
- package/dist/src/cli/commands/metrics.js +21 -1
- package/dist/src/cli/commands/ml-task.d.ts +5 -0
- package/dist/src/cli/commands/ml-task.js +86 -16
- package/dist/src/cli/commands/mlflow.d.ts +11 -0
- package/dist/src/cli/commands/mlflow.js +121 -0
- package/dist/src/cli/commands/plugin.js +5 -11
- package/dist/src/cli/commands/project-deployer.js +70 -0
- package/dist/src/cli/commands/project-library.js +2 -5
- package/dist/src/cli/commands/project.js +8 -0
- package/dist/src/cli/commands/recipe.d.ts +13 -0
- package/dist/src/cli/commands/recipe.js +130 -7
- package/dist/src/cli/commands/saved-model.d.ts +1 -1
- package/dist/src/cli/commands/saved-model.js +9 -76
- package/dist/src/cli/commands/streaming-endpoint.js +30 -1
- package/dist/src/cli/commands/webapp.js +8 -0
- package/dist/src/cli/commands/wiki.js +78 -0
- package/dist/src/cli/commands/workspace.js +8 -0
- package/dist/src/cli/contract.d.ts +16 -15
- package/dist/src/cli/contract.js +150 -3407
- package/dist/src/cli/doctor.d.ts +13 -0
- package/dist/src/cli/doctor.js +43 -1
- package/dist/src/cli/flags.d.ts +14 -1
- package/dist/src/cli/flags.js +106 -8
- package/dist/src/cli/helpers/app-successor.js +1 -2
- package/dist/src/cli/helpers/dataset.d.ts +12 -0
- package/dist/src/cli/helpers/dataset.js +36 -0
- package/dist/src/cli/helpers/documentation.d.ts +21 -0
- package/dist/src/cli/helpers/documentation.js +53 -0
- package/dist/src/cli/helpers/flow-zone.d.ts +21 -0
- package/dist/src/cli/helpers/flow-zone.js +144 -4
- package/dist/src/cli/helpers/trained-model.d.ts +26 -0
- package/dist/src/cli/helpers/trained-model.js +144 -0
- package/dist/src/cli/list-output.d.ts +7 -0
- package/dist/src/cli/list-output.js +77 -0
- package/dist/src/cli/list-shapes.d.ts +21 -0
- package/dist/src/cli/list-shapes.js +111 -0
- package/dist/src/cli/output-schemas.d.ts +0 -14
- package/dist/src/cli/output-schemas.js +4 -7
- package/dist/src/cli/output.d.ts +0 -1
- package/dist/src/cli/output.js +33 -19
- package/dist/src/cli/plans.d.ts +14 -0
- package/dist/src/cli/plans.js +3740 -0
- package/dist/src/cli/types.d.ts +2 -0
- package/dist/src/cli/usage.d.ts +7 -0
- package/dist/src/cli/usage.js +20 -1
- package/dist/src/cli/version.d.ts +2 -2
- package/dist/src/cli/version.js +2 -2
- package/dist/src/cli.js +137 -115
- package/dist/src/client.d.ts +52 -43
- package/dist/src/client.js +267 -96
- package/dist/src/errors.d.ts +22 -2
- package/dist/src/errors.js +49 -50
- package/dist/src/generated/action-output-schemas.json +345 -89
- package/dist/src/index.d.ts +5 -1
- package/dist/src/index.js +3 -0
- package/dist/src/resources/analyses.d.ts +8 -0
- package/dist/src/resources/analyses.js +13 -1
- package/dist/src/resources/bundles.d.ts +34 -0
- package/dist/src/resources/bundles.js +67 -0
- package/dist/src/resources/connections.d.ts +9 -0
- package/dist/src/resources/connections.js +15 -0
- package/dist/src/resources/data-quality.d.ts +20 -0
- package/dist/src/resources/data-quality.js +30 -0
- package/dist/src/resources/dataset-create.d.ts +38 -0
- package/dist/src/resources/dataset-create.js +135 -0
- package/dist/src/resources/datasets.d.ts +46 -15
- package/dist/src/resources/datasets.js +120 -112
- package/dist/src/resources/discussions.d.ts +5 -0
- package/dist/src/resources/discussions.js +7 -0
- package/dist/src/resources/documentation.d.ts +25 -0
- package/dist/src/resources/documentation.js +16 -0
- package/dist/src/resources/flow-zones.d.ts +29 -3
- package/dist/src/resources/flow-zones.js +53 -3
- package/dist/src/resources/flow.d.ts +48 -0
- package/dist/src/resources/flow.js +65 -0
- package/dist/src/resources/futures.d.ts +23 -0
- package/dist/src/resources/futures.js +32 -0
- package/dist/src/resources/jobs.d.ts +34 -0
- package/dist/src/resources/jobs.js +170 -3
- package/dist/src/resources/metrics.d.ts +10 -0
- package/dist/src/resources/metrics.js +10 -0
- package/dist/src/resources/ml-tasks.d.ts +65 -2
- package/dist/src/resources/ml-tasks.js +102 -28
- package/dist/src/resources/mlflow-extension.d.ts +73 -0
- package/dist/src/resources/mlflow-extension.js +105 -0
- package/dist/src/resources/projects.d.ts +15 -0
- package/dist/src/resources/projects.js +18 -3
- package/dist/src/resources/recipe-create.d.ts +79 -0
- package/dist/src/resources/recipe-create.js +454 -0
- package/dist/src/resources/recipes.d.ts +28 -29
- package/dist/src/resources/recipes.js +201 -267
- package/dist/src/resources/saved-models.d.ts +10 -6
- package/dist/src/resources/saved-models.js +16 -14
- package/dist/src/resources/scenarios.js +8 -14
- package/dist/src/resources/sql.js +52 -13
- package/dist/src/resources/streaming-endpoints.d.ts +12 -0
- package/dist/src/resources/streaming-endpoints.js +15 -0
- package/dist/src/resources/trained-model.d.ts +60 -0
- package/dist/src/resources/trained-model.js +98 -0
- package/dist/src/resources/webapps.d.ts +8 -0
- package/dist/src/resources/webapps.js +10 -0
- package/dist/src/resources/wiki.d.ts +52 -1
- package/dist/src/resources/wiki.js +96 -0
- package/dist/src/resources/workspaces.d.ts +2 -0
- package/dist/src/resources/workspaces.js +4 -0
- package/dist/src/utils/flow-analysis.js +4 -0
- package/dist/src/utils/response-file.js +20 -9
- package/dist/src/utils/secret-sanitize.d.ts +7 -0
- package/dist/src/utils/secret-sanitize.js +46 -0
- package/package.json +25 -26
- package/plugin.json +1 -1
- package/skills/dataiku-dss/SKILL.md +1 -1
- package/skills/dataiku-dss/references/authentication.md +3 -1
- package/skills/dataiku-dss/references/coding.md +1 -0
- package/skills/dataiku-dss/references/discovery.md +4 -6
- package/skills/dataiku-dss/references/flow-maps.md +2 -2
- package/skills/dataiku-dss/references/troubleshooting.md +3 -2
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { readFileSync, } from "node:fs";
|
|
2
2
|
import { writeFile, } from "node:fs/promises";
|
|
3
3
|
import { join, } from "node:path";
|
|
4
|
-
import { ClientValidationError, } from "../../errors.js";
|
|
4
|
+
import { ClientValidationError, DataikuError, } from "../../errors.js";
|
|
5
|
+
import { recipeCreateWarnings, recipeOutputSchemaIsComputable, schemaUpdateComputableId, schemaUpdateIsPending, } from "../../resources/recipe-create.js";
|
|
5
6
|
import { deepMerge, } from "../../utils/deep-merge.js";
|
|
6
7
|
import { jobLogFilterFromFlag, jsonInput, maxLogLinesFromFlags, normalizeLineEndings, num, recipeInputDatasetsFromFlags, requiredJsonInput, requiredStringFlag, rewritePairsFromFlags, sha256Hex, splitCsvFlag, stableHash, } from "../coerce.js";
|
|
7
8
|
import { executionMode, } from "../flags.js";
|
|
8
9
|
import { moveCreatedItemsToZone, resolveFlowZoneIdFromFlags, } from "../helpers/flow-zone.js";
|
|
9
10
|
import { ensureRecipeBackupDir, readRecipeBackup, recipeBackupDocument, recipeBackupPath, recipeCodeEnv, recipeGraph, recipeInputItemRef, recipeRoleInputItems, recipeRunShouldWait, writeRecipeBackup, } from "../helpers/recipe.js";
|
|
10
|
-
import { encodedProjectEndpoint, readIfExists, skipResult, } from "../output.js";
|
|
11
|
+
import { encodedProjectEndpoint, enqueueCliWarning, readIfExists, skipResult, } from "../output.js";
|
|
11
12
|
import { commandUsage, withUsage, } from "../syntax.js";
|
|
12
13
|
import { requireArgs, UsageError, } from "../usage.js";
|
|
13
14
|
/** Read a local recipe file before any DSS request, mapping read failures to usage validation. */
|
|
@@ -30,6 +31,51 @@ function readRecipeBackupFile(backupPath) {
|
|
|
30
31
|
throw new UsageError(`Could not read --backup ${backupPath}: ${reason}.`, "not_found", "Verify the backup file path and that it is readable.");
|
|
31
32
|
}
|
|
32
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* DSS does not recompute visual-recipe output schemas when the recipe is
|
|
36
|
+
* saved, and a build against a stale or empty output schema "succeeds" with
|
|
37
|
+
* the wrong columns. Around a payload write: outputs whose schema matched the
|
|
38
|
+
* DSS-computed one before the write (DSS-derived) or is empty get the newly
|
|
39
|
+
* computed schema; outputs whose schema had been hand-edited are left alone
|
|
40
|
+
* and reported in a warning.
|
|
41
|
+
*/
|
|
42
|
+
async function writeKeepingDerivedOutputSchemas(c, recipeName, recipeType, projectKey, write) {
|
|
43
|
+
if (typeof recipeType !== "string" || !recipeOutputSchemaIsComputable(recipeType)) {
|
|
44
|
+
await write();
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
const derivedOutputs = await c.recipes.computeSchemaUpdates(recipeName, projectKey).then((before) => before.computables.filter((computable) => !schemaUpdateIsPending(computable)).map(schemaUpdateComputableId),
|
|
48
|
+
// Unknown before-state: only empty schemas are safe to fill.
|
|
49
|
+
(error) => {
|
|
50
|
+
if (error instanceof DataikuError)
|
|
51
|
+
return [];
|
|
52
|
+
throw error;
|
|
53
|
+
});
|
|
54
|
+
await write();
|
|
55
|
+
try {
|
|
56
|
+
const result = await c.recipes.updateSchema(recipeName, { projectKey, derivedOutputs, });
|
|
57
|
+
if (result.pending.length > 0) {
|
|
58
|
+
enqueueCliWarning({
|
|
59
|
+
code: "recipe_output_schema_outdated",
|
|
60
|
+
recipe: recipeName,
|
|
61
|
+
outputs: result.pending,
|
|
62
|
+
hint: `These outputs have an edited schema that differs from the DSS-computed one. Run dss recipe update-schema ${recipeName} to replace it, or build with --auto-update-schema.`,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return result.updated.length > 0 ? { outputSchemaUpdated: result.updated, } : {};
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
if (!(error instanceof DataikuError))
|
|
69
|
+
throw error;
|
|
70
|
+
enqueueCliWarning({
|
|
71
|
+
code: "recipe_output_schema_not_computed",
|
|
72
|
+
recipe: recipeName,
|
|
73
|
+
error: error.message.split("\n")[0],
|
|
74
|
+
hint: `Fix the recipe settings, then run dss recipe update-schema ${recipeName}.`,
|
|
75
|
+
});
|
|
76
|
+
return {};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
33
79
|
function formatLineDiff(remoteName, localPath, remoteContent, localContent) {
|
|
34
80
|
// Line-ending differences are not content differences: compare and split on
|
|
35
81
|
// CRLF-normalized text, mirroring assert-unchanged's normalized payload hash.
|
|
@@ -61,6 +107,19 @@ function formatLineDiff(remoteName, localPath, remoteContent, localContent) {
|
|
|
61
107
|
}
|
|
62
108
|
return lines.join("\n");
|
|
63
109
|
}
|
|
110
|
+
const PREPARE_STEP_FLAGS = {
|
|
111
|
+
"rename": "rename",
|
|
112
|
+
"fill-empty": "fillEmpty",
|
|
113
|
+
"formula": "formula",
|
|
114
|
+
"filter": "filter",
|
|
115
|
+
"drop-columns": "dropColumns",
|
|
116
|
+
"keep-columns": "keepColumns",
|
|
117
|
+
};
|
|
118
|
+
/** Queue the stderr warnings for `recipe create` options (also used by `--plan` and `--dry-run`). */
|
|
119
|
+
export function enqueueRecipeCreateWarnings(options) {
|
|
120
|
+
for (const warning of recipeCreateWarnings(options))
|
|
121
|
+
enqueueCliWarning(warning);
|
|
122
|
+
}
|
|
64
123
|
/** Maps `recipe create` flags to SDK options; shared by the handler and `--plan`. */
|
|
65
124
|
export function recipeCreateOptionsFromFlags(f) {
|
|
66
125
|
const type = f["type"];
|
|
@@ -99,6 +158,11 @@ export function recipeCreateOptionsFromFlags(f) {
|
|
|
99
158
|
fuzzyDistance = normalized;
|
|
100
159
|
}
|
|
101
160
|
const fuzzyThreshold = num(f["fuzzy-threshold"], "--fuzzy-threshold");
|
|
161
|
+
// Prepare option groups run in the order their flags were typed (object keys keep first-use order).
|
|
162
|
+
const stepOrder = Object.keys(f).flatMap((flag) => {
|
|
163
|
+
const kind = Object.hasOwn(PREPARE_STEP_FLAGS, flag) ? PREPARE_STEP_FLAGS[flag] : undefined;
|
|
164
|
+
return kind ? [kind,] : [];
|
|
165
|
+
});
|
|
102
166
|
const payload = {
|
|
103
167
|
type,
|
|
104
168
|
name,
|
|
@@ -112,10 +176,24 @@ export function recipeCreateOptionsFromFlags(f) {
|
|
|
112
176
|
...(fuzzyDistance ? { fuzzyDistance, } : {}),
|
|
113
177
|
...(fuzzyThreshold !== undefined ? { fuzzyThreshold, } : {}),
|
|
114
178
|
fuzzyNormalize: f["normalize"] === true,
|
|
179
|
+
...csvOption("groupBy", f["group-by"]),
|
|
180
|
+
...csvOption("aggregate", f["aggregate"]),
|
|
181
|
+
...(typeof f["order-by"] === "string" ? { orderBy: f["order-by"], } : {}),
|
|
182
|
+
...csvOption("rename", f["rename"]),
|
|
183
|
+
...csvOption("fillEmpty", f["fill-empty"]),
|
|
184
|
+
...(typeof f["formula"] === "string" ? { formula: f["formula"], } : {}),
|
|
185
|
+
...(typeof f["filter"] === "string" ? { filter: f["filter"], } : {}),
|
|
186
|
+
...csvOption("dropColumns", f["drop-columns"]),
|
|
187
|
+
...csvOption("keepColumns", f["keep-columns"]),
|
|
188
|
+
...(stepOrder.length > 0 ? { stepOrder, } : {}),
|
|
115
189
|
projectKey: pk,
|
|
116
190
|
};
|
|
117
191
|
return payload;
|
|
118
192
|
}
|
|
193
|
+
function csvOption(key, value) {
|
|
194
|
+
const items = splitCsvFlag(value);
|
|
195
|
+
return items.length > 0 ? { [key]: items, } : {};
|
|
196
|
+
}
|
|
119
197
|
export const recipeCommands = withUsage("recipe", {
|
|
120
198
|
list: {
|
|
121
199
|
handler: (c, _a, f) => c.recipes.list(f["project-key"]),
|
|
@@ -271,6 +349,7 @@ export const recipeCommands = withUsage("recipe", {
|
|
|
271
349
|
create: {
|
|
272
350
|
handler: async (c, _a, f) => {
|
|
273
351
|
const payload = recipeCreateOptionsFromFlags(f);
|
|
352
|
+
enqueueRecipeCreateWarnings(payload);
|
|
274
353
|
const name = payload.name;
|
|
275
354
|
const pk = payload.projectKey;
|
|
276
355
|
const zoneId = await resolveFlowZoneIdFromFlags(c, f, pk);
|
|
@@ -310,13 +389,38 @@ export const recipeCommands = withUsage("recipe", {
|
|
|
310
389
|
objectId: createdName,
|
|
311
390
|
objectType: "RECIPE",
|
|
312
391
|
},], pk);
|
|
392
|
+
if (created.requestedName) {
|
|
393
|
+
// DSS appends _N when the requested name is taken; any other difference is DSS naming
|
|
394
|
+
// the recipe itself. The public API has no recipe rename.
|
|
395
|
+
const suffix = createdName.startsWith(`${created.requestedName}_`)
|
|
396
|
+
? createdName.slice(created.requestedName.length + 1)
|
|
397
|
+
: "";
|
|
398
|
+
const nameTaken = /^\d+$/.test(suffix);
|
|
399
|
+
enqueueCliWarning({
|
|
400
|
+
code: "recipe_renamed",
|
|
401
|
+
requestedName: created.requestedName,
|
|
402
|
+
recipe: createdName,
|
|
403
|
+
reason: nameTaken ? "name_taken" : "dss_chose_name",
|
|
404
|
+
hint: nameTaken
|
|
405
|
+
? `A recipe named ${created.requestedName} already exists; use ${createdName} in follow-up commands.`
|
|
406
|
+
: `DSS ignored the requested name; use ${createdName} in follow-up commands.`,
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
if (created.outputSchemaUpdateError) {
|
|
410
|
+
enqueueCliWarning({
|
|
411
|
+
code: "recipe_output_schema_not_computed",
|
|
412
|
+
recipe: createdName,
|
|
413
|
+
error: created.outputSchemaUpdateError,
|
|
414
|
+
hint: `Fix the recipe settings, then run dss recipe update-schema ${createdName}.`,
|
|
415
|
+
});
|
|
416
|
+
}
|
|
313
417
|
return { created: createdName, resource: "recipe", ...created, ...moved, };
|
|
314
418
|
},
|
|
315
|
-
description: "Create a recipe with optional inputs and a dataset or managed-folder output.",
|
|
419
|
+
description: "Create a recipe with optional inputs and a dataset or managed-folder output. Missing outputs are created on --output-connection as DSS managed datasets. Join, grouping (--group-by/--aggregate) and prepare (--rename/--formula/--filter/...) payloads come from flags. Visual recipe outputs get the DSS-computed schema (outputSchemaUpdated).",
|
|
316
420
|
examples: [
|
|
317
421
|
"dss recipe create --type python --input raw_orders,lookup --output orders_clean",
|
|
318
|
-
"dss recipe create --type
|
|
319
|
-
"dss recipe create --type
|
|
422
|
+
"dss recipe create --type grouping --input orders --output orders_by_cat --group-by category --aggregate amount:sum+avg,name:first --order-by day",
|
|
423
|
+
"dss recipe create --type prepare --input orders --output orders_prep --rename name=label --formula 'total=amount * 2' --filter 'amount > 0'",
|
|
320
424
|
],
|
|
321
425
|
},
|
|
322
426
|
clone: {
|
|
@@ -586,22 +690,41 @@ export const recipeCommands = withUsage("recipe", {
|
|
|
586
690
|
ensureRecipeBackupDir(backupDir);
|
|
587
691
|
writeRecipeBackup(backupPath, `${JSON.stringify(recipeBackupDocument(a[0], pk, current), null, 2)}\n`);
|
|
588
692
|
}
|
|
589
|
-
await c.recipes.replace(a[0], { ...current, payload: content, }, pk);
|
|
693
|
+
const schema = await writeKeepingDerivedOutputSchemas(c, a[0], current.recipe.type, pk, () => c.recipes.replace(a[0], { ...current, payload: content, }, pk));
|
|
590
694
|
return {
|
|
591
695
|
updated: a[0],
|
|
592
696
|
resource: "recipe",
|
|
593
697
|
file: filePath,
|
|
594
698
|
backupCreated: backupPath !== undefined,
|
|
595
699
|
...(backupPath ? { backupPath, } : {}),
|
|
700
|
+
...schema,
|
|
596
701
|
};
|
|
597
702
|
},
|
|
598
|
-
description: "Upload recipe code from a local file, backing up payload, graph, settings, and version metadata by default.",
|
|
703
|
+
description: "Upload recipe code from a local file, backing up payload, graph, settings, and version metadata by default. For visual and SQL query recipes, outputs whose schema was empty or matched the DSS-computed one before the upload get the newly computed schema (outputSchemaUpdated); hand-edited output schemas are kept and reported in a recipe_output_schema_outdated warning.",
|
|
599
704
|
examples: [
|
|
600
705
|
"dss recipe set-payload compute_orders --file code.py --dry-run",
|
|
601
706
|
"dss recipe set-payload compute_orders --file code.py --backup-dir ./backups",
|
|
602
707
|
"dss recipe set-payload compute_orders --file code.py --no-backup",
|
|
603
708
|
],
|
|
604
709
|
},
|
|
710
|
+
"update-schema": {
|
|
711
|
+
handler: async (c, a, f) => {
|
|
712
|
+
requireArgs(a, 1, commandUsage("recipe", "update-schema"));
|
|
713
|
+
const dryRun = executionMode(f).dryRun;
|
|
714
|
+
const result = await c.recipes.updateSchema(a[0], {
|
|
715
|
+
projectKey: f["project-key"],
|
|
716
|
+
dryRun,
|
|
717
|
+
});
|
|
718
|
+
return dryRun
|
|
719
|
+
? { dryRun: true, action: "update-schema", resource: "recipe", name: a[0], ...result, }
|
|
720
|
+
: result;
|
|
721
|
+
},
|
|
722
|
+
description: "Propagate schema changes: write the output schemas DSS computes from a visual or SQL query recipe (the UI's Update schema; dataikuapi compute_schema_updates().apply()) to every output whose schema differs. --dry-run lists them under pending. Code recipes are rejected: their code sets the schema when it runs.",
|
|
723
|
+
examples: [
|
|
724
|
+
"dss recipe update-schema compute_orders_joined --dry-run",
|
|
725
|
+
"dss recipe update-schema compute_orders_joined",
|
|
726
|
+
],
|
|
727
|
+
},
|
|
605
728
|
restore: {
|
|
606
729
|
handler: async (c, a, f) => {
|
|
607
730
|
const usage = commandUsage("recipe", "restore");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CommandMeta } from "../types.js";
|
|
2
2
|
/**
|
|
3
|
-
* Mutating actions accept --plan (buildMutationPlan in
|
|
3
|
+
* Mutating actions accept --plan (buildMutationPlan in plans.ts owns the
|
|
4
4
|
* --plan path centrally); the handlers below keep --dry-run support with a
|
|
5
5
|
* zero-request planned payload, mirroring set-active/delete.
|
|
6
6
|
*/
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { unexpectedResponseError, } from "../../errors.js";
|
|
2
|
-
import { writeResponseToFile, } from "../../utils/response-file.js";
|
|
3
1
|
import { json, jsonInput, parseBooleanOption, requiredJsonInput, } from "../coerce.js";
|
|
4
2
|
import { executionMode, } from "../flags.js";
|
|
3
|
+
import { trainedModelCommands, } from "../helpers/trained-model.js";
|
|
5
4
|
import { readIfExists, skipResult, } from "../output.js";
|
|
6
5
|
import { commandUsage, withUsage, } from "../syntax.js";
|
|
7
6
|
import { requireArgs, UsageError, } from "../usage.js";
|
|
8
7
|
/**
|
|
9
|
-
* Mutating actions accept --plan (buildMutationPlan in
|
|
8
|
+
* Mutating actions accept --plan (buildMutationPlan in plans.ts owns the
|
|
10
9
|
* --plan path centrally); the handlers below keep --dry-run support with a
|
|
11
10
|
* zero-request planned payload, mirroring set-active/delete.
|
|
12
11
|
*/
|
|
@@ -361,79 +360,13 @@ export const savedModelCommands = withUsage("saved-model", {
|
|
|
361
360
|
"dss saved-model evaluate-version MODEL_ID VERSION_ID --dataset ds --skip-expensive-reports true --project-key PROJECT",
|
|
362
361
|
],
|
|
363
362
|
},
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
const fullClassName = f["full-class-name"];
|
|
372
|
-
const jarOptions = {
|
|
373
|
-
...(fullClassName !== undefined ? { fullClassName, } : {}),
|
|
374
|
-
...(f["include-libs"] !== undefined
|
|
375
|
-
? { includeLibs: parseBooleanOption(f["include-libs"], "--include-libs"), }
|
|
376
|
-
: {}),
|
|
377
|
-
};
|
|
378
|
-
const res = await c.savedModels.downloadScoringJar(jarOptions, a[0], a[1], f["project-key"]);
|
|
379
|
-
if (!res.body) {
|
|
380
|
-
throw unexpectedResponseError("savedModels.downloadScoringJar response did not include a body");
|
|
381
|
-
}
|
|
382
|
-
const bytes = await writeResponseToFile(out, res);
|
|
383
|
-
return { path: out, bytes, };
|
|
384
|
-
},
|
|
385
|
-
description: "Download the optimized scoring JAR of a version (license-gated server side). --full-class-name forwards the documented fullClassName query parameter; --include-libs toggles including scoring libraries.",
|
|
386
|
-
examples: [
|
|
387
|
-
"dss saved-model download-scoring-jar MODEL_ID VERSION_ID --output ./scoring.jar --project-key PROJECT",
|
|
388
|
-
"dss saved-model download-scoring-jar MODEL_ID VERSION_ID --output ./scoring.jar --full-class-name model.Model --include-libs false --project-key PROJECT",
|
|
389
|
-
],
|
|
390
|
-
},
|
|
391
|
-
"download-scoring-pmml": {
|
|
392
|
-
handler: async (c, a, f) => {
|
|
393
|
-
requireArgs(a, 2, commandUsage("saved-model", "download-scoring-pmml"));
|
|
394
|
-
const out = f["output"];
|
|
395
|
-
if (!out)
|
|
396
|
-
throw new UsageError("--output PATH is required.", "missing_required_flag");
|
|
397
|
-
const res = await c.savedModels.downloadScoringPmml(a[0], a[1], f["project-key"]);
|
|
398
|
-
if (!res.body) {
|
|
399
|
-
throw unexpectedResponseError("savedModels.downloadScoringPmml response did not include a body");
|
|
400
|
-
}
|
|
401
|
-
const bytes = await writeResponseToFile(out, res);
|
|
402
|
-
return { path: out, bytes, };
|
|
403
|
-
},
|
|
404
|
-
description: "Download the PMML scoring file of a version (license-gated server side).",
|
|
405
|
-
examples: [
|
|
406
|
-
"dss saved-model download-scoring-pmml MODEL_ID VERSION_ID --output ./model.pmml --project-key PROJECT",
|
|
407
|
-
],
|
|
408
|
-
},
|
|
409
|
-
"set-user-meta": {
|
|
410
|
-
handler: async (c, a, f) => {
|
|
411
|
-
const usage = commandUsage("saved-model", "set-user-meta");
|
|
412
|
-
requireArgs(a, 2, usage);
|
|
413
|
-
const userMeta = requiredJsonInput(f, "User-meta JSON is required via --data, --data-file, or --stdin.");
|
|
414
|
-
const projectKey = f["project-key"];
|
|
415
|
-
if (executionMode(f).dryRun) {
|
|
416
|
-
return {
|
|
417
|
-
dryRun: true,
|
|
418
|
-
action: "set-user-meta",
|
|
419
|
-
resource: "saved-model",
|
|
420
|
-
id: a[0],
|
|
421
|
-
versionId: a[1],
|
|
422
|
-
projectKey,
|
|
423
|
-
payload: userMeta,
|
|
424
|
-
};
|
|
425
|
-
}
|
|
426
|
-
return c.savedModels.setUserMeta(a[0], a[1], userMeta, projectKey).then(() => ({
|
|
427
|
-
updated: a[0],
|
|
428
|
-
versionId: a[1],
|
|
429
|
-
resource: "saved-model",
|
|
430
|
-
}));
|
|
431
|
-
},
|
|
432
|
-
description: 'Update the user metadata of a model version. Send only the "userMeta" field of a previously-retrieved version-details object.',
|
|
433
|
-
examples: [
|
|
434
|
-
'dss saved-model set-user-meta MODEL_ID VERSION_ID --data \'{"name":"Churn model","description":"v2"}\' --project-key PROJECT',
|
|
435
|
-
],
|
|
436
|
-
},
|
|
363
|
+
...trainedModelCommands({
|
|
364
|
+
resource: "saved-model",
|
|
365
|
+
ids: "MODEL_ID VERSION_ID",
|
|
366
|
+
noun: "saved-model version",
|
|
367
|
+
model: (c, a, pk) => c.savedModels.version(a[0], a[1], pk),
|
|
368
|
+
downloadDocumentation: (c, exportId, pk) => c.savedModels.downloadDocumentation(exportId, pk),
|
|
369
|
+
}),
|
|
437
370
|
});
|
|
438
371
|
function mlflowImportOptions(f) {
|
|
439
372
|
const codeEnvName = f["code-env"];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsonInput, requiredJsonInput, } from "../coerce.js";
|
|
2
2
|
import { commandUsage, withUsage, } from "../syntax.js";
|
|
3
|
-
import { requireArgs, } from "../usage.js";
|
|
3
|
+
import { requireArgs, UsageError, } from "../usage.js";
|
|
4
4
|
export const streamingEndpointCommands = withUsage("streaming-endpoint", {
|
|
5
5
|
list: {
|
|
6
6
|
handler: (c, _a, f) => c.streamingEndpoints.list(f["project-key"]),
|
|
@@ -43,4 +43,33 @@ export const streamingEndpointCommands = withUsage("streaming-endpoint", {
|
|
|
43
43
|
description: "Delete a streaming endpoint.",
|
|
44
44
|
examples: ["dss streaming-endpoint delete my-stream",],
|
|
45
45
|
},
|
|
46
|
+
"create-managed": {
|
|
47
|
+
handler: async (c, a, f) => {
|
|
48
|
+
const connectionId = f["connection"];
|
|
49
|
+
if (typeof connectionId !== "string") {
|
|
50
|
+
throw new UsageError("--connection CONN is required.", "missing_required_flag");
|
|
51
|
+
}
|
|
52
|
+
const formatOptionId = f["format-option"];
|
|
53
|
+
await c.streamingEndpoints.createManaged(a[0], {
|
|
54
|
+
connectionId,
|
|
55
|
+
...(typeof formatOptionId === "string" ? { formatOptionId, } : {}),
|
|
56
|
+
}, f["project-key"]);
|
|
57
|
+
return { created: a[0], resource: "streaming-endpoint", };
|
|
58
|
+
},
|
|
59
|
+
description: "Create a managed streaming endpoint on a connection; DSS picks type and params from the connection (--format-option for the message format).",
|
|
60
|
+
examples: ["dss streaming-endpoint create-managed orders_stream --connection kafka_main",],
|
|
61
|
+
},
|
|
62
|
+
schema: {
|
|
63
|
+
handler: (c, a, f) => c.streamingEndpoints.getSchema(a[0], f["project-key"]),
|
|
64
|
+
description: "Get a streaming endpoint's schema ({columns: [{name, type}]}).",
|
|
65
|
+
examples: ["dss streaming-endpoint schema orders_stream",],
|
|
66
|
+
},
|
|
67
|
+
"set-schema": {
|
|
68
|
+
handler: async (c, a, f) => {
|
|
69
|
+
await c.streamingEndpoints.setSchema(a[0], requiredJsonInput(f, '--data, --data-file, or --stdin is required ({"columns": [...]}).'), f["project-key"]);
|
|
70
|
+
return { updated: a[0], resource: "streaming-endpoint", };
|
|
71
|
+
},
|
|
72
|
+
description: "Replace a streaming endpoint's schema with an object from the schema action, edited.",
|
|
73
|
+
examples: ["dss streaming-endpoint set-schema orders_stream --data-file schema.json",],
|
|
74
|
+
},
|
|
46
75
|
});
|
|
@@ -113,4 +113,12 @@ export const webappCommands = withUsage("webapp", {
|
|
|
113
113
|
description: "Get a webapp backend's runtime state.",
|
|
114
114
|
examples: ["dss webapp backend-state WEBAPP_ID",],
|
|
115
115
|
},
|
|
116
|
+
trust: {
|
|
117
|
+
handler: (c, a, f) => c.webapps.trust(a[0], {
|
|
118
|
+
projectKey: f["project-key"],
|
|
119
|
+
...(f["for-everybody"] === true ? { trustForEverybody: true, } : {}),
|
|
120
|
+
}),
|
|
121
|
+
description: "Trust a webapp's code so it can run for you, or for every user with --for-everybody (admin). Returns canAccess and trustedCodeStatus.",
|
|
122
|
+
examples: ["dss webapp trust VCMN2ra", "dss webapp trust VCMN2ra --for-everybody",],
|
|
123
|
+
},
|
|
116
124
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { findWikiAttachment, statWikiAttachmentFile, wikiAttachmentNotFound, wikiAttachments, } from "../../resources/wiki.js";
|
|
1
2
|
import { deepMerge, } from "../../utils/deep-merge.js";
|
|
2
3
|
import { jsonInput, textInput, } from "../coerce.js";
|
|
3
4
|
import { executionMode, } from "../flags.js";
|
|
@@ -117,4 +118,81 @@ export const wikiCommands = withUsage("wiki", {
|
|
|
117
118
|
description: "Delete a wiki article.",
|
|
118
119
|
examples: ["dss wiki delete ARTICLE_ID --dry-run",],
|
|
119
120
|
},
|
|
121
|
+
attach: {
|
|
122
|
+
handler: async (c, a, f) => {
|
|
123
|
+
requireArgs(a, 2, commandUsage("wiki", "attach"));
|
|
124
|
+
const pk = f["project-key"];
|
|
125
|
+
const file = await statWikiAttachmentFile(a[1]);
|
|
126
|
+
if (executionMode(f).dryRun) {
|
|
127
|
+
const current = await c.wiki.get(a[0], pk);
|
|
128
|
+
return {
|
|
129
|
+
dryRun: true,
|
|
130
|
+
action: "attach",
|
|
131
|
+
resource: "wiki",
|
|
132
|
+
article: a[0],
|
|
133
|
+
file,
|
|
134
|
+
current: wikiAttachments(current),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
const result = await c.wiki.attach(a[0], a[1], pk);
|
|
138
|
+
return { attached: result.attachment.smartId, resource: "wiki", ...result, };
|
|
139
|
+
},
|
|
140
|
+
description: "Upload a local file and attach it to a wiki article; returns its smartId.",
|
|
141
|
+
examples: ["dss wiki attach ARTICLE_ID ./diagram.png --dry-run",],
|
|
142
|
+
},
|
|
143
|
+
detach: {
|
|
144
|
+
handler: async (c, a, f) => {
|
|
145
|
+
requireArgs(a, 2, commandUsage("wiki", "detach"));
|
|
146
|
+
const pk = f["project-key"];
|
|
147
|
+
const ifExists = f["if-exists"] === true;
|
|
148
|
+
const dryRun = executionMode(f).dryRun;
|
|
149
|
+
if (dryRun || ifExists) {
|
|
150
|
+
const current = ifExists
|
|
151
|
+
? await readIfExists(() => c.wiki.get(a[0], pk))
|
|
152
|
+
: await c.wiki.get(a[0], pk);
|
|
153
|
+
const attachment = current && findWikiAttachment(current, a[1]);
|
|
154
|
+
if (!current || !attachment) {
|
|
155
|
+
if (!ifExists && current)
|
|
156
|
+
throw wikiAttachmentNotFound(current, a[1]);
|
|
157
|
+
return skipResult("wiki", a[1], "missing", { article: a[0], });
|
|
158
|
+
}
|
|
159
|
+
if (dryRun) {
|
|
160
|
+
return {
|
|
161
|
+
dryRun: true,
|
|
162
|
+
action: "detach",
|
|
163
|
+
resource: "wiki",
|
|
164
|
+
article: a[0],
|
|
165
|
+
smartId: a[1],
|
|
166
|
+
current: attachment,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const result = await c.wiki.detach(a[0], a[1], pk);
|
|
171
|
+
return { resource: "wiki", ...result, };
|
|
172
|
+
},
|
|
173
|
+
description: "Remove one attachment from a wiki article by smartId.",
|
|
174
|
+
examples: ["dss wiki detach ARTICLE_ID SMART_ID --if-exists",],
|
|
175
|
+
},
|
|
176
|
+
"update-settings": {
|
|
177
|
+
handler: async (c, _a, f) => {
|
|
178
|
+
const pk = f["project-key"];
|
|
179
|
+
const settings = jsonInput(f);
|
|
180
|
+
if (!settings) {
|
|
181
|
+
throw new UsageError("--data, --data-file, or --stdin is required.", "missing_required_flag");
|
|
182
|
+
}
|
|
183
|
+
if (executionMode(f).dryRun) {
|
|
184
|
+
return {
|
|
185
|
+
dryRun: true,
|
|
186
|
+
action: "update-settings",
|
|
187
|
+
resource: "wiki",
|
|
188
|
+
current: await c.wiki.settings(pk),
|
|
189
|
+
next: settings,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
await c.wiki.updateSettings(settings, pk);
|
|
193
|
+
return { updated: "wiki", resource: "wiki", };
|
|
194
|
+
},
|
|
195
|
+
description: "Replace the wiki properties (home article id and taxonomy tree) with an object from dss wiki settings, edited.",
|
|
196
|
+
examples: ["dss wiki update-settings --data-file wiki.json --dry-run",],
|
|
197
|
+
},
|
|
120
198
|
});
|
|
@@ -59,4 +59,12 @@ export const workspaceCommands = withUsage("workspace", {
|
|
|
59
59
|
description: "Add an object (link or DSS object) to a workspace.",
|
|
60
60
|
examples: ["dss workspace add-object MY_WS --data-file object.json",],
|
|
61
61
|
},
|
|
62
|
+
"remove-object": {
|
|
63
|
+
handler: async (c, a) => {
|
|
64
|
+
await c.workspaces.removeObject(a[0], a[1]);
|
|
65
|
+
return { removed: a[1], resource: "workspace", workspace: a[0], };
|
|
66
|
+
},
|
|
67
|
+
description: "Remove an object from a workspace by its workspace object id (see list-objects).",
|
|
68
|
+
examples: ["dss workspace remove-object MY_WORKSPACE abcd1234",],
|
|
69
|
+
},
|
|
62
70
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type CommandInputContract, type CommandPositionalMetadata } from "./syntax.js";
|
|
2
2
|
import type { CommandFlagChoice, CommandMeta, CommandPayloadSchema } from "./types.js";
|
|
3
|
+
export declare function splitPackageSpec(raw: string): string[];
|
|
3
4
|
export declare const AUTH_ACTIONS: Record<string, {
|
|
4
5
|
handler: (flags: Record<string, string | boolean>) => Promise<unknown>;
|
|
5
6
|
description?: string;
|
|
@@ -35,8 +36,7 @@ export interface CommandRequiredInputGroup {
|
|
|
35
36
|
oneOf: CommandRequiredInputAlternative[];
|
|
36
37
|
}
|
|
37
38
|
export interface CommandStructuredExample {
|
|
38
|
-
|
|
39
|
-
argv?: string[];
|
|
39
|
+
argv: string[];
|
|
40
40
|
payload?: unknown;
|
|
41
41
|
}
|
|
42
42
|
export interface CommandUnsafeOutput {
|
|
@@ -58,7 +58,6 @@ export interface CommandRegistryEntry {
|
|
|
58
58
|
examples?: string[];
|
|
59
59
|
structuredExamples: CommandStructuredExample[];
|
|
60
60
|
flags: CommandFlagMetadata[];
|
|
61
|
-
positionals: string[];
|
|
62
61
|
positionalArguments: CommandPositionalMetadata[];
|
|
63
62
|
sideEffect: CommandSideEffect;
|
|
64
63
|
requiresAuth: boolean;
|
|
@@ -92,22 +91,24 @@ export declare function isAllowedCleanupAction(resource: string, action: string)
|
|
|
92
91
|
export declare function buildCommandSchemas(resource: string, action: string, flags: CommandFlagMetadata[], requiredFlags: string[], requiredOneOf: CommandFlagChoice[], payloadSchema: CommandPayloadSchema | undefined, outputShape: CommandOutputShape, usage: string): CommandAgentSchemas;
|
|
93
92
|
export declare function supportsCleanupLedger(resource: string, action: string): boolean;
|
|
94
93
|
export declare function inferCleanupHint(resource: string, action: string): string | undefined;
|
|
94
|
+
export declare function buildRegistryEntry(resource: string, action: string, meta: CommandMeta): CommandRegistryEntry;
|
|
95
95
|
export declare function buildCommandRegistry(resourceFilter?: string): Record<string, Record<string, CommandRegistryEntry>>;
|
|
96
|
+
export interface CommandSearchMatch {
|
|
97
|
+
id: string;
|
|
98
|
+
usage: string;
|
|
99
|
+
description: string;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Find actions by concept: every query word of three or more letters is
|
|
103
|
+
* matched (case-insensitively, trailing plural `s` ignored) against the action
|
|
104
|
+
* id, usage, and description. When some actions match every word, only those
|
|
105
|
+
* are returned; otherwise actions matching more words rank first. Matches in
|
|
106
|
+
* the id break ties. Reads command definitions only, never builds entries.
|
|
107
|
+
*/
|
|
108
|
+
export declare function searchCommands(query: string): CommandSearchMatch[];
|
|
96
109
|
export declare function agentContractJsonSchema(): Record<string, unknown>;
|
|
97
110
|
export declare function commandActionSummary(): Record<string, string[]>;
|
|
98
111
|
export declare function buildAgentContract(): Record<string, unknown>;
|
|
99
|
-
export declare function commandPlanShape(resource: string, action: string, args: string[], flags: Record<string, string | boolean>, entry: CommandRegistryEntry, projectKey: string | undefined): {
|
|
100
|
-
endpoint?: string;
|
|
101
|
-
exact?: boolean;
|
|
102
|
-
identifiers?: Record<string, unknown>;
|
|
103
|
-
method?: string;
|
|
104
|
-
payload?: unknown;
|
|
105
|
-
localWrites?: unknown;
|
|
106
|
-
reason?: string;
|
|
107
|
-
wait?: unknown;
|
|
108
|
-
requests?: unknown;
|
|
109
|
-
};
|
|
110
|
-
export declare function buildMutationPlan(resource: string, action: string, meta: CommandMeta, args: string[], flags: Record<string, string | boolean>): Record<string, unknown>;
|
|
111
112
|
/**
|
|
112
113
|
* Batch plans may surface exit 4: any dispatched step can be a long-running
|
|
113
114
|
* lifecycle command whose remote work fails, or a synchronous assertion
|