dataiku-sdk 3.1.0 → 3.2.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 (58) hide show
  1. package/README.md +124 -12
  2. package/dist/build-metadata.json +1 -1
  3. package/dist/src/auth.js +1 -1
  4. package/dist/src/cli/coerce.js +11 -2
  5. package/dist/src/cli/commands/analysis.js +4 -3
  6. package/dist/src/cli/commands/api-service.js +5 -3
  7. package/dist/src/cli/commands/app.js +4 -3
  8. package/dist/src/cli/commands/bundle.js +2 -1
  9. package/dist/src/cli/commands/code-env.js +10 -9
  10. package/dist/src/cli/commands/dashboard.js +7 -6
  11. package/dist/src/cli/commands/data-quality.js +9 -8
  12. package/dist/src/cli/commands/dataset.js +9 -8
  13. package/dist/src/cli/commands/doctor.js +4 -2
  14. package/dist/src/cli/commands/flow-zone.js +9 -8
  15. package/dist/src/cli/commands/folder.js +9 -8
  16. package/dist/src/cli/commands/future.js +2 -1
  17. package/dist/src/cli/commands/insight.js +8 -7
  18. package/dist/src/cli/commands/job.js +4 -3
  19. package/dist/src/cli/commands/meaning.js +5 -4
  20. package/dist/src/cli/commands/ml-task.js +3 -2
  21. package/dist/src/cli/commands/model-evaluation-store.js +4 -3
  22. package/dist/src/cli/commands/notebook.js +11 -10
  23. package/dist/src/cli/commands/project-library.js +7 -6
  24. package/dist/src/cli/commands/project.js +3 -2
  25. package/dist/src/cli/commands/recipe.js +14 -13
  26. package/dist/src/cli/commands/saved-model.js +4 -3
  27. package/dist/src/cli/commands/scenario.js +9 -8
  28. package/dist/src/cli/commands/sql.js +3 -2
  29. package/dist/src/cli/commands/statistics.js +7 -6
  30. package/dist/src/cli/commands/variable.js +2 -1
  31. package/dist/src/cli/commands/webapp.js +2 -1
  32. package/dist/src/cli/commands/wiki.js +7 -6
  33. package/dist/src/cli/contract.d.ts +1 -1
  34. package/dist/src/cli/contract.js +100 -82
  35. package/dist/src/cli/flags.d.ts +4 -0
  36. package/dist/src/cli/flags.js +20 -1
  37. package/dist/src/cli.js +92 -68
  38. package/dist/src/client.d.ts +3 -1
  39. package/dist/src/client.js +78 -21
  40. package/dist/src/errors.js +2 -0
  41. package/dist/src/resources/folders.js +2 -1
  42. package/dist/src/resources/projects.d.ts +0 -2
  43. package/dist/src/resources/projects.js +3 -17
  44. package/dist/src/resources/sql.js +1 -1
  45. package/dist/src/skill.d.ts +13 -4
  46. package/dist/src/skill.js +75 -24
  47. package/dist/src/utils/response-file.d.ts +2 -0
  48. package/dist/src/utils/response-file.js +34 -0
  49. package/package.json +6 -4
  50. package/plugin.json +1 -1
  51. package/skills/dataiku-dss/SKILL.md +44 -224
  52. package/skills/dataiku-dss/references/app-releases.md +27 -0
  53. package/skills/dataiku-dss/references/authentication.md +39 -0
  54. package/skills/dataiku-dss/references/coding.md +8 -0
  55. package/skills/dataiku-dss/references/discovery.md +30 -0
  56. package/skills/dataiku-dss/references/flow-maps.md +12 -0
  57. package/skills/dataiku-dss/references/mutations.md +33 -0
  58. package/skills/dataiku-dss/references/troubleshooting.md +29 -0
package/dist/src/cli.js CHANGED
@@ -1,22 +1,32 @@
1
1
  #!/usr/bin/env node
2
2
  import * as fs from "node:fs/promises";
3
+ import { homedir, } from "node:os";
4
+ import { resolve, } from "node:path";
3
5
  import { num, unknownJsonInput, } from "./cli/coerce.js";
4
- import { commands, } from "./cli/commands/index.js";
5
- import { AGENT_CONTRACT_USAGE, AUTH_ACTIONS, BATCH_EXAMPLE_PAYLOAD, BATCH_HINT, BATCH_PLAN_EXIT_CODES, BATCH_USAGE, buildAgentContract, buildCommandRegistry, buildMutationPlan, CLEANUP_USAGE, commandActionSummary, COMMANDS_USAGE, inferRequiresProject, isAllowedCleanupAction, supportsCleanupLedger, } from "./cli/contract.js";
6
- import { runDoctor, runFixtures, } from "./cli/doctor.js";
7
6
  import { dataikuEnvironmentEnabled, loadEnvFile, } from "./cli/env.js";
