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,4 +1,5 @@
1
1
  import { readFileSync, } from "node:fs";
2
+ import { ClientValidationError, } from "../../errors.js";
2
3
  import { asRecord, } from "../../utils/records.js";
3
4
  import { compareStrings, } from "../../utils/stable-hash.js";
4
5
  import { finiteNumberField, jsonInput, optionalStringField, parseJsonObject, requiredStringArray, splitCsvFlag, } from "../coerce.js";
@@ -319,6 +320,16 @@ export function flowZonePruneItems(existing, plannedItemKeys) {
319
320
  return [];
320
321
  return flowZoneExplicitItems(existing).filter((item) => !plannedItemKeys.has(flowZoneItemKey(item)));
321
322
  }
323
+ /**
324
+ * The position an existing zone must move to, if the plan changes it. DSS
325
+ * honors a zone position only on creation, so a move means recreating the zone.
326
+ */
327
+ export function flowZoneRepositionTarget(plan, existing) {
328
+ return plan.position !== undefined
329
+ && !flowZoneSamePosition(flowZoneCurrentPosition(existing), plan.position)
330
+ ? plan.position
331
+ : undefined;
332
+ }
322
333
  export function flowZoneOrganizeStep(plan, existing, sync, plannedItemKeys) {
323
334
  ensureFlowZonePlanTarget(plan, existing);
324
335
  const update = {};
@@ -326,10 +337,8 @@ export function flowZoneOrganizeStep(plan, existing, sync, plannedItemKeys) {
326
337
  update.name = plan.name;
327
338
  if (existing && plan.color && plan.color !== existing.color)
328
339
  update.color = plan.color;
329
- if (existing && plan.position !== undefined
330
- && !flowZoneSamePosition(flowZoneCurrentPosition(existing), plan.position)) {
331
- update.position = plan.position;
332
- }
340
+ const recreatePosition = existing ? flowZoneRepositionTarget(plan, existing) : undefined;
341
+ const recreate = recreatePosition ? { position: recreatePosition, } : undefined;
333
342
  const pruneItems = sync ? flowZonePruneItems(existing, plannedItemKeys) : [];
334
343
  const moveItems = flowZoneMoveDelta(existing, plan.items);
335
344
  return {
@@ -341,10 +350,141 @@ export function flowZoneOrganizeStep(plan, existing, sync, plannedItemKeys) {
341
350
  },
342
351
  ...(existing ? { existing: flowZoneSummary(existing), } : { create: true, }),
343
352
  ...(Object.keys(update).length > 0 ? { update, } : {}),
353
+ ...(recreate ? { recreate, } : {}),
344
354
  moveItems,
355
+ ...(plan.impliedItems && plan.impliedItems.length > 0
356
+ ? { impliedItems: plan.impliedItems, }
357
+ : {}),
345
358
  ...(pruneItems.length > 0 ? { pruneItems, } : {}),
346
359
  };
347
360
  }
361
+ function flowNodeObjectType(node, knownTypes) {
362
+ switch (node.kind) {
363
+ case "recipe":
364
+ return "RECIPE";
365
+ case "dataset":
366
+ return "DATASET";
367
+ case "folder":
368
+ return "MANAGED_FOLDER";
369
+ default:
370
+ return knownTypes.get(node.id);
371
+ }
372
+ }
373
+ /**
374
+ * DSS keeps a recipe and its outputs in one zone: moving either drags the
375
+ * others. Each unit is keyed by its recipe id and lists the recipe plus every
376
+ * object the recipe writes.
377
+ */
378
+ function flowZoneUnits(graph) {
379
+ const kindById = new Map(graph.nodes.map((node) => [node.id, node.kind,]));
380
+ const units = new Map();
381
+ for (const node of graph.nodes) {
382
+ if (node.kind === "recipe")
383
+ units.set(node.id, [node.id,]);
384
+ }
385
+ for (const edge of graph.edges) {
386
+ if (kindById.get(edge.from) !== "recipe" || kindById.get(edge.to) === "recipe")
387
+ continue;
388
+ units.get(edge.from)?.push(edge.to);
389
+ }
390
+ return units;
391
+ }
392
+ function explicitTypesById(zones) {
393
+ const types = new Map();
394
+ for (const zone of zones) {
395
+ for (const item of flowZoneItems(zone)) {
396
+ if (!item.projectKey)
397
+ types.set(item.objectId, item.objectType);
398
+ }
399
+ }
400
+ return types;
401
+ }
402
+ /**
403
+ * Enforce the DSS recipe/output zone invariant on a plan. Rejects plans that
404
+ * place members of one unit in different zones (they would never converge),
405
+ * and adds the unlisted members of each planned unit to that zone as
406
+ * `impliedItems`, so moves, `--sync` pruning, and reruns all agree with what
407
+ * DSS actually does.
408
+ */
409
+ export function applyFlowZoneUnits(plan, graph, zones, projectKey) {
410
+ const zoneIndexById = new Map();
411
+ plan.zones.forEach((zonePlan, index) => {
412
+ for (const item of zonePlan.items) {
413
+ // Shared objects from other projects never move with a local recipe.
414
+ if (!item.projectKey || item.projectKey === projectKey)
415
+ zoneIndexById.set(item.objectId, index);
416
+ }
417
+ });
418
+ const nodeById = new Map(graph.nodes.map((node) => [node.id, node,]));
419
+ const knownTypes = explicitTypesById(zones);
420
+ const conflicts = [];
421
+ const implied = plan.zones.map(() => []);
422
+ for (const [recipe, members,] of flowZoneUnits(graph)) {
423
+ const planned = members.filter((member) => zoneIndexById.has(member));
424
+ if (planned.length === 0)
425
+ continue;
426
+ const indexes = new Set(planned.map((member) => zoneIndexById.get(member)));
427
+ if (indexes.size > 1) {
428
+ const byZone = {};
429
+ for (const member of planned) {
430
+ const label = flowZonePlanLabel(plan.zones[zoneIndexById.get(member)]);
431
+ (byZone[label] ??= []).push(member);
432
+ }
433
+ conflicts.push({ recipe, zones: byZone, });
434
+ continue;
435
+ }
436
+ const [index,] = indexes;
437
+ for (const member of members) {
438
+ if (zoneIndexById.has(member))
439
+ continue;
440
+ const node = nodeById.get(member);
441
+ const objectType = node ? flowNodeObjectType(node, knownTypes) : undefined;
442
+ if (objectType)
443
+ implied[index].push({ objectType, objectId: member, });
444
+ }
445
+ }
446
+ if (conflicts.length > 0) {
447
+ throw new ClientValidationError(`Flow zone plan splits ${conflicts.length} recipe(s) from their outputs across zones; DSS keeps a recipe and its outputs in one zone.`, "validation_failed", "Assign each recipe to one zone (its outputs follow automatically), or list the recipe and all its outputs in the same zone.", { conflicts, });
448
+ }
449
+ return {
450
+ ...plan,
451
+ zones: plan.zones.map((zonePlan, index) => implied[index].length === 0
452
+ ? zonePlan
453
+ : {
454
+ ...zonePlan,
455
+ items: [...zonePlan.items, ...implied[index],],
456
+ impliedItems: implied[index],
457
+ }),
458
+ };
459
+ }
460
+ /**
461
+ * Default-zone objects an organization plan has to place: recipes (their
462
+ * outputs follow) and objects no recipe produces, such as uploaded sources.
463
+ */
464
+ export function flowZoneUnassignedItems(graph, zones) {
465
+ const assigned = new Set();
466
+ for (const zone of zones) {
467
+ if (zone.id === "default")
468
+ continue;
469
+ for (const item of flowZoneExplicitItems(zone))
470
+ assigned.add(item.objectId);
471
+ }
472
+ const produced = new Set();
473
+ for (const members of flowZoneUnits(graph).values()) {
474
+ for (const member of members.slice(1))
475
+ produced.add(member);
476
+ }
477
+ const knownTypes = explicitTypesById(zones);
478
+ const items = [];
479
+ for (const node of graph.nodes) {
480
+ if (assigned.has(node.id) || produced.has(node.id))
481
+ continue;
482
+ const objectType = flowNodeObjectType(node, knownTypes);
483
+ if (objectType)
484
+ items.push({ objectType, objectId: node.id, });
485
+ }
486
+ return items.sort((a, b) => compareStrings(flowZoneItemKey(a), flowZoneItemKey(b)));
487
+ }
348
488
  export function flowZoneValidationBucket(index, objectType) {
349
489
  switch (objectType) {
350
490
  case "DATASET":
@@ -0,0 +1,26 @@
1
+ import type { DataikuClient } from "../../client.js";
2
+ import { type ComputedModelDiagnostic, type ModelDiagnostic, type ModelDiagnosticsComputation, type TrainedModel } from "../../resources/trained-model.js";
3
+ import type { CommandDefinition } from "../types.js";
4
+ type Flags = Record<string, string | boolean>;
5
+ export declare function diagnosticKindFromFlags(flags: Flags): ModelDiagnostic;
6
+ /** `compute-diagnostics` flags → kind, features, and computation settings (shared with --plan). */
7
+ export declare function diagnosticsComputationFromFlags(flags: Flags): {
8
+ kind: ComputedModelDiagnostic;
9
+ features: string[];
10
+ computation: ModelDiagnosticsComputation;
11
+ };
12
+ export interface TrainedModelCommandSpec {
13
+ resource: "ml-task" | "saved-model";
14
+ /** Positional ids in examples, e.g. `ANALYSIS_ID TASK_ID MODEL_ID`. */
15
+ ids: string;
16
+ /** What one model is called in descriptions: "lab model" or "saved-model version". */
17
+ noun: string;
18
+ model: (client: DataikuClient, args: string[], projectKey: string | undefined) => TrainedModel;
19
+ downloadDocumentation: (client: DataikuClient, exportId: string, projectKey: string | undefined) => Promise<Response>;
20
+ }
21
+ /**
22
+ * The actions lab models and saved-model versions share, over one
23
+ * {@link TrainedModel}: user meta, scoring exports, diagnostics, documentation.
24
+ */
25
+ export declare function trainedModelCommands(spec: TrainedModelCommandSpec): Record<string, CommandDefinition>;
26
+ export {};
@@ -0,0 +1,144 @@
1
+ import { unexpectedResponseError, } from "../../errors.js";
2
+ import { COMPUTED_MODEL_DIAGNOSTICS, MODEL_DIAGNOSTICS, } from "../../resources/trained-model.js";
3
+ import { writeResponseToFile, } from "../../utils/response-file.js";
4
+ import { num, parseBooleanOption, requiredJsonInput, splitCsvFlag, } from "../coerce.js";
5
+ import { executionMode, } from "../flags.js";
6
+ import { commandUsage, } from "../syntax.js";
7
+ import { requireArgs, UsageError, } from "../usage.js";
8
+ import { documentationTemplateFromFlags, runDocumentationCommand, taskWaitOptions, } from "./documentation.js";
9
+ export function diagnosticKindFromFlags(flags) {
10
+ const kind = flags["kind"];
11
+ if (typeof kind !== "string" || MODEL_DIAGNOSTICS[kind] !== true) {
12
+ throw new UsageError(`--kind must be one of ${Object.keys(MODEL_DIAGNOSTICS).join(", ")}.`, "invalid_enum");
13
+ }
14
+ return kind;
15
+ }
16
+ /** `compute-diagnostics` flags → kind, features, and computation settings (shared with --plan). */
17
+ export function diagnosticsComputationFromFlags(flags) {
18
+ const kind = flags["kind"];
19
+ if (typeof kind !== "string" || COMPUTED_MODEL_DIAGNOSTICS[kind] !== true) {
20
+ throw new UsageError(`--kind must be one of ${Object.keys(COMPUTED_MODEL_DIAGNOSTICS).join(", ")}.`, "invalid_enum");
21
+ }
22
+ const sampleSize = num(flags["sample-size"], "--sample-size");
23
+ const randomState = num(flags["random-state"], "--random-state");
24
+ const nJobs = num(flags["n-jobs"], "--n-jobs");
25
+ return {
26
+ kind: kind,
27
+ features: splitCsvFlag(flags["features"]),
28
+ computation: {
29
+ ...(sampleSize !== undefined ? { sampleSize, } : {}),
30
+ ...(randomState !== undefined ? { randomState, } : {}),
31
+ ...(nJobs !== undefined ? { nJobs, } : {}),
32
+ },
33
+ };
34
+ }
35
+ /** Write a binary export to `--output`; DSS answering without a body is an unexpected response. */
36
+ async function writeExport(res, out, operation) {
37
+ if (!res.body)
38
+ throw unexpectedResponseError(`${operation} response did not include a body`);
39
+ return { path: out, bytes: await writeResponseToFile(out, res), };
40
+ }
41
+ function requiredOutput(flags) {
42
+ const out = flags["output"];
43
+ if (typeof out !== "string") {
44
+ throw new UsageError("--output PATH is required.", "missing_required_flag");
45
+ }
46
+ return out;
47
+ }
48
+ /**
49
+ * The actions lab models and saved-model versions share, over one
50
+ * {@link TrainedModel}: user meta, scoring exports, diagnostics, documentation.
51
+ */
52
+ export function trainedModelCommands(spec) {
53
+ const { resource, ids, noun, } = spec;
54
+ const argCount = ids.split(" ").length;
55
+ const model = (c, a, f, action) => {
56
+ requireArgs(a, argCount, commandUsage(resource, action));
57
+ return spec.model(c, a, f["project-key"]);
58
+ };
59
+ return {
60
+ "set-user-meta": {
61
+ handler: async (c, a, f) => {
62
+ const target = model(c, a, f, "set-user-meta");
63
+ const userMeta = requiredJsonInput(f, "User-meta JSON is required via --data, --data-file, or --stdin.");
64
+ if (executionMode(f).dryRun) {
65
+ return {
66
+ dryRun: true,
67
+ action: "set-user-meta",
68
+ resource,
69
+ ids: a.slice(0, argCount),
70
+ payload: userMeta,
71
+ };
72
+ }
73
+ await target.setUserMeta(userMeta);
74
+ return { updated: a[argCount - 1], resource, };
75
+ },
76
+ description: `Update the user metadata (name, description, labels, ...) of a ${noun}. Send only the "userMeta" field of its details, edited.`,
77
+ examples: [
78
+ `dss ${resource} set-user-meta ${ids} --data '{"name":"Churn model","description":"v2"}'`,
79
+ ],
80
+ },
81
+ "download-scoring-jar": {
82
+ handler: async (c, a, f) => {
83
+ const target = model(c, a, f, "download-scoring-jar");
84
+ const out = requiredOutput(f);
85
+ const fullClassName = f["full-class-name"];
86
+ const res = await target.downloadScoringJar({
87
+ ...(typeof fullClassName === "string" ? { fullClassName, } : {}),
88
+ ...(f["include-libs"] !== undefined
89
+ ? { includeLibs: parseBooleanOption(f["include-libs"], "--include-libs"), }
90
+ : {}),
91
+ });
92
+ return writeExport(res, out, "Scoring JAR download");
93
+ },
94
+ description: `Download the optimized scoring JAR of a ${noun} (license-gated server side). --full-class-name sets the Java class; --include-libs toggles bundling the scoring libraries.`,
95
+ examples: [`dss ${resource} download-scoring-jar ${ids} --output ./scoring.jar`,],
96
+ },
97
+ "download-scoring-pmml": {
98
+ handler: async (c, a, f) => {
99
+ const target = model(c, a, f, "download-scoring-pmml");
100
+ const out = requiredOutput(f);
101
+ return writeExport(await target.downloadScoringPmml(), out, "Scoring PMML download");
102
+ },
103
+ description: `Download the PMML scoring file of a ${noun} (license-gated server side).`,
104
+ examples: [`dss ${resource} download-scoring-pmml ${ids} --output ./model.pmml`,],
105
+ },
106
+ diagnostics: {
107
+ handler: (c, a, f) => model(c, a, f, "diagnostics").get(diagnosticKindFromFlags(f)),
108
+ description: `Read computed diagnostics of a ${noun}: subpopulation-analyses, partial-dependencies, timeseries-residuals, or (forecasting) per-timeseries-metrics / per-timeseries-evaluation-forecasts.`,
109
+ examples: [`dss ${resource} diagnostics ${ids} --kind partial-dependencies`,],
110
+ },
111
+ "compute-diagnostics": {
112
+ handler: async (c, a, f) => {
113
+ const target = model(c, a, f, "compute-diagnostics");
114
+ const { kind, features, computation, } = diagnosticsComputationFromFlags(f);
115
+ const task = await target.compute(kind, features, computation);
116
+ return f["wait"] === true ? c.futures.waitTask(task, taskWaitOptions(f)) : task;
117
+ },
118
+ description: `Compute subpopulation-analyses or partial-dependencies over --features COLS (--sample-size N, default 10000), or timeseries-residuals, for a ${noun}. Returns the DSS future; --wait waits and returns the result.`,
119
+ examples: [
120
+ `dss ${resource} compute-diagnostics ${ids} --kind partial-dependencies --features age,income --wait`,
121
+ ],
122
+ },
123
+ "generate-documentation": {
124
+ handler: async (c, a, f) => {
125
+ const target = model(c, a, f, "generate-documentation");
126
+ const pk = f["project-key"];
127
+ const task = await target.generateDocumentation(documentationTemplateFromFlags(f));
128
+ return runDocumentationCommand(c, f, task, (exportId) => spec.downloadDocumentation(c, exportId, pk));
129
+ },
130
+ description: `Generate the model documentation (Word docx) of a ${noun} from the DSS default template, an uploaded --template-file, or a template in a managed folder (--folder FOLDER_ID --path PATH). Returns the DSS future; --wait waits; --output PATH waits and downloads.`,
131
+ examples: [`dss ${resource} generate-documentation ${ids} --output model.docx`,],
132
+ },
133
+ "download-documentation": {
134
+ handler: async (c, a, f) => {
135
+ requireArgs(a, 1, commandUsage(resource, "download-documentation"));
136
+ const out = requiredOutput(f);
137
+ const res = await spec.downloadDocumentation(c, a[0], f["project-key"]);
138
+ return writeExport(res, out, "Model documentation download");
139
+ },
140
+ description: "Download a generated model documentation by the exportId from a finished generate-documentation future.",
141
+ examples: [`dss ${resource} download-documentation EXPORT_ID --output model.docx`,],
142
+ },
143
+ };
144
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Shape a `*.list` result for agents: `--contains` filters on identifier
3
+ * fields, `--limit` caps the count (a `list_truncated` warning reports the
4
+ * total), and large DSS objects compact to their decision fields unless
5
+ * `--full` or `--fields` asks for the DSS objects.
6
+ */
7
+ export declare function shapeListResult(resource: string, result: unknown, flags: Record<string, string | boolean>): unknown;
@@ -0,0 +1,77 @@
1
+ import { num, } from "./coerce.js";
2
+ import { COMPACT_LIST_FIELDS, } from "./list-shapes.js";
3
+ import { enqueueCliWarning, } from "./output.js";
4
+ function record(value) {
5
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
6
+ }
7
+ function compactValue(item, spec) {
8
+ let value = item;
9
+ for (const key of spec.path.split("."))
10
+ value = record(value)[key];
11
+ if (spec.roleRefs !== true)
12
+ return value;
13
+ // Dataset refs across every role of recipe inputs/outputs (`{main:{items:[{ref}]}}`).
14
+ return Object.values(record(value)).flatMap((role) => {
15
+ const items = record(role).items;
16
+ return Array.isArray(items)
17
+ ? items.flatMap((entry) => {
18
+ const ref = record(entry).ref;
19
+ return typeof ref === "string" ? [ref,] : [];
20
+ })
21
+ : [];
22
+ });
23
+ }
24
+ /** Identifier fields `--contains` matches; string items match themselves. */
25
+ const IDENTIFIER_FIELDS = [
26
+ "id",
27
+ "name",
28
+ "projectKey",
29
+ "envName",
30
+ "login",
31
+ "displayName",
32
+ "label",
33
+ "runnableType",
34
+ ];
35
+ /** `job list` filters by --contains/--limit itself (job name, state, outputs). */
36
+ const LISTS_WITH_OWN_FILTERS = { job: true, };
37
+ function itemMatches(item, needle) {
38
+ if (typeof item === "string")
39
+ return item.toLowerCase().includes(needle);
40
+ const fields = record(item);
41
+ return IDENTIFIER_FIELDS.some((field) => {
42
+ const value = fields[field];
43
+ return typeof value === "string" && value.toLowerCase().includes(needle);
44
+ });
45
+ }
46
+ /**
47
+ * Shape a `*.list` result for agents: `--contains` filters on identifier
48
+ * fields, `--limit` caps the count (a `list_truncated` warning reports the
49
+ * total), and large DSS objects compact to their decision fields unless
50
+ * `--full` or `--fields` asks for the DSS objects.
51
+ */
52
+ export function shapeListResult(resource, result, flags) {
53
+ if (!Array.isArray(result))
54
+ return result;
55
+ let items = result;
56
+ if (LISTS_WITH_OWN_FILTERS[resource] !== true) {
57
+ const contains = flags["contains"];
58
+ if (typeof contains === "string" && contains.length > 0) {
59
+ const needle = contains.toLowerCase();
60
+ items = items.filter((item) => itemMatches(item, needle));
61
+ }
62
+ const limit = num(flags["limit"], "--limit");
63
+ if (limit !== undefined && items.length > limit) {
64
+ enqueueCliWarning({
65
+ code: "list_truncated",
66
+ shown: limit,
67
+ total: items.length,
68
+ hint: "Raise --limit or narrow with --contains.",
69
+ });
70
+ items = items.slice(0, Math.max(0, limit));
71
+ }
72
+ }
73
+ const fields = COMPACT_LIST_FIELDS[resource];
74
+ if (!fields || flags["full"] === true || typeof flags["fields"] === "string")
75
+ return items;
76
+ return items.map((item) => Object.fromEntries(Object.entries(fields).map(([name, spec,]) => [name, compactValue(record(item), spec),])));
77
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Compact `RESOURCE.list` item shapes, as plain data shared by the runtime
3
+ * mapper (src/cli/list-output.ts) and the discovery output schemas
4
+ * (src/cli/output-schemas.ts), so the advertised schema is the emitted shape.
5
+ */
6
+ /** Where a compact field comes from in the DSS object, and its JSON Schema. */
7
+ export interface CompactListField {
8
+ /** Dotted path into the DSS list item. */
9
+ path: string;
10
+ /** Flatten recipe roles (`{main:{items:[{ref}]}}`) to the dataset refs. */
11
+ roleRefs?: true;
12
+ schema: Record<string, unknown>;
13
+ }
14
+ /**
15
+ * Lists whose DSS objects are large: the identifier the follow-up get/build
16
+ * commands take, the kind, and the one or two attributes that decide what to
17
+ * call next. Lists not named here keep the DSS objects.
18
+ */
19
+ export declare const COMPACT_LIST_FIELDS: Record<string, Record<string, CompactListField>>;
20
+ /** Discovery output schemas of the compact `RESOURCE.list` defaults. */
21
+ export declare function compactListOutputSchemas(): Record<string, Record<string, unknown>>;
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Compact `RESOURCE.list` item shapes, as plain data shared by the runtime
3
+ * mapper (src/cli/list-output.ts) and the discovery output schemas
4
+ * (src/cli/output-schemas.ts), so the advertised schema is the emitted shape.
5
+ */
6
+ const STRING = { type: ["string", "null",], };
7
+ const BOOLEAN = { type: ["boolean", "null",], };
8
+ const NUMBER = { type: ["number", "null",], };
9
+ const STRINGS = { type: "array", items: { type: "string", }, };
10
+ const field = (path, schema) => ({
11
+ path,
12
+ schema,
13
+ });
14
+ /**
15
+ * Lists whose DSS objects are large: the identifier the follow-up get/build
16
+ * commands take, the kind, and the one or two attributes that decide what to
17
+ * call next. Lists not named here keep the DSS objects.
18
+ */
19
+ export const COMPACT_LIST_FIELDS = {
20
+ project: {
21
+ projectKey: field("projectKey", STRING),
22
+ name: field("name", STRING),
23
+ ownerLogin: field("ownerLogin", STRING),
24
+ },
25
+ dataset: {
26
+ name: field("name", STRING),
27
+ type: field("type", STRING),
28
+ managed: field("managed", BOOLEAN),
29
+ connection: field("params.connection", STRING),
30
+ },
31
+ recipe: {
32
+ name: field("name", STRING),
33
+ type: field("type", STRING),
34
+ inputs: { path: "inputs", roleRefs: true, schema: STRINGS, },
35
+ outputs: { path: "outputs", roleRefs: true, schema: STRINGS, },
36
+ },
37
+ scenario: {
38
+ id: field("id", STRING),
39
+ name: field("name", STRING),
40
+ type: field("type", STRING),
41
+ active: field("active", BOOLEAN),
42
+ running: field("running", BOOLEAN),
43
+ },
44
+ folder: {
45
+ id: field("id", STRING),
46
+ name: field("name", STRING),
47
+ type: field("type", STRING),
48
+ connection: field("params.connection", STRING),
49
+ },
50
+ job: {
51
+ id: field("def.id", STRING),
52
+ name: field("def.name", STRING),
53
+ type: field("def.type", STRING),
54
+ state: field("state", STRING),
55
+ startTime: field("startTime", NUMBER),
56
+ endTime: field("endTime", NUMBER),
57
+ },
58
+ "code-env": {
59
+ envName: field("envName", STRING),
60
+ envLang: field("envLang", STRING),
61
+ deploymentMode: field("deploymentMode", STRING),
62
+ },
63
+ future: {
64
+ jobId: field("jobId", STRING),
65
+ owner: field("owner", STRING),
66
+ alive: field("alive", BOOLEAN),
67
+ hasResult: field("hasResult", BOOLEAN),
68
+ runningTime: field("runningTime", NUMBER),
69
+ },
70
+ user: {
71
+ login: field("login", STRING),
72
+ displayName: field("displayName", STRING),
73
+ userProfile: field("userProfile", STRING),
74
+ groups: field("groups", STRINGS),
75
+ enabled: field("enabled", BOOLEAN),
76
+ },
77
+ group: {
78
+ name: field("name", STRING),
79
+ description: field("description", STRING),
80
+ admin: field("admin", BOOLEAN),
81
+ },
82
+ plugin: {
83
+ id: field("id", STRING),
84
+ version: field("version", STRING),
85
+ label: field("meta.label", STRING),
86
+ },
87
+ macro: {
88
+ runnableType: field("runnableType", STRING),
89
+ ownerPluginId: field("ownerPluginId", STRING),
90
+ label: field("meta.label", STRING),
91
+ },
92
+ meaning: {
93
+ id: field("id", STRING),
94
+ label: field("label", STRING),
95
+ type: field("type", STRING),
96
+ },
97
+ };
98
+ /** Discovery output schemas of the compact `RESOURCE.list` defaults. */
99
+ export function compactListOutputSchemas() {
100
+ return Object.fromEntries(Object.entries(COMPACT_LIST_FIELDS).map(([resource, fields,]) => [
101
+ `${resource}.list`,
102
+ {
103
+ type: "array",
104
+ items: {
105
+ type: "object",
106
+ additionalProperties: false,
107
+ properties: Object.fromEntries(Object.entries(fields).map(([name, spec,]) => [name, spec.schema,])),
108
+ },
109
+ },
110
+ ]));
111
+ }
@@ -1,17 +1,3 @@
1
- /**
2
- * Canonical discovery output schemas, keyed by `resource.action`.
3
- *
4
- * TypeBox definitions from `packages/types` plus the inline literal schemas
5
- * that exist only on the CLI side (code-env log envelope, code.run outcome,
6
- * project-library payloads, notebook saves, sql.query handoff envelope).
7
- * `scripts/generate-action-output-schemas.mjs` serializes this map into
8
- * `src/generated/action-output-schemas.json`; discovery (src/cli/contract.ts)
9
- * reads that generated JSON as plain data, so the TypeBox schema graph never
10
- * loads on the discovery path. SDK validation keeps using the TypeBox schema
11
- * objects from `packages/types` directly.
12
- *
13
- * Imported by the generator and the discovery parity test only.
14
- */
15
1
  /**
16
2
  * Canonical TypeBox-derived output schemas, keyed by `resource.action`. This is
17
3
  * the single source of truth for `src/generated/action-output-schemas.json`,
@@ -12,6 +12,7 @@
12
12
  *
13
13
  * Imported by the generator and the discovery parity test only.
14
14
  */
15
+ import { compactListOutputSchemas, } from "./list-shapes.js";
15
16
  const PROJECT_LIBRARY_ITEM_OUTPUT_SCHEMA = {
16
17
  type: "object",
17
18
  additionalProperties: false,
@@ -62,9 +63,8 @@ let commandOutputSchemas;
62
63
  export function typeBoxCommandOutputSchemas() {
63
64
  if (commandOutputSchemas)
64
65
  return commandOutputSchemas;
65
- const { CodeEnvDetailsSchema, CodeEnvLogSummaryArraySchema, CodeEnvSummaryArraySchema, CodeEnvUsageArraySchema, CodeEnvVersionForProjectSchema, DatasetDetailsSchema, DatasetSchemaSchema, DatasetSummaryArraySchema, FlowZoneArraySchema, FlowZoneSchema, JobSummaryArraySchema, JobWaitResultSchema, JupyterNotebookContentSchema, JupyterNotebookSummaryArraySchema, NotebookSessionArraySchema, ProjectDetailsSchema, ProjectMetadataSchema, ProjectSummaryArraySchema, RecipeSummaryArraySchema, ScenarioDetailsSchema, ScenarioStatusSchema, ScenarioSummaryArraySchema, SqlNotebookContentSchema, SqlNotebookHistorySchema, SqlNotebookSummaryArraySchema, SqlQueryResponseSchema, } = require("../schemas.js");
66
+ const { CodeEnvDetailsSchema, CodeEnvLogSummaryArraySchema, CodeEnvUsageArraySchema, CodeEnvVersionForProjectSchema, DatasetDetailsSchema, DatasetSchemaSchema, FlowZoneArraySchema, FlowZoneSchema, JobWaitResultSchema, JupyterNotebookContentSchema, JupyterNotebookSummaryArraySchema, NotebookSessionArraySchema, ProjectDetailsSchema, ProjectMetadataSchema, ScenarioDetailsSchema, ScenarioStatusSchema, SqlNotebookContentSchema, SqlNotebookHistorySchema, SqlNotebookSummaryArraySchema, SqlQueryResponseSchema, } = require("../schemas.js");
66
67
  return commandOutputSchemas = {
67
- "code-env.list": CodeEnvSummaryArraySchema,
68
68
  "code-env.get": CodeEnvDetailsSchema,
69
69
  "code-env.list-logs": CodeEnvLogSummaryArraySchema,
70
70
  "code-env.get-log": {
@@ -196,17 +196,12 @@ export function typeBoxCommandOutputSchemas() {
196
196
  maxLines: { type: "integer", minimum: 0, },
197
197
  },
198
198
  },
199
- "project.list": ProjectSummaryArraySchema,
200
199
  "project.get": ProjectDetailsSchema,
201
200
  "project.metadata": ProjectMetadataSchema,
202
- "dataset.list": DatasetSummaryArraySchema,
203
201
  "dataset.get": DatasetDetailsSchema,
204
202
  "dataset.schema": DatasetSchemaSchema,
205
- "recipe.list": RecipeSummaryArraySchema,
206
- "job.list": JobSummaryArraySchema,
207
203
  "job.wait": JobWaitResultSchema,
208
204
  "job.monitor": JobWaitResultSchema,
209
- "scenario.list": ScenarioSummaryArraySchema,
210
205
  "scenario.get": ScenarioDetailsSchema,
211
206
  "scenario.status": ScenarioStatusSchema,
212
207
  "flow-zone.list": FlowZoneArraySchema,
@@ -229,5 +224,7 @@ export function typeBoxCommandOutputSchemas() {
229
224
  },
230
225
  ],
231
226
  },
227
+ // `*.list` defaults to compact items; `--full` returns the DSS objects.
228
+ ...compactListOutputSchemas(),
232
229
  };
233
230
  }
@@ -12,7 +12,6 @@ export declare function pickResultFields(item: unknown, fields: string[]): unkno
12
12
  */
13
13
  export declare function projectResultFields(result: unknown, fields: string[], availableFieldNames?: () => string[]): unknown;
14
14
  export declare function writeCommandResult(result: unknown): void;
15
- export declare function transientBodyWithTargetContext(body: string, target: string, elapsedMs: number): string;
16
15
  export declare function addTransientTargetContext(error: unknown, target: string, elapsedMs: number): never;
17
16
  export declare function isFailedWaitResult(result: unknown): boolean;
18
17
  export declare function isAssertionFailureResult(result: unknown): boolean;