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.
- package/README.md +124 -12
- package/dist/build-metadata.json +1 -1
- package/dist/src/auth.js +1 -1
- package/dist/src/cli/coerce.js +11 -2
- package/dist/src/cli/commands/analysis.js +4 -3
- package/dist/src/cli/commands/api-service.js +5 -3
- package/dist/src/cli/commands/app.js +4 -3
- package/dist/src/cli/commands/bundle.js +2 -1
- package/dist/src/cli/commands/code-env.js +10 -9
- package/dist/src/cli/commands/dashboard.js +7 -6
- package/dist/src/cli/commands/data-quality.js +9 -8
- package/dist/src/cli/commands/dataset.js +9 -8
- package/dist/src/cli/commands/doctor.js +4 -2
- package/dist/src/cli/commands/flow-zone.js +9 -8
- package/dist/src/cli/commands/folder.js +9 -8
- package/dist/src/cli/commands/future.js +2 -1
- package/dist/src/cli/commands/insight.js +8 -7
- package/dist/src/cli/commands/job.js +4 -3
- package/dist/src/cli/commands/meaning.js +5 -4
- package/dist/src/cli/commands/ml-task.js +3 -2
- package/dist/src/cli/commands/model-evaluation-store.js +4 -3
- package/dist/src/cli/commands/notebook.js +11 -10
- package/dist/src/cli/commands/project-library.js +7 -6
- package/dist/src/cli/commands/project.js +3 -2
- package/dist/src/cli/commands/recipe.js +14 -13
- package/dist/src/cli/commands/saved-model.js +4 -3
- package/dist/src/cli/commands/scenario.js +9 -8
- package/dist/src/cli/commands/sql.js +3 -2
- package/dist/src/cli/commands/statistics.js +7 -6
- package/dist/src/cli/commands/variable.js +2 -1
- package/dist/src/cli/commands/webapp.js +2 -1
- package/dist/src/cli/commands/wiki.js +7 -6
- package/dist/src/cli/contract.d.ts +1 -1
- package/dist/src/cli/contract.js +100 -82
- package/dist/src/cli/flags.d.ts +4 -0
- package/dist/src/cli/flags.js +20 -1
- package/dist/src/cli.js +92 -68
- package/dist/src/client.d.ts +3 -1
- package/dist/src/client.js +78 -21
- package/dist/src/errors.js +2 -0
- package/dist/src/resources/folders.js +2 -1
- package/dist/src/resources/projects.d.ts +0 -2
- package/dist/src/resources/projects.js +3 -17
- package/dist/src/resources/sql.js +1 -1
- package/dist/src/skill.d.ts +13 -4
- package/dist/src/skill.js +75 -24
- package/dist/src/utils/response-file.d.ts +2 -0
- package/dist/src/utils/response-file.js +34 -0
- package/package.json +6 -4
- package/plugin.json +1 -1
- package/skills/dataiku-dss/SKILL.md +44 -224
- package/skills/dataiku-dss/references/app-releases.md +27 -0
- package/skills/dataiku-dss/references/authentication.md +39 -0
- package/skills/dataiku-dss/references/coding.md +8 -0
- package/skills/dataiku-dss/references/discovery.md +30 -0
- package/skills/dataiku-dss/references/flow-maps.md +12 -0
- package/skills/dataiku-dss/references/mutations.md +33 -0
- 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
|
-
|
|
270
|
-
function cachedCommandRegistry() {
|
|
271
|
-
if (commandRegistryCache
|
|
272
|
-
commandRegistryCache
|
|
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()
|
|
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
|
|
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()
|
|
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()
|
|
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()
|
|
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
|
|
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
|
|
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()
|
|
629
|
+
const entry = cachedCommandRegistry(resource)?.[action ?? ""];
|
|
618
630
|
if (!entry)
|
|
619
631
|
return;
|
|
620
|
-
if (flags
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
684
|
+
plannedAndDryRun: executionMode(flags).dryRun,
|
|
668
685
|
});
|
|
669
686
|
}
|
|
670
687
|
return {
|
|
671
688
|
scope,
|
|
672
689
|
target: cwd,
|
|
673
|
-
installed: flags
|
|
690
|
+
installed: executionMode(flags).dryRun
|
|
674
691
|
? installed
|
|
675
692
|
: installSkill(targets, { global: isGlobal, cwd, }),
|
|
676
|
-
...(flags
|
|
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
|
|
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
|
|
754
|
+
dryRun: executionMode(flags).dryRun,
|
|
738
755
|
},
|
|
739
756
|
idempotency: "none",
|
|
740
757
|
asyncKind: "none",
|
|
741
|
-
exitCodesOnFailure: BATCH_PLAN_EXIT_CODES,
|
|
742
|
-
plannedAndDryRun: flags
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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
|
});
|
package/dist/src/client.d.ts
CHANGED
|
@@ -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
|
-
/**
|
|
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;
|