8
- import { FLAG_ALIASES, isNegativeNumberToken, parseArgs, SHORT_FLAGS, VALUE_FLAGS, } from "./cli/flags.js";
7
+ import { executionMode, FLAG_ALIASES, isNegativeNumberToken, parseArgs, SHORT_FLAGS, VALUE_FLAGS, } from "./cli/flags.js";
9
8
  import { cleanupLedgerEntry, } from "./cli/helpers/cleanup.js";
10
9
  import { commandFailureExitCode, CommandResultFailure, flushCliWarnings, isFailedWaitResult, planResult, projectResultFields, setOutputFieldProjection, writeCommandResult, } from "./cli/output.js";
11
10
  import { currentCommandContext, resolveCredentials, resolveLoginCredentials, } from "./cli/runtime.js";
12
11
  import { COMMANDS_RUN_HINT, missingActionError, noCommandError, requireArgs, unknownActionError, unknownResourceError, UsageError, } from "./cli/usage.js";
13
12
  import { cliVersionResult, } from "./cli/version.js";
14
- import { DataikuClient, } from "./client.js";
15
13
  import { getCredentialsPath, } from "./config.js";
16
14
  import { canonicalStatusText, ClientValidationError, DataikuError, dataikuErrorCode, } from "./errors.js";
17
- import { AGENTS, detectAgents, findWorkspaceRoot, installSkill, planSkillInstalls, } from "./skill.js";
18
15
  import { appendCleanupLedgerEntry, findCleanupLedgerBindingViolation, preflightCleanupLedgerPath, readCleanupLedger, reserveCleanupLedgerDssUrl, } from "./utils/cleanup-ledger.js";
19
16
  import { canonicalDssUrl, } from "./utils/dss-url.js";
17
+ let commands;
18
+ let contract;
19
+ let commandRuntimeLoad;
20
+ // Dispatch and error reporting initialize these bindings before synchronous validation.
21
+ function loadCommandRuntime() {
22
+ return commandRuntimeLoad ??= Promise.all([
23
+ import("./cli/commands/index.js"),
24
+ import("./cli/contract.js"),
25
+ ]).then(([commandModule, contractModule,]) => {
26
+ commands = commandModule.commands;
27
+ contract = contractModule;
28
+ });
29
+ }
20
30
  // ---------------------------------------------------------------------------
21
31
  // Arg parsing
22
32
  // ---------------------------------------------------------------------------
