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.
Files changed (139) hide show
  1. package/README.md +14 -6
  2. package/bin/bun-version.js +14 -0
  3. package/bin/dss.js +11 -15
  4. package/dist/build-metadata.json +1 -1
  5. package/dist/packages/types/src/index.d.ts +114 -5
  6. package/dist/packages/types/src/index.js +75 -2
  7. package/dist/src/cli/coerce.d.ts +2 -0
  8. package/dist/src/cli/coerce.js +20 -16
  9. package/dist/src/cli/command-syntax.json +3369 -144
  10. package/dist/src/cli/commands/analysis.js +19 -1
  11. package/dist/src/cli/commands/bundle.js +22 -0
  12. package/dist/src/cli/commands/connection.js +26 -2
  13. package/dist/src/cli/commands/data-quality.js +33 -1
  14. package/dist/src/cli/commands/dataset.js +76 -9
  15. package/dist/src/cli/commands/discussion.js +15 -0
  16. package/dist/src/cli/commands/doctor.js +1 -1
  17. package/dist/src/cli/commands/flow-zone.js +241 -46
  18. package/dist/src/cli/commands/flow.d.ts +5 -0
  19. package/dist/src/cli/commands/flow.js +57 -0
  20. package/dist/src/cli/commands/future.js +8 -0
  21. package/dist/src/cli/commands/index.js +6 -0
  22. package/dist/src/cli/commands/job.js +44 -6
  23. package/dist/src/cli/commands/metrics.js +21 -1
  24. package/dist/src/cli/commands/ml-task.d.ts +5 -0
  25. package/dist/src/cli/commands/ml-task.js +86 -16
  26. package/dist/src/cli/commands/mlflow.d.ts +11 -0
  27. package/dist/src/cli/commands/mlflow.js +121 -0
  28. package/dist/src/cli/commands/plugin.js +5 -11
  29. package/dist/src/cli/commands/project-deployer.js +70 -0
  30. package/dist/src/cli/commands/project-library.js +2 -5
  31. package/dist/src/cli/commands/project.js +8 -0
  32. package/dist/src/cli/commands/recipe.d.ts +13 -0
  33. package/dist/src/cli/commands/recipe.js +130 -7
  34. package/dist/src/cli/commands/saved-model.d.ts +1 -1
  35. package/dist/src/cli/commands/saved-model.js +9 -76
  36. package/dist/src/cli/commands/streaming-endpoint.js +30 -1
  37. package/dist/src/cli/commands/webapp.js +8 -0
  38. package/dist/src/cli/commands/wiki.js +78 -0
  39. package/dist/src/cli/commands/workspace.js +8 -0
  40. package/dist/src/cli/contract.d.ts +16 -15
  41. package/dist/src/cli/contract.js +150 -3407
  42. package/dist/src/cli/doctor.d.ts +13 -0
  43. package/dist/src/cli/doctor.js +43 -1
  44. package/dist/src/cli/flags.d.ts +14 -1
  45. package/dist/src/cli/flags.js +106 -8
  46. package/dist/src/cli/helpers/app-successor.js +1 -2
  47. package/dist/src/cli/helpers/dataset.d.ts +12 -0
  48. package/dist/src/cli/helpers/dataset.js +36 -0
  49. package/dist/src/cli/helpers/documentation.d.ts +21 -0
  50. package/dist/src/cli/helpers/documentation.js +53 -0
  51. package/dist/src/cli/helpers/flow-zone.d.ts +21 -0
  52. package/dist/src/cli/helpers/flow-zone.js +144 -4
  53. package/dist/src/cli/helpers/trained-model.d.ts +26 -0
  54. package/dist/src/cli/helpers/trained-model.js +144 -0
  55. package/dist/src/cli/list-output.d.ts +7 -0
  56. package/dist/src/cli/list-output.js +77 -0
  57. package/dist/src/cli/list-shapes.d.ts +21 -0
  58. package/dist/src/cli/list-shapes.js +111 -0
  59. package/dist/src/cli/output-schemas.d.ts +0 -14
  60. package/dist/src/cli/output-schemas.js +4 -7
  61. package/dist/src/cli/output.d.ts +0 -1
  62. package/dist/src/cli/output.js +33 -19
  63. package/dist/src/cli/plans.d.ts +14 -0
  64. package/dist/src/cli/plans.js +3740 -0
  65. package/dist/src/cli/types.d.ts +2 -0
  66. package/dist/src/cli/usage.d.ts +7 -0
  67. package/dist/src/cli/usage.js +20 -1
  68. package/dist/src/cli/version.d.ts +2 -2
  69. package/dist/src/cli/version.js +2 -2
  70. package/dist/src/cli.js +137 -115
  71. package/dist/src/client.d.ts +52 -43
  72. package/dist/src/client.js +267 -96
  73. package/dist/src/errors.d.ts +22 -2
  74. package/dist/src/errors.js +49 -50
  75. package/dist/src/generated/action-output-schemas.json +345 -89
  76. package/dist/src/index.d.ts +5 -1
  77. package/dist/src/index.js +3 -0
  78. package/dist/src/resources/analyses.d.ts +8 -0
  79. package/dist/src/resources/analyses.js +13 -1
  80. package/dist/src/resources/bundles.d.ts +34 -0
  81. package/dist/src/resources/bundles.js +67 -0
  82. package/dist/src/resources/connections.d.ts +9 -0
  83. package/dist/src/resources/connections.js +15 -0
  84. package/dist/src/resources/data-quality.d.ts +20 -0
  85. package/dist/src/resources/data-quality.js +30 -0
  86. package/dist/src/resources/dataset-create.d.ts +38 -0
  87. package/dist/src/resources/dataset-create.js +135 -0
  88. package/dist/src/resources/datasets.d.ts +46 -15
  89. package/dist/src/resources/datasets.js +120 -112
  90. package/dist/src/resources/discussions.d.ts +5 -0
  91. package/dist/src/resources/discussions.js +7 -0
  92. package/dist/src/resources/documentation.d.ts +25 -0
  93. package/dist/src/resources/documentation.js +16 -0
  94. package/dist/src/resources/flow-zones.d.ts +29 -3
  95. package/dist/src/resources/flow-zones.js +53 -3
  96. package/dist/src/resources/flow.d.ts +48 -0
  97. package/dist/src/resources/flow.js +65 -0
  98. package/dist/src/resources/futures.d.ts +23 -0
  99. package/dist/src/resources/futures.js +32 -0
  100. package/dist/src/resources/jobs.d.ts +34 -0
  101. package/dist/src/resources/jobs.js +170 -3
  102. package/dist/src/resources/metrics.d.ts +10 -0
  103. package/dist/src/resources/metrics.js +10 -0
  104. package/dist/src/resources/ml-tasks.d.ts +65 -2
  105. package/dist/src/resources/ml-tasks.js +102 -28
  106. package/dist/src/resources/mlflow-extension.d.ts +73 -0
  107. package/dist/src/resources/mlflow-extension.js +105 -0
  108. package/dist/src/resources/projects.d.ts +15 -0
  109. package/dist/src/resources/projects.js +18 -3
  110. package/dist/src/resources/recipe-create.d.ts +79 -0
  111. package/dist/src/resources/recipe-create.js +454 -0
  112. package/dist/src/resources/recipes.d.ts +28 -29
  113. package/dist/src/resources/recipes.js +201 -267
  114. package/dist/src/resources/saved-models.d.ts +10 -6
  115. package/dist/src/resources/saved-models.js +16 -14
  116. package/dist/src/resources/scenarios.js +8 -14
  117. package/dist/src/resources/sql.js +52 -13
  118. package/dist/src/resources/streaming-endpoints.d.ts +12 -0
  119. package/dist/src/resources/streaming-endpoints.js +15 -0
  120. package/dist/src/resources/trained-model.d.ts +60 -0
  121. package/dist/src/resources/trained-model.js +98 -0
  122. package/dist/src/resources/webapps.d.ts +8 -0
  123. package/dist/src/resources/webapps.js +10 -0
  124. package/dist/src/resources/wiki.d.ts +52 -1
  125. package/dist/src/resources/wiki.js +96 -0
  126. package/dist/src/resources/workspaces.d.ts +2 -0
  127. package/dist/src/resources/workspaces.js +4 -0
  128. package/dist/src/utils/flow-analysis.js +4 -0
  129. package/dist/src/utils/response-file.js +20 -9
  130. package/dist/src/utils/secret-sanitize.d.ts +7 -0
  131. package/dist/src/utils/secret-sanitize.js +46 -0
  132. package/package.json +25 -26
  133. package/plugin.json +1 -1
  134. package/skills/dataiku-dss/SKILL.md +1 -1
  135. package/skills/dataiku-dss/references/authentication.md +3 -1
  136. package/skills/dataiku-dss/references/coding.md +1 -0
  137. package/skills/dataiku-dss/references/discovery.md +4 -6
  138. package/skills/dataiku-dss/references/flow-maps.md +2 -2
  139. 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 python --input orders --input customers --output orders_clean --zone Experiments",
319
- "dss recipe create --type python --input orders --output-folder LT7TUHJ8 --output-connection filesystem --dry-run",
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 contract.ts owns the
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 contract.ts owns the
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
- "download-scoring-jar": {
365
- handler: async (c, a, f) => {
366
- const usage = commandUsage("saved-model", "download-scoring-jar");
367
- requireArgs(a, 2, usage);
368
- const out = f["output"];
369
- if (!out)
370
- throw new UsageError("--output PATH is required.", "missing_required_flag");
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
- shell: string;
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