@@ -60,7 +70,7 @@ function findUnboundLifecycleCleanup(entries) {
60
70
  async function runCleanup(flags) {
61
71
  const filePath = flags["file"];
62
72
  if (typeof filePath !== "string" || filePath.trim().length === 0) {
63
- throw new UsageError(`--file is required. Usage: ${CLEANUP_USAGE}`);
73
+ throw new UsageError(`--file is required. Usage: ${contract.CLEANUP_USAGE}`);
64
74
  }
65
75
  let entries;
66
76
  try {
@@ -95,6 +105,7 @@ async function runCleanup(flags) {
95
105
  }
96
106
  const requestTimeoutMs = num(flags["request-timeout"], "--request-timeout");
97
107
  const retryMaxAttempts = num(flags["retries"], "--retries");
108
+ const { DataikuClient, } = await import("./client.js");
98
109
  const client = new DataikuClient({
99
110
  url,
100
111
  apiKey,
@@ -158,7 +169,7 @@ async function runCleanup(flags) {
158
169
  action,
159
170
  projectKey: parsed.flags["project-key"],
160
171
  });
161
- if (!resource || !action || !isAllowedCleanupAction(resource, action)
172
+ if (!resource || !action || !contract.isAllowedCleanupAction(resource, action)
162
173
  || !commands[resource]?.[action]) {
163
174
  throw new UsageError(`Invalid cleanup argv: ${entry.cleanup.argv.join(" ")}`);
164
175
  }
@@ -231,11 +242,11 @@ async function runCleanup(flags) {
231
242
  }
232
243
  function parseBatchSteps(payload) {
233
244
  if (!Array.isArray(payload)) {
234
- throw new UsageError("Batch payload must be a JSON array of command-argument arrays.", "validation_failed", BATCH_HINT, { example: BATCH_EXAMPLE_PAYLOAD, });
245
+ throw new UsageError("Batch payload must be a JSON array of command-argument arrays.", "validation_failed", contract.BATCH_HINT, { example: contract.BATCH_EXAMPLE_PAYLOAD, });
235
246
  }
236
247
  return payload.map((step, index) => {
237
248
  if (!Array.isArray(step) || !step.every((token) => typeof token === "string")) {
238
- throw new UsageError(`Batch step ${index} must be an array of string arguments.`, "validation_failed", BATCH_HINT);
249
+ throw new UsageError(`Batch step ${index} must be an array of string arguments.`, "validation_failed", contract.BATCH_HINT);
239
250
  }
240
251
  return step;
241
252
  });
@@ -266,12 +277,12 @@ const META_COMMAND_RESOURCES = {
266
277
  fixtures: true,
267
278
  batch: true,
268
279
  };
269
- let commandRegistryCache;
270
- function cachedCommandRegistry() {
271
- if (commandRegistryCache === undefined) {
272
- commandRegistryCache = buildCommandRegistry();
280
+ const commandRegistryCache = new Map();
281
+ function cachedCommandRegistry(resource) {
282
+ if (!commandRegistryCache.has(resource)) {
283
+ commandRegistryCache.set(resource, contract.buildCommandRegistry(resource)[resource]);
273
284
  }
274
- return commandRegistryCache;
285
+ return commandRegistryCache.get(resource);
275
286
  }
276
287
  function supportedCommandFlags(entry) {
277
288
  const supported = { ...ALWAYS_ALLOWED_COMMAND_FLAGS, };
@@ -309,7 +320,7 @@ function commandRegistrySelectors(flags) {
309
320
  return selectors;
310
321
  }
311
322
  function validateSupportedCommandFlags(resource, action, flags) {
312
- const entry = cachedCommandRegistry()[resource]?.[action];
323
+ const entry = cachedCommandRegistry(resource)?.[action];
313
324
  if (!entry)
314
325
  return;
315
326
  const supported = supportedCommandFlags(entry);
@@ -318,7 +329,7 @@ function validateSupportedCommandFlags(resource, action, flags) {
318
329
  throw new UsageError(`Unknown flag --${flagName} for ${resource} ${action}`, "unknown_flag", scopedCommandDiscoveryHint(resource, action));
319
330
  }
320
331
  }
321
- if (flags["dry-run"] === true && !entry.dryRun) {
332
+ if (executionMode(flags).dryRun && !entry.dryRun) {
322
333
  throw new UsageError(`--dry-run is not supported for ${resource} ${action}.`, "unknown_flag", entry.flags.some((flag) => flag.name === "plan")
323
334
  ? "Remove --dry-run; use --plan to preview the mutation instead."
324
335
  : `Remove --dry-run; ${resource} ${action} has no dry-run mode.`);
@@ -381,7 +392,7 @@ function validateRequiredCommandInputs(resource, action, args, flags, entry) {
381
392
  }
382
393
  }
383
394
  function validateRegistryCommandInputs(resource, action, args, flags) {
384
- const entry = cachedCommandRegistry()[resource]?.[action];
395
+ const entry = cachedCommandRegistry(resource)?.[action];
385
396
  if (!entry)
386
397
  return;
387
398
  validateSupportedCommandFlags(resource, action, flags);
@@ -418,7 +429,7 @@ async function validateDryRunHandlerPreconditions(handler, args, flags) {
418
429
  throw error;
419
430
  }
420
431
  }
421
- function validateMetaCommandInputs(resource, action, flags) {
432
+ async function validateMetaCommandInputs(resource, action, flags) {
422
433
  if (resource === "doctor") {
423
434
  if (action !== undefined && action !== "run") {
424
435
  throw unknownActionError("doctor", action, ["run",]);
@@ -426,11 +437,11 @@ function validateMetaCommandInputs(resource, action, flags) {
426
437
  return "run";
427
438
  }
428
439
  if (resource === "auth") {
429
- const validActions = Object.keys(AUTH_ACTIONS);
440
+ const validActions = Object.keys(contract.AUTH_ACTIONS);
430
441
  if (!action) {
431
442
  throw missingActionError("auth", validActions, "dss auth login --url URL --api-key KEY");
432
443
  }
433
- if (!AUTH_ACTIONS[action]) {
444
+ if (!contract.AUTH_ACTIONS[action]) {
434
445
  throw unknownActionError("auth", action, validActions, "auth only supports 'login'. To check credentials/connectivity, run 'dss doctor'.");
435
446
  }
436
447
  return action;
@@ -439,6 +450,7 @@ function validateMetaCommandInputs(resource, action, flags) {
439
450
  if (action !== undefined && action !== "run") {
440
451
  throw unknownActionError("install-skill", action, ["run",]);
441
452
  }
453
+ const { AGENTS, } = await import("./skill.js");
442
454
  const agentFilter = typeof flags["agent"] === "string" ? flags["agent"] : undefined;
443
455
  if (agentFilter && !AGENTS[agentFilter]) {
444
456
  throw new UsageError(`Unknown agent: ${agentFilter}.`, "usage_error", COMMANDS_RUN_HINT, { agent: agentFilter, validAgents: Object.keys(AGENTS), });
@@ -447,14 +459,14 @@ function validateMetaCommandInputs(resource, action, flags) {
447
459
  }
448
460
  if (resource === "agent") {
449
461
  if (!action)
450
- throw missingActionError("agent", ["contract",], AGENT_CONTRACT_USAGE);
462
+ throw missingActionError("agent", ["contract",], contract.AGENT_CONTRACT_USAGE);
451
463
  if (action !== "contract")
452
464
  throw unknownActionError("agent", action, ["contract",]);
453
465
  return action;
454
466
  }
455
467
  if (resource === "commands") {
456
468
  if (!action)
457
- throw missingActionError("commands", ["run",], COMMANDS_USAGE);
469
+ throw missingActionError("commands", ["run",], contract.COMMANDS_USAGE);
458
470
  if (action !== "run")
459
471
  throw unknownActionError("commands", action, ["run",]);
460
472
  validateSupportedCommandFlags("commands", "run", flags);
@@ -471,7 +483,7 @@ function validateMetaCommandInputs(resource, action, flags) {
471
483
  if (action !== undefined && action !== "run") {
472
484
  throw unknownActionError("cleanup", action, ["run",]);
473
485
  }
474
- const entry = cachedCommandRegistry().cleanup?.run;
486
+ const entry = cachedCommandRegistry("cleanup")?.run;
475
487
  if (entry)
476
488
  validateRequiredCommandInputs("cleanup", "run", [], flags, entry);
477
489
  return "run";
@@ -486,7 +498,7 @@ function validateMetaCommandInputs(resource, action, flags) {
486
498
  if (action !== undefined && action !== "run") {
487
499
  throw unknownActionError("batch", action, ["run",]);
488
500
  }
489
- const entry = cachedCommandRegistry().batch?.run;
501
+ const entry = cachedCommandRegistry("batch")?.run;
490
502
  if (entry)
491
503
  validateRequiredCommandInputs("batch", "run", [], flags, entry);
492
504
  return "run";
@@ -499,7 +511,7 @@ async function validateBatchStep(argv) {
499
511
  const action = positional[1];
500
512
  if (!resource)
501
513
  throw noCommandError();
502
- const metaAction = validateMetaCommandInputs(resource, action, flags);
514
+ const metaAction = await validateMetaCommandInputs(resource, action, flags);
503
515
  if (metaAction)
504
516
  return { positional, flags, resource, action: metaAction, };
505
517
  const resourceActions = commands[resource];
@@ -518,7 +530,7 @@ async function validateBatchStep(argv) {
518
530
  function batchStepNeedsClient(argv) {
519
531
  try {
520
532
  const { positional, flags, } = parseArgs(argv);
521
- if (flags["plan"] === true)
533
+ if (executionMode(flags).plan)
522
534
  return false;
523
535
  const resource = positional[0];
524
536
  if (!resource)
@@ -600,7 +612,7 @@ function validateBatchStepMode(argv, index) {
600
612
  catch {
601
613
  return;
602
614
  }
603
- if (flags["plan"] !== true && flags["dry-run"] !== true)
615
+ if (!executionMode(flags).plan && !executionMode(flags).dryRun)
604
616
  return;
605
617
  const resource = positional[0];
606
618
  const action = positional[1];
@@ -614,13 +626,13 @@ function validateBatchStepMode(argv, index) {
614
626
  const meta = resourceActions[action ?? ""];
615
627
  if (!meta)
616
628
  return;
617
- const entry = cachedCommandRegistry()[resource]?.[action ?? ""];
629
+ const entry = cachedCommandRegistry(resource)?.[action ?? ""];
618
630
  if (!entry)
619
631
  return;
620
- if (flags["plan"] === true && !entry.flags.some((flag) => flag.name === "plan")) {
632
+ if (executionMode(flags).plan && !entry.flags.some((flag) => flag.name === "plan")) {
621
633
  throw new UsageError(`Batch step ${index} requests --plan, which is not supported for ${resource} ${action}.`, "unknown_flag", "Remove --plan from the step; only mutating commands support --plan.");
622
634
  }
623
- if (flags["dry-run"] === true && !entry.dryRun) {
635
+ if (executionMode(flags).dryRun && !entry.dryRun) {
624
636
  throw new UsageError(`Batch step ${index} requests --dry-run, which is not supported for ${resource} ${action}.`, "unknown_flag", "Remove --dry-run from the step.");
625
637
  }
626
638
  }
@@ -629,7 +641,8 @@ function validateBatchStepModes(steps) {
629
641
  validateBatchStepMode(steps[index], index);
630
642
  }
631
643
  }
632
- function runInstallSkill(flags) {
644
+ async function runInstallSkill(flags) {
645
+ const { AGENTS, detectAgents, findWorkspaceRoot, installSkill, planSkillInstalls, } = await import("./skill.js");
633
646
  const agentFilter = typeof flags["agent"] === "string" ? flags["agent"] : undefined;
634
647
  const isGlobal = flags["global"] === true;
635
648
  const targetDir = typeof flags["target"] === "string" ? flags["target"] : undefined;
@@ -655,25 +668,29 @@ function runInstallSkill(flags) {
655
668
  throw new UsageError("No coding agents detected.", "usage_error", "Use --agent NAME to choose one of the supported agents.", { validAgents: Object.keys(AGENTS), });
656
669
  }
657
670
  const scope = isGlobal ? "global" : "project";
658
- const cwd = targetDir ?? (isGlobal ? process.cwd() : findWorkspaceRoot(process.cwd()));
671
+ const cwd = isGlobal
672
+ ? homedir()
673
+ : targetDir
674
+ ? resolve(targetDir)
675
+ : findWorkspaceRoot(process.cwd());
659
676
  const installed = planSkillInstalls(targets, { global: isGlobal, cwd, });
660
- if (flags["plan"] === true) {
677
+ if (executionMode(flags).plan) {
661
678
  return planResult("install-skill", "run", {
662
679
  identifiers: { scope, target: cwd, },
663
680
  payload: { installed, },
664
681
  idempotency: "none",
665
682
  asyncKind: "none",
666
683
  exitCodesOnFailure: { usage: 1, error: 2, transient: 3, },
667
- plannedAndDryRun: flags["dry-run"] === true,
684
+ plannedAndDryRun: executionMode(flags).dryRun,
668
685
  });
669
686
  }
670
687
  return {
671
688
  scope,
672
689
  target: cwd,
673
- installed: flags["dry-run"] === true
690
+ installed: executionMode(flags).dryRun
674
691
  ? installed
675
692
  : installSkill(targets, { global: isGlobal, cwd, }),
676
- ...(flags["dry-run"] === true ? { dryRun: true, } : {}),
693
+ ...(executionMode(flags).dryRun ? { dryRun: true, } : {}),
677
694
  };
678
695
  }
679
696
  const META_PLAN_EXIT_CODES = { usage: 1, error: 2, transient: 3, };
@@ -706,7 +723,7 @@ function authLoginPlan(flags) {
706
723
  function cleanupPlan(flags) {
707
724
  const filePath = flags["file"];
708
725
  if (typeof filePath !== "string" || filePath.trim().length === 0) {
709
- throw new UsageError(`--file is required. Usage: ${CLEANUP_USAGE}`);
726
+ throw new UsageError(`--file is required. Usage: ${contract.CLEANUP_USAGE}`);
710
727
  }
711
728
  return planResult("cleanup", "run", {
712
729
  identifiers: { file: filePath, },
@@ -717,13 +734,13 @@ function cleanupPlan(flags) {
717
734
  idempotency: "none",
718
735
  asyncKind: "none",
719
736
  exitCodesOnFailure: META_PLAN_EXIT_CODES,
720
- plannedAndDryRun: flags["dry-run"] === true,
737
+ plannedAndDryRun: executionMode(flags).dryRun,
721
738
  });
722
739
  }
723
740
  function batchPlan(flags) {
724
741
  const payload = unknownJsonInput(flags);
725
742
  if (payload === undefined) {
726
- throw new UsageError(`Provide steps via --data, --data-file, or --stdin. Usage: ${BATCH_USAGE}`, "missing_required_flag", BATCH_HINT);
743
+ throw new UsageError(`Provide steps via --data, --data-file, or --stdin. Usage: ${contract.BATCH_USAGE}`, "missing_required_flag", contract.BATCH_HINT);
727
744
  }
728
745
  const steps = parseBatchSteps(payload);
729
746
  return planResult("batch", "run", {
@@ -734,34 +751,37 @@ function batchPlan(flags) {
734
751
  payload: {
735
752
  steps: steps.map((argv) => redactArgv(argv)),
736
753
  continueOnError: flags["continue-on-error"] === true,
737
- dryRun: flags["dry-run"] === true,
754
+ dryRun: executionMode(flags).dryRun,
738
755
  },
739
756
  idempotency: "none",
740
757
  asyncKind: "none",
741
- exitCodesOnFailure: BATCH_PLAN_EXIT_CODES,
742
- plannedAndDryRun: flags["dry-run"] === true,
758
+ exitCodesOnFailure: contract.BATCH_PLAN_EXIT_CODES,
759
+ plannedAndDryRun: executionMode(flags).dryRun,
743
760
  });
744
761
  }
745
762
  async function runMetaCommand(resource, action, flags) {
763
+ if (resource !== "version")
764
+ await loadCommandRuntime();
746
765
  if (resource === "doctor") {
747
766
  if (action !== undefined && action !== "run") {
748
767
  throw unknownActionError("doctor", action, ["run",]);
749
768
  }
750
769
  currentCommandContext.action = action ?? "run";
770
+ const { runDoctor, } = await import("./cli/doctor.js");
751
771
  const { result, exitCode, } = await runDoctor(flags);
752
772
  return { action: "run", result, exitCode, };
753
773
  }
754
774
  if (resource === "auth") {
755
- const validActions = Object.keys(AUTH_ACTIONS);
775
+ const validActions = Object.keys(contract.AUTH_ACTIONS);
756
776
  if (!action) {
757
777
  throw missingActionError("auth", validActions, "dss auth login --url URL --api-key KEY");
758
778
  }
759
779
  currentCommandContext.action = action;
760
- const authMeta = AUTH_ACTIONS[action];
780
+ const authMeta = contract.AUTH_ACTIONS[action];
761
781
  if (!authMeta) {
762
782
  throw unknownActionError("auth", action, validActions, "auth only supports 'login'. To check credentials/connectivity, run 'dss doctor'.");
763
783
  }
764
- if (flags["plan"] === true) {
784
+ if (executionMode(flags).plan) {
765
785
  return { action, result: authLoginPlan(flags), exitCode: 0, };
766
786
  }
767
787
  return { action, result: await authMeta.handler(flags), exitCode: 0, };
@@ -771,29 +791,29 @@ async function runMetaCommand(resource, action, flags) {
771
791
  throw unknownActionError("install-skill", action, ["run",]);
772
792
  }
773
793
  currentCommandContext.action = action ?? "run";
774
- return { action: "run", result: runInstallSkill(flags), exitCode: 0, };
794
+ return { action: "run", result: await runInstallSkill(flags), exitCode: 0, };
775
795
  }
776
796
  if (resource === "agent") {
777
797
  if (!action)
778
- throw missingActionError("agent", ["contract",], AGENT_CONTRACT_USAGE);
798
+ throw missingActionError("agent", ["contract",], contract.AGENT_CONTRACT_USAGE);
779
799
  currentCommandContext.action = action;
780
800
  if (action !== "contract")
781
801
  throw unknownActionError("agent", action, ["contract",]);
782
- return { action, result: buildAgentContract(), exitCode: 0, };
802
+ return { action, result: contract.buildAgentContract(), exitCode: 0, };
783
803
  }
784
804
  if (resource === "commands") {
785
805
  if (!action)
786
- throw missingActionError("commands", ["run",], COMMANDS_USAGE);
806
+ throw missingActionError("commands", ["run",], contract.COMMANDS_USAGE);
787
807
  currentCommandContext.action = action;
788
808
  if (action !== "run")
789
809
  throw unknownActionError("commands", action, ["run",]);
790
810
  validateSupportedCommandFlags("commands", "run", flags);
791
811
  const selectors = commandRegistrySelectors(flags);
792
- const registry = buildCommandRegistry();
812
+ const registry = contract.buildCommandRegistry();
793
813
  for (const selector of selectors) {
794
814
  const selectorParts = selector.split(".");
795
815
  if (selectorParts.some((part) => part.length === 0)) {
796
- throw new UsageError(`Invalid --fields selector: ${selector}. Expected RESOURCE or RESOURCE.ACTION[.FIELD...].`, "usage_error", COMMANDS_USAGE, { selector, });
816
+ throw new UsageError(`Invalid --fields selector: ${selector}. Expected RESOURCE or RESOURCE.ACTION[.FIELD...].`, "usage_error", contract.COMMANDS_USAGE, { selector, });
797
817
  }
798
818
  const [selectedResource, selectedAction,] = selectorParts;
799
819
  const resourceActions = registry[selectedResource];
@@ -814,7 +834,7 @@ async function runMetaCommand(resource, action, flags) {
814
834
  }
815
835
  return {
816
836
  action,
817
- result: selectors.length === 0 ? commandActionSummary(registry) : selectedRegistry,
837
+ result: selectors.length === 0 ? contract.commandActionSummary(registry) : selectedRegistry,
818
838
  exitCode: 0,
819
839
  };
820
840
  }
@@ -830,7 +850,7 @@ async function runMetaCommand(resource, action, flags) {
830
850
  throw unknownActionError("cleanup", action, ["run",]);
831
851
  }
832
852
  currentCommandContext.action = action ?? "run";
833
- if (flags["plan"] === true) {
853
+ if (executionMode(flags).plan) {
834
854
  return { action: "run", result: cleanupPlan(flags), exitCode: 0, };
835
855
  }
836
856
  const { result, exitCode, } = await runCleanup(flags);
@@ -841,6 +861,7 @@ async function runMetaCommand(resource, action, flags) {
841
861
  throw unknownActionError("fixtures", action, ["run",]);
842
862
  }
843
863
  currentCommandContext.action = action ?? "run";
864
+ const { runFixtures, } = await import("./cli/doctor.js");
844
865
  return { action: "run", result: await runFixtures(flags), exitCode: 0, };
845
866
  }
846
867
  if (resource === "batch") {
@@ -848,7 +869,7 @@ async function runMetaCommand(resource, action, flags) {
848
869
  throw unknownActionError("batch", action, ["run",]);
849
870
  }
850
871
  currentCommandContext.action = action ?? "run";
851
- if (flags["plan"] === true) {
872
+ if (executionMode(flags).plan) {
852
873
  return { action: "run", result: batchPlan(flags), exitCode: 0, };
853
874
  }
854
875
  const { result, exitCode, } = await runBatch(flags);
@@ -862,9 +883,9 @@ async function runMetaCommand(resource, action, flags) {
862
883
  * share this guard.
863
884
  */
864
885
  function assertCleanupLedgerSupported(resource, action, flags) {
865
- if (typeof flags["record-cleanup"] !== "string" || flags["dry-run"] === true)
886
+ if (typeof flags["record-cleanup"] !== "string" || executionMode(flags).dryRun)
866
887
  return;
867
- if (!supportsCleanupLedger(resource, action)) {
888
+ if (!contract.supportsCleanupLedger(resource, action)) {
868
889
  throw new UsageError(`--record-cleanup is not supported for ${resource} ${action}.`);
869
890
  }
870
891
  if (resource === "workspace" && action === "create" && flags["stdin"] === true) {
@@ -878,7 +899,7 @@ function assertCleanupLedgerSupported(resource, action, flags) {
878
899
  * steps both call it, and dry-run/preview runs never touch the ledger.
879
900
  */
880
901
  async function preflightCleanupLedgerForFlags(client, flags) {
881
- if (flags["dry-run"] === true)
902
+ if (executionMode(flags).dryRun)
882
903
  return;
883
904
  const ledgerPath = flags["record-cleanup"];
884
905
  if (typeof ledgerPath !== "string")
@@ -929,7 +950,7 @@ async function preflightCleanupLedgerForFlags(client, flags) {
929
950
  */
930
951
  async function recordCleanupLedgerEntry(client, resource, action, args, flags, result, projectKey) {
931
952
  const ledgerPath = flags["record-cleanup"];
932
- if (typeof ledgerPath !== "string" || flags["dry-run"] === true)
953
+ if (typeof ledgerPath !== "string" || executionMode(flags).dryRun)
933
954
  return;
934
955
  const entry = cleanupLedgerEntry(resource, action, args, flags, result, projectKey);
935
956
  if (entry) {
@@ -946,10 +967,10 @@ async function recordCleanupLedgerEntry(client, resource, action, args, flags, r
946
967
  async function runBatch(flags) {
947
968
  const payload = unknownJsonInput(flags);
948
969
  if (payload === undefined) {
949
- throw new UsageError(`Provide steps via --data, --data-file, or --stdin. Usage: ${BATCH_USAGE}`, "missing_required_flag", BATCH_HINT);
970
+ throw new UsageError(`Provide steps via --data, --data-file, or --stdin. Usage: ${contract.BATCH_USAGE}`, "missing_required_flag", contract.BATCH_HINT);
950
971
  }
951
972
  const steps = parseBatchSteps(payload);
952
- if (flags["dry-run"] === true) {
973
+ if (executionMode(flags).dryRun) {
953
974
  const batchProjectKey = typeof flags["project-key"] === "string"
954
975
  ? flags["project-key"]
955
976
  : dataikuEnvironmentEnabled()
@@ -1016,6 +1037,7 @@ async function runBatch(flags) {
1016
1037
  env: ["DATAIKU_API_KEY",],
1017
1038
  });
1018
1039
  }
1040
+ const { DataikuClient, } = await import("./client.js");
1019
1041
  client = new DataikuClient({
1020
1042
  url,
1021
1043
  apiKey,
@@ -1078,8 +1100,8 @@ async function runBatch(flags) {
1078
1100
  if (!meta)
1079
1101
  throw unknownActionError(resource, action, Object.keys(resourceActions));
1080
1102
  validateSupportedCommandFlags(resource, action, stepFlags);
1081
- if (stepFlags["plan"] === true) {
1082
- result = buildMutationPlan(resource, action, meta, positional.slice(2), stepFlags);
1103
+ if (executionMode(stepFlags).plan) {
1104
+ result = contract.buildMutationPlan(resource, action, meta, positional.slice(2), stepFlags);
1083
1105
  }
1084
1106
  else {
1085
1107
  if (!client) {
@@ -1176,7 +1198,7 @@ function commandIsProjectScoped(resource, action) {
1176
1198
  if (!resource)
1177
1199
  return false;
1178
1200
  const usage = commands[resource]?.[action ?? ""]?.usage ?? "";
1179
- return inferRequiresProject(resource, action ?? "", usage);
1201
+ return contract.inferRequiresProject(resource, action ?? "", usage);
1180
1202
  }
1181
1203
  function rawCommandContext() {
1182
1204
  const argv = process.argv.slice(2);
@@ -1262,7 +1284,7 @@ function isAmbiguousMutationFailure(err, context) {
1262
1284
  if (err.status !== 0 && err.status < 500)
1263
1285
  return false;
1264
1286
  const entry = context.resource && context.action
1265
- ? cachedCommandRegistry()[context.resource]?.[context.action]
1287
+ ? cachedCommandRegistry(context.resource)?.[context.action]
1266
1288
  : undefined;
1267
1289
  return entry?.sideEffect === "write" && entry.idempotency === "none";
1268
1290
  }
@@ -1480,8 +1502,8 @@ async function main() {
1480
1502
  throw unknownActionError(resource, action, Object.keys(resourceActions));
1481
1503
  validateSupportedCommandFlags(resource, action, flags);
1482
1504
  const args = positional.slice(2);
1483
- if (flags["plan"] === true) {
1484
- const plan = buildMutationPlan(resource, action, actionMeta, args, flags);
1505
+ if (executionMode(flags).plan) {
1506
+ const plan = contract.buildMutationPlan(resource, action, actionMeta, args, flags);
1485
1507
  writeCommandResult(plan);
1486
1508
  return;
1487
1509
  }
@@ -1504,6 +1526,7 @@ async function main() {
1504
1526
  }
1505
1527
  const requestTimeoutMs = num(flags["request-timeout"], "--request-timeout");
1506
1528
  const retryMaxAttempts = num(flags["retries"], "--retries");
1529
+ const { DataikuClient, } = await import("./client.js");
1507
1530
  const client = new DataikuClient({
1508
1531
  url,
1509
1532
  apiKey,
@@ -1523,7 +1546,8 @@ async function main() {
1523
1546
  throw new CommandResultFailure(result, failureExitCode);
1524
1547
  writeCommandResult(result);
1525
1548
  }
1526
- main().catch((err) => {
1549
+ main().catch(async (err) => {
1550
+ await loadCommandRuntime();
1527
1551
  writeErrorReport(err);
1528
1552
  process.exitCode = errorExitCode(err);
1529
1553
  });
@@ -67,7 +67,7 @@ export interface DataikuClientConfig {
67
67
  apiKey: string;
68
68
  /** Default project key — used when a resource method omits projectKey */
69
69
  projectKey?: string;
70
- /** Per-request timeout in milliseconds (default 30 000) */
70
+ /** Request/header timeout and buffered-body budget; idle timeout per raw stream read (default 30 000 ms). */
71
71
  requestTimeoutMs?: number;
72
72
  /** Max retry attempts for idempotent requests (default 4, capped at 10) */
73
73
  retryMaxAttempts?: number;
@@ -247,6 +247,8 @@ export declare class DataikuClient {
247
247
  upload(path: string, filePath: string, fileName?: string): Promise<void>;
248
248
  uploadJson<T>(path: string, filePath: string, fileName?: string): Promise<T>;
249
249
  stream(path: string): Promise<Response>;
250
+ /** Bound each pending read, not total transfer time; preserve large downloads and backpressure. */
251
+ private withBodyDeadline;
250
252
  private getHeaders;
251
253
  private getAnyHeaders;
252
254
  private responseMeta;