dataiku-sdk 3.0.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 +246 -19
- package/dist/build-metadata.json +1 -1
- package/dist/packages/types/src/index.d.ts +39 -4
- package/dist/packages/types/src/index.js +31 -2
- 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 +66 -18
- package/dist/src/cli/commands/app.js +4 -3
- package/dist/src/cli/commands/bundle.js +51 -16
- package/dist/src/cli/commands/code-env.js +219 -57
- package/dist/src/cli/commands/code.d.ts +19 -0
- package/dist/src/cli/commands/code.js +87 -15
- 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 +17 -11
- package/dist/src/cli/commands/doctor.js +4 -2
- package/dist/src/cli/commands/flow-zone.js +42 -13
- 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 +82 -50
- package/dist/src/cli/commands/project-git.js +8 -5
- package/dist/src/cli/commands/project-library.d.ts +21 -0
- package/dist/src/cli/commands/project-library.js +128 -56
- package/dist/src/cli/commands/project.js +19 -4
- package/dist/src/cli/commands/recipe.js +51 -25
- 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.d.ts +10 -0
- package/dist/src/cli/commands/sql.js +42 -19
- 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 +68 -13
- package/dist/src/cli/commands/wiki.js +7 -6
- package/dist/src/cli/contract.d.ts +16 -1
- package/dist/src/cli/contract.js +967 -186
- package/dist/src/cli/env.d.ts +9 -0
- package/dist/src/cli/env.js +20 -2
- package/dist/src/cli/flags.d.ts +4 -0
- package/dist/src/cli/flags.js +29 -1
- package/dist/src/cli/helpers/cleanup.js +104 -3
- package/dist/src/cli/helpers/flow-zone.d.ts +3 -0
- package/dist/src/cli/helpers/flow-zone.js +33 -3
- package/dist/src/cli/helpers/recipe.d.ts +20 -0
- package/dist/src/cli/helpers/recipe.js +158 -3
- package/dist/src/cli/output.d.ts +2 -0
- package/dist/src/cli/output.js +33 -6
- package/dist/src/cli/runtime.d.ts +35 -1
- package/dist/src/cli/runtime.js +125 -18
- package/dist/src/cli/types.d.ts +7 -0
- package/dist/src/cli.js +226 -95
- package/dist/src/client.d.ts +63 -1
- package/dist/src/client.js +305 -53
- package/dist/src/errors.d.ts +8 -2
- package/dist/src/errors.js +42 -0
- package/dist/src/index.d.ts +4 -3
- package/dist/src/index.js +2 -1
- package/dist/src/resources/api-services.d.ts +48 -6
- package/dist/src/resources/api-services.js +54 -8
- package/dist/src/resources/bundles.d.ts +51 -6
- package/dist/src/resources/bundles.js +39 -9
- package/dist/src/resources/code-envs.d.ts +25 -3
- package/dist/src/resources/code-envs.js +104 -2
- package/dist/src/resources/datasets.d.ts +20 -0
- package/dist/src/resources/datasets.js +232 -52
- package/dist/src/resources/folders.js +2 -1
- package/dist/src/resources/jobs.d.ts +35 -10
- package/dist/src/resources/jobs.js +92 -17
- package/dist/src/resources/notebooks.d.ts +77 -7
- package/dist/src/resources/notebooks.js +143 -19
- package/dist/src/resources/project-git.d.ts +12 -0
- package/dist/src/resources/project-git.js +39 -8
- package/dist/src/resources/project-library.d.ts +122 -7
- package/dist/src/resources/project-library.js +494 -25
- package/dist/src/resources/projects.d.ts +5 -4
- package/dist/src/resources/projects.js +21 -19
- package/dist/src/resources/scenarios.d.ts +30 -0
- package/dist/src/resources/scenarios.js +73 -27
- package/dist/src/resources/sql.d.ts +6 -0
- package/dist/src/resources/sql.js +23 -3
- package/dist/src/resources/webapps.d.ts +35 -4
- package/dist/src/resources/webapps.js +54 -5
- package/dist/src/schemas.d.ts +2 -2
- package/dist/src/schemas.js +1 -1
- package/dist/src/skill.d.ts +18 -0
- package/dist/src/skill.js +93 -9
- package/dist/src/utils/flow-analysis.d.ts +53 -0
- package/dist/src/utils/flow-analysis.js +382 -0
- package/dist/src/utils/project-archive.d.ts +41 -2
- package/dist/src/utils/project-archive.js +159 -16
- package/dist/src/utils/response-file.d.ts +2 -0
- package/dist/src/utils/response-file.js +34 -0
- package/package.json +9 -7
- package/packages/types/dist/index.d.ts +39 -4
- package/packages/types/dist/index.js +31 -2
- package/plugin.json +1 -1
- package/skills/dataiku-dss/SKILL.md +44 -197
- 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/contract.js
CHANGED
|
@@ -4,19 +4,31 @@ import { validateCredentials, } from "../auth.js";
|
|
|
4
4
|
import { getCredentialsPath, saveCredentials, } from "../config.js";
|
|
5
5
|
import { DataikuError, } from "../errors.js";
|
|
6
6
|
import { APP_MANIFEST_CONCURRENCY_CONTROL, } from "../resources/applications.js";
|
|
7
|
-
import {
|
|
7
|
+
import { encodeGitReferencePath, validateGitReferencePath, } from "../resources/project-git.js";
|
|
8
|
+
import { encodeLibraryPath, PROJECT_LIBRARY_CONCURRENCY_CONTROL, validateLibraryDestinationPath, validateLibraryName, validateLibraryPath, } from "../resources/project-library.js";
|
|
9
|
+
import { 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, } from "../schemas.js";
|
|
10
|
+
import { jobBuildTargetTypeFromFlags, json, jsonInput, num, parseBooleanOption, parseJsonObject, recipeInputDatasetsFromFlags, requiredJsonInput, rewritePairsFromFlags, schemaColumnsInput, sha256Hex, stableHash, stringField, textInput, } from "./coerce.js";
|
|
11
|
+
import { parseCodeRunIntegerFlag, resolveCodeInputWithSource, } from "./commands/code.js";
|
|
8
12
|
import { commands, } from "./commands/index.js";
|
|
13
|
+
import { projectLibraryPutPayload, } from "./commands/project-library.js";
|
|
14
|
+
import { resolveSqlQueryInvocation, } from "./commands/sql.js";
|
|
9
15
|
import { dataikuEnvironmentEnabled, } from "./env.js";
|
|
10
|
-
import { BOOLEAN_FLAGS, FLAG_ALIASES, KNOWN_LONG_FLAGS, SHORT_FLAGS, } from "./flags.js";
|
|
16
|
+
import { BOOLEAN_FLAGS, executionMode, FLAG_ALIASES, KNOWN_LONG_FLAGS, SHORT_FLAGS, } from "./flags.js";
|
|
11
17
|
import { flowZoneColor, flowZoneMoveItems, flowZoneName, } from "./helpers/flow-zone.js";
|
|
12
18
|
import { recipeBackupPath, recipeRunShouldWait, } from "./helpers/recipe.js";
|
|
13
19
|
import { encodedProjectEndpointForPlan, planResult, } from "./output.js";
|
|
14
|
-
import {
|
|
20
|
+
import { resolveLoginCredentials, } from "./runtime.js";
|
|
15
21
|
import { requireArgs, UsageError, } from "./usage.js";
|
|
16
22
|
import { AGENT_CONTRACT_SCHEMA_ID, AGENT_CONTRACT_VERSION, cliVersionResult, JSON_SCHEMA_DRAFT, } from "./version.js";
|
|
17
23
|
function codeEnvWait(flags) {
|
|
18
24
|
return flags["no-wait"] !== true;
|
|
19
25
|
}
|
|
26
|
+
function codeEnvLang(value, usage) {
|
|
27
|
+
if (value !== "PYTHON" && value !== "R") {
|
|
28
|
+
throw new UsageError(`Invalid code environment language ${JSON.stringify(value)}. Usage: ${usage}`);
|
|
29
|
+
}
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
20
32
|
function codeEnvParams(flags) {
|
|
21
33
|
const params = json(flags["params"]) ?? jsonInput(flags) ?? {};
|
|
22
34
|
if (typeof flags["python-interpreter"] === "string") {
|
|
@@ -46,23 +58,7 @@ function codeEnvPackageList(flags) {
|
|
|
46
58
|
export const AUTH_ACTIONS = {
|
|
47
59
|
login: {
|
|
48
60
|
handler: async (flags) => {
|
|
49
|
-
const tlsSettings =
|
|
50
|
-
const useEnv = dataikuEnvironmentEnabled();
|
|
51
|
-
const url = typeof flags["url"] === "string"
|
|
52
|
-
? flags["url"]
|
|
53
|
-
: useEnv
|
|
54
|
-
? process.env.DATAIKU_URL ?? ""
|
|
55
|
-
: "";
|
|
56
|
-
const apiKey = typeof flags["api-key"] === "string"
|
|
57
|
-
? flags["api-key"]
|
|
58
|
-
: useEnv
|
|
59
|
-
? process.env.DATAIKU_API_KEY ?? ""
|
|
60
|
-
: "";
|
|
61
|
-
const projectKey = typeof flags["project-key"] === "string"
|
|
62
|
-
? flags["project-key"]
|
|
63
|
-
: useEnv
|
|
64
|
-
? process.env.DATAIKU_PROJECT_KEY
|
|
65
|
-
: undefined;
|
|
61
|
+
const { url, apiKey, projectKey, tlsSettings, } = resolveLoginCredentials(flags);
|
|
66
62
|
if (!url || !apiKey) {
|
|
67
63
|
throw new UsageError("Missing --url and/or --api-key for auth login.", "missing_required_flag", "Pass --url and --api-key, or set DATAIKU_URL and DATAIKU_API_KEY.", { requiredFlags: ["url", "api-key",], env: ["DATAIKU_URL", "DATAIKU_API_KEY",], });
|
|
68
64
|
}
|
|
@@ -237,13 +233,13 @@ const VERSION_USAGE = "dss version";
|
|
|
237
233
|
const VERSION_DESCRIPTION = "Print the CLI version, checkout/build revisions, load source, runtime, and stale-build status as JSON.";
|
|
238
234
|
const VERSION_EXAMPLES = ["dss version", "dss --version",];
|
|
239
235
|
const INSTALL_SKILL_USAGE = "dss install-skill [--global] [--agent NAME] [--target PATH] [--list-agents] [--dry-run] [--plan]";
|
|
240
|
-
const INSTALL_SKILL_DESCRIPTION = "
|
|
236
|
+
const INSTALL_SKILL_DESCRIPTION = "Report missing/stale/current skill status and atomically install changed dataiku-dss agent skills.";
|
|
241
237
|
const INSTALL_SKILL_EXAMPLES = [
|
|
242
238
|
"dss install-skill --list-agents",
|
|
243
239
|
"dss install-skill --agent omp --dry-run",
|
|
244
240
|
];
|
|
245
241
|
export const CLEANUP_USAGE = "dss cleanup --file PATH [--dry-run|--apply] [--continue-on-error]";
|
|
246
|
-
const CLEANUP_DESCRIPTION = "Replay cleanup
|
|
242
|
+
const CLEANUP_DESCRIPTION = "Replay cleanup entries in reverse order; failures include structured code/category/exitCode/retryability summaries.";
|
|
247
243
|
const CLEANUP_EXAMPLES = [
|
|
248
244
|
"dss cleanup --file cleanup.jsonl",
|
|
249
245
|
"dss cleanup --file cleanup.jsonl --apply",
|
|
@@ -272,6 +268,12 @@ const ALLOWED_CLEANUP_ACTIONS = new Set([
|
|
|
272
268
|
"folder delete-file",
|
|
273
269
|
"project delete",
|
|
274
270
|
"app delete-instance",
|
|
271
|
+
"meaning delete",
|
|
272
|
+
"notebook delete-jupyter",
|
|
273
|
+
"notebook delete-sql",
|
|
274
|
+
"project-library delete",
|
|
275
|
+
"streaming-endpoint delete",
|
|
276
|
+
"workspace delete",
|
|
275
277
|
]);
|
|
276
278
|
export function isAllowedCleanupAction(resource, action) {
|
|
277
279
|
return ALLOWED_CLEANUP_ACTIONS.has(`${resource} ${action}`);
|
|
@@ -407,7 +409,202 @@ function structuredExamples(examples, examplePayload) {
|
|
|
407
409
|
};
|
|
408
410
|
});
|
|
409
411
|
}
|
|
410
|
-
|
|
412
|
+
const PROJECT_LIBRARY_ITEM_OUTPUT_SCHEMA = {
|
|
413
|
+
type: "object",
|
|
414
|
+
additionalProperties: false,
|
|
415
|
+
required: ["name",],
|
|
416
|
+
properties: {
|
|
417
|
+
name: { type: "string", },
|
|
418
|
+
path: { type: "string", },
|
|
419
|
+
size: { type: "integer", minimum: 0, },
|
|
420
|
+
mimeType: { type: "string", },
|
|
421
|
+
hasData: { type: "boolean", },
|
|
422
|
+
lastModified: { type: "number", },
|
|
423
|
+
children: { type: "array", items: { type: "object", additionalProperties: true, }, },
|
|
424
|
+
},
|
|
425
|
+
};
|
|
426
|
+
const NOTEBOOK_SAVE_OUTPUT_SCHEMA = {
|
|
427
|
+
type: "object",
|
|
428
|
+
additionalProperties: false,
|
|
429
|
+
required: ["saved", "resource", "created", "hash",],
|
|
430
|
+
properties: {
|
|
431
|
+
saved: { type: "string", },
|
|
432
|
+
resource: { enum: ["jupyter-notebook", "sql-notebook",], },
|
|
433
|
+
created: { type: "boolean", },
|
|
434
|
+
hash: { type: "string", pattern: "^[a-f0-9]{64}$", },
|
|
435
|
+
},
|
|
436
|
+
};
|
|
437
|
+
const COMMAND_OUTPUT_SCHEMAS = {
|
|
438
|
+
"code-env.list": CodeEnvSummaryArraySchema,
|
|
439
|
+
"code-env.get": CodeEnvDetailsSchema,
|
|
440
|
+
"code-env.list-logs": CodeEnvLogSummaryArraySchema,
|
|
441
|
+
"code-env.get-log": {
|
|
442
|
+
oneOf: [
|
|
443
|
+
{
|
|
444
|
+
type: "object",
|
|
445
|
+
required: ["log", "bytes", "truncated", "tailed", "envLang", "envName", "logName",],
|
|
446
|
+
properties: {
|
|
447
|
+
log: { type: "string", },
|
|
448
|
+
bytes: { type: "integer", minimum: 0, },
|
|
449
|
+
truncated: { type: "boolean", },
|
|
450
|
+
tailed: { type: "boolean", },
|
|
451
|
+
envLang: { enum: ["PYTHON", "R",], },
|
|
452
|
+
envName: { type: "string", },
|
|
453
|
+
logName: { type: "string", },
|
|
454
|
+
},
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
type: "object",
|
|
458
|
+
required: ["path", "bytes", "truncated", "tailed", "envLang", "envName", "logName",],
|
|
459
|
+
properties: {
|
|
460
|
+
path: { type: "string", },
|
|
461
|
+
bytes: { type: "integer", minimum: 0, },
|
|
462
|
+
truncated: { type: "boolean", },
|
|
463
|
+
tailed: { type: "boolean", },
|
|
464
|
+
envLang: { enum: ["PYTHON", "R",], },
|
|
465
|
+
envName: { type: "string", },
|
|
466
|
+
logName: { type: "string", },
|
|
467
|
+
},
|
|
468
|
+
},
|
|
469
|
+
],
|
|
470
|
+
},
|
|
471
|
+
"code-env.version": CodeEnvVersionForProjectSchema,
|
|
472
|
+
"code-env.usages": CodeEnvUsageArraySchema,
|
|
473
|
+
"code.run": {
|
|
474
|
+
type: "object",
|
|
475
|
+
additionalProperties: false,
|
|
476
|
+
required: [
|
|
477
|
+
"outcome",
|
|
478
|
+
"success",
|
|
479
|
+
"runId",
|
|
480
|
+
"elapsedMs",
|
|
481
|
+
"pollCount",
|
|
482
|
+
"output",
|
|
483
|
+
"logTruncated",
|
|
484
|
+
"maxLogBytes",
|
|
485
|
+
"cleanup",
|
|
486
|
+
],
|
|
487
|
+
properties: {
|
|
488
|
+
outcome: { type: "string", },
|
|
489
|
+
success: { type: "boolean", },
|
|
490
|
+
runId: { type: "string", },
|
|
491
|
+
elapsedMs: { type: "number", minimum: 0, },
|
|
492
|
+
pollCount: { type: "integer", minimum: 0, },
|
|
493
|
+
output: { type: "string", },
|
|
494
|
+
log: { type: "string", },
|
|
495
|
+
logTruncated: { type: "boolean", },
|
|
496
|
+
maxLogBytes: { type: "integer", minimum: 0, },
|
|
497
|
+
timedOut: { const: true, },
|
|
498
|
+
timeoutMs: { type: "integer", minimum: 0, },
|
|
499
|
+
cleanup: {
|
|
500
|
+
type: "object",
|
|
501
|
+
additionalProperties: false,
|
|
502
|
+
required: ["status",],
|
|
503
|
+
properties: {
|
|
504
|
+
status: { enum: ["deleted", "kept", "failed",], },
|
|
505
|
+
error: { type: "string", },
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
},
|
|
509
|
+
},
|
|
510
|
+
"notebook.list-jupyter": JupyterNotebookSummaryArraySchema,
|
|
511
|
+
"notebook.get-jupyter": JupyterNotebookContentSchema,
|
|
512
|
+
"notebook.sessions-jupyter": NotebookSessionArraySchema,
|
|
513
|
+
"notebook.list-sql": SqlNotebookSummaryArraySchema,
|
|
514
|
+
"notebook.get-sql": SqlNotebookContentSchema,
|
|
515
|
+
"notebook.history-sql": SqlNotebookHistorySchema,
|
|
516
|
+
"notebook.save-jupyter": NOTEBOOK_SAVE_OUTPUT_SCHEMA,
|
|
517
|
+
"notebook.save-sql": NOTEBOOK_SAVE_OUTPUT_SCHEMA,
|
|
518
|
+
"project-library.list": { type: "array", items: PROJECT_LIBRARY_ITEM_OUTPUT_SCHEMA, },
|
|
519
|
+
"project-library.get-bytes": {
|
|
520
|
+
type: "object",
|
|
521
|
+
additionalProperties: false,
|
|
522
|
+
required: ["path", "bytes", "sha256",],
|
|
523
|
+
properties: {
|
|
524
|
+
path: { type: "string", },
|
|
525
|
+
bytes: { type: "integer", minimum: 0, },
|
|
526
|
+
sha256: { type: "string", pattern: "^[a-f0-9]{64}$", },
|
|
527
|
+
},
|
|
528
|
+
},
|
|
529
|
+
"project-library.put": {
|
|
530
|
+
type: "object",
|
|
531
|
+
additionalProperties: false,
|
|
532
|
+
required: ["updated", "bytes", "sha256",],
|
|
533
|
+
properties: {
|
|
534
|
+
updated: { type: "string", },
|
|
535
|
+
bytes: { type: "integer", minimum: 0, },
|
|
536
|
+
sha256: { type: "string", pattern: "^[a-f0-9]{64}$", },
|
|
537
|
+
beforeSha256: { type: "string", pattern: "^[a-f0-9]{64}$", },
|
|
538
|
+
},
|
|
539
|
+
},
|
|
540
|
+
"project-library.diff": {
|
|
541
|
+
type: "object",
|
|
542
|
+
additionalProperties: false,
|
|
543
|
+
required: [
|
|
544
|
+
"path",
|
|
545
|
+
"unchanged",
|
|
546
|
+
"added",
|
|
547
|
+
"removed",
|
|
548
|
+
"diff",
|
|
549
|
+
"diffTruncated",
|
|
550
|
+
"localSha256",
|
|
551
|
+
"localBytes",
|
|
552
|
+
"maxLines",
|
|
553
|
+
],
|
|
554
|
+
properties: {
|
|
555
|
+
path: { type: "string", },
|
|
556
|
+
unchanged: { type: "boolean", },
|
|
557
|
+
added: { type: "integer", minimum: 0, },
|
|
558
|
+
removed: { type: "integer", minimum: 0, },
|
|
559
|
+
diff: { type: "string", },
|
|
560
|
+
diffTruncated: { type: "boolean", },
|
|
561
|
+
binary: { type: "boolean", },
|
|
562
|
+
remoteAbsent: { type: "boolean", },
|
|
563
|
+
remoteSha256: { type: "string", pattern: "^[a-f0-9]{64}$", },
|
|
564
|
+
remoteBytes: { type: "integer", minimum: 0, },
|
|
565
|
+
localSha256: { type: "string", pattern: "^[a-f0-9]{64}$", },
|
|
566
|
+
localBytes: { type: "integer", minimum: 0, },
|
|
567
|
+
maxLines: { type: "integer", minimum: 0, },
|
|
568
|
+
},
|
|
569
|
+
},
|
|
570
|
+
"project.list": ProjectSummaryArraySchema,
|
|
571
|
+
"project.get": ProjectDetailsSchema,
|
|
572
|
+
"project.metadata": ProjectMetadataSchema,
|
|
573
|
+
"dataset.list": DatasetSummaryArraySchema,
|
|
574
|
+
"dataset.get": DatasetDetailsSchema,
|
|
575
|
+
"dataset.schema": DatasetSchemaSchema,
|
|
576
|
+
"recipe.list": RecipeSummaryArraySchema,
|
|
577
|
+
"job.list": JobSummaryArraySchema,
|
|
578
|
+
"job.wait": JobWaitResultSchema,
|
|
579
|
+
"job.monitor": JobWaitResultSchema,
|
|
580
|
+
"scenario.list": ScenarioSummaryArraySchema,
|
|
581
|
+
"scenario.get": ScenarioDetailsSchema,
|
|
582
|
+
"scenario.status": ScenarioStatusSchema,
|
|
583
|
+
"flow-zone.list": FlowZoneArraySchema,
|
|
584
|
+
"flow-zone.get": FlowZoneSchema,
|
|
585
|
+
"sql.query": {
|
|
586
|
+
anyOf: [
|
|
587
|
+
SqlQueryResponseSchema,
|
|
588
|
+
{
|
|
589
|
+
type: "object",
|
|
590
|
+
required: ["queryId", "rowCount", "preview",],
|
|
591
|
+
additionalProperties: true,
|
|
592
|
+
properties: {
|
|
593
|
+
queryId: { type: "string", },
|
|
594
|
+
rowCount: { type: "number", },
|
|
595
|
+
preview: { type: "array", items: true, },
|
|
596
|
+
truncated: { type: "boolean", },
|
|
597
|
+
outputPath: { type: "string", },
|
|
598
|
+
written: { type: "string", },
|
|
599
|
+
},
|
|
600
|
+
},
|
|
601
|
+
],
|
|
602
|
+
},
|
|
603
|
+
};
|
|
604
|
+
function outputJsonSchema(resource, action, shape) {
|
|
605
|
+
const precise = COMMAND_OUTPUT_SCHEMAS[registryKey(resource, action)];
|
|
606
|
+
if (precise)
|
|
607
|
+
return precise;
|
|
411
608
|
if (shape === "array")
|
|
412
609
|
return { type: "array", items: true, };
|
|
413
610
|
if (shape === "string")
|
|
@@ -417,6 +614,9 @@ function outputJsonSchema(shape) {
|
|
|
417
614
|
function payloadJsonSchema(payloadSchema) {
|
|
418
615
|
if (!payloadSchema)
|
|
419
616
|
return undefined;
|
|
617
|
+
if (payloadSchema.contentType === "text/plain") {
|
|
618
|
+
return { type: "string", contentMediaType: "text/plain", };
|
|
619
|
+
}
|
|
420
620
|
return payloadSchema.jsonShape === "array"
|
|
421
621
|
? { type: "array", items: true, }
|
|
422
622
|
: { type: "object", additionalProperties: true, };
|
|
@@ -549,11 +749,11 @@ function unsafeOutputs(resource, action, producesLocalFile) {
|
|
|
549
749
|
condition: "--output or --output-file",
|
|
550
750
|
kind: "local-file",
|
|
551
751
|
detail: sensitivePermissions
|
|
552
|
-
? "
|
|
553
|
-
: "
|
|
752
|
+
? "Writes access-control identities and permissions to an owner-only local file."
|
|
753
|
+
: "Writes a local file; stdout contains JSON metadata.",
|
|
554
754
|
...(sensitivePermissions
|
|
555
755
|
? {
|
|
556
|
-
safeAlternative: "Keep
|
|
756
|
+
safeAlternative: "Keep owner-only and outside version control unless repository policy explicitly permits committing access-control data.",
|
|
557
757
|
}
|
|
558
758
|
: {}),
|
|
559
759
|
});
|
|
@@ -564,10 +764,13 @@ export function buildCommandSchemas(resource, action, flags, requiredFlags, requ
|
|
|
564
764
|
return {
|
|
565
765
|
argv: argvJsonSchema(resource, action, flags, usage, requiredFlags, requiredOneOf),
|
|
566
766
|
...(payloadSchema ? { input: payloadJsonSchema(payloadSchema), } : {}),
|
|
567
|
-
output: outputJsonSchema(outputShape),
|
|
767
|
+
output: outputJsonSchema(resource, action, outputShape),
|
|
568
768
|
};
|
|
569
769
|
}
|
|
570
770
|
const EXPLICIT_REGISTRY_OVERRIDES = {
|
|
771
|
+
"code.run": {
|
|
772
|
+
payloadSchema: { stdin: true, contentType: "text/plain", },
|
|
773
|
+
},
|
|
571
774
|
"dashboard.create": {
|
|
572
775
|
examplePayload: { name: "Agent dashboard", pages: [], },
|
|
573
776
|
},
|
|
@@ -620,8 +823,78 @@ function extractUsageFlags(usage) {
|
|
|
620
823
|
}
|
|
621
824
|
return uniqueStrings(flags).filter((flag) => KNOWN_LONG_FLAGS.has(flag));
|
|
622
825
|
}
|
|
623
|
-
function
|
|
624
|
-
|
|
826
|
+
function extractPositionalArguments(usage) {
|
|
827
|
+
const positionals = [];
|
|
828
|
+
const add = (name, required) => {
|
|
829
|
+
const existing = positionals.find((positional) => positional.name === name);
|
|
830
|
+
if (existing)
|
|
831
|
+
existing.required ||= required;
|
|
832
|
+
else
|
|
833
|
+
positionals.push({ name, required, });
|
|
834
|
+
};
|
|
835
|
+
for (const match of usage.matchAll(/<([^>]+)>/g)) {
|
|
836
|
+
const before = usage.slice(0, match.index);
|
|
837
|
+
const openParen = before.lastIndexOf("(");
|
|
838
|
+
const insideParen = openParen > before.lastIndexOf(")");
|
|
839
|
+
const closeParen = insideParen ? usage.indexOf(")", match.index) : -1;
|
|
840
|
+
const group = closeParen >= 0 ? usage.slice(openParen + 1, closeParen) : "";
|
|
841
|
+
const hasFlagAlternative = group.split("|").some((alternative) => alternative.includes("--"));
|
|
842
|
+
const required = before.lastIndexOf("[") <= before.lastIndexOf("]")
|
|
843
|
+
&& !hasFlagAlternative;
|
|
844
|
+
add(match[1], required);
|
|
845
|
+
}
|
|
846
|
+
for (const suffix of usage.split("[").slice(1)) {
|
|
847
|
+
const candidate = suffix.split("]", 1)[0];
|
|
848
|
+
if (candidate && /^[A-Za-z][A-Za-z0-9_-]*$/.test(candidate))
|
|
849
|
+
add(candidate, false);
|
|
850
|
+
}
|
|
851
|
+
for (const group of topLevelParenGroups(usage)) {
|
|
852
|
+
const candidate = group.split("|", 1)[0]?.trim();
|
|
853
|
+
if (candidate && /^[A-Z][A-Z0-9_-]*$/.test(candidate))
|
|
854
|
+
add(candidate, false);
|
|
855
|
+
}
|
|
856
|
+
return positionals;
|
|
857
|
+
}
|
|
858
|
+
const COMMAND_REQUIRED_INPUT_GROUPS = {
|
|
859
|
+
"notebook.unload-jupyter": [
|
|
860
|
+
{
|
|
861
|
+
oneOf: [
|
|
862
|
+
{ positionals: ["name", "sessionId",], },
|
|
863
|
+
{ flags: ["all",], },
|
|
864
|
+
],
|
|
865
|
+
},
|
|
866
|
+
],
|
|
867
|
+
"sql.query": [
|
|
868
|
+
{
|
|
869
|
+
oneOf: [
|
|
870
|
+
{ positionals: ["SQL",], },
|
|
871
|
+
{ flags: ["sql",], },
|
|
872
|
+
{ flags: ["sql-file",], },
|
|
873
|
+
{ flags: ["stdin",], },
|
|
874
|
+
],
|
|
875
|
+
},
|
|
876
|
+
{ oneOf: [{ flags: ["connection",], }, { flags: ["dataset",], },], },
|
|
877
|
+
],
|
|
878
|
+
"flow-zone.move": [
|
|
879
|
+
{
|
|
880
|
+
oneOf: [
|
|
881
|
+
{ positionals: ["id",], },
|
|
882
|
+
{ flags: ["zone",], },
|
|
883
|
+
{ flags: ["zone-id",], },
|
|
884
|
+
],
|
|
885
|
+
},
|
|
886
|
+
{
|
|
887
|
+
oneOf: [
|
|
888
|
+
{ flags: ["dataset",], },
|
|
889
|
+
{ flags: ["recipe",], },
|
|
890
|
+
{ flags: ["folder",], },
|
|
891
|
+
{ flags: ["object",], },
|
|
892
|
+
],
|
|
893
|
+
},
|
|
894
|
+
],
|
|
895
|
+
};
|
|
896
|
+
function requiredInputGroups(resource, action) {
|
|
897
|
+
return COMMAND_REQUIRED_INPUT_GROUPS[registryKey(resource, action)] ?? [];
|
|
625
898
|
}
|
|
626
899
|
function inferSideEffect(resource, action) {
|
|
627
900
|
if (resource === "auth")
|
|
@@ -633,6 +906,10 @@ function inferSideEffect(resource, action) {
|
|
|
633
906
|
}
|
|
634
907
|
if (resource === "install-skill")
|
|
635
908
|
return "write";
|
|
909
|
+
if (resource === "sql" && action === "query")
|
|
910
|
+
return "write";
|
|
911
|
+
if (resource === "ml-task" && action === "train")
|
|
912
|
+
return "write";
|
|
636
913
|
// Project and dashboard exports stream a rendered/archive artifact and write it
|
|
637
914
|
// locally; the DSS-side resource is untouched.
|
|
638
915
|
if ((resource === "project" || resource === "dashboard") && action === "export")
|
|
@@ -668,6 +945,8 @@ export function inferRequiresProject(resource, action, usage) {
|
|
|
668
945
|
|| resource === "install-skill" || resource === "version") {
|
|
669
946
|
return false;
|
|
670
947
|
}
|
|
948
|
+
if (resource === "sql" && action === "query")
|
|
949
|
+
return false;
|
|
671
950
|
if (PROJECT_SCOPED_RESOURCES.has(resource))
|
|
672
951
|
return true;
|
|
673
952
|
if (resource === "project-git")
|
|
@@ -828,6 +1107,11 @@ const GLOBAL_FLAG_VALUE_HINTS = {
|
|
|
828
1107
|
"ca-cert": { valueType: "PATH", },
|
|
829
1108
|
"project-key": { valueType: "KEY", },
|
|
830
1109
|
"record-cleanup": { valueType: "PATH", },
|
|
1110
|
+
color: { valueType: "HEX", },
|
|
1111
|
+
data: { valueType: "JSON", },
|
|
1112
|
+
local: { valueType: "JSON", },
|
|
1113
|
+
standard: { valueType: "JSON", },
|
|
1114
|
+
until: { valueType: "STATE", },
|
|
831
1115
|
};
|
|
832
1116
|
/** Derive a value placeholder (and enum members) for each value flag from its usage token. */
|
|
833
1117
|
function extractFlagValueHints(usage) {
|
|
@@ -866,6 +1150,7 @@ function inferExitCodes(resource, action, asyncKind) {
|
|
|
866
1150
|
|| `${resource}.${action}` === "dataset.assert-count"
|
|
867
1151
|
|| `${resource}.${action}` === "dataset.assert-schema"
|
|
868
1152
|
|| `${resource}.${action}` === "data-quality.assert-results"
|
|
1153
|
+
|| `${resource}.${action}` === "flow-zone.organize"
|
|
869
1154
|
|| `${resource}.${action}` === "batch.run";
|
|
870
1155
|
return {
|
|
871
1156
|
ok: 0,
|
|
@@ -877,6 +1162,12 @@ function inferExitCodes(resource, action, asyncKind) {
|
|
|
877
1162
|
};
|
|
878
1163
|
}
|
|
879
1164
|
function cleanupCommandFromDeleteUsage(resource, action) {
|
|
1165
|
+
if (`${resource}.${action}` === "notebook.save-jupyter") {
|
|
1166
|
+
return "dss notebook delete-jupyter <name> --if-exists";
|
|
1167
|
+
}
|
|
1168
|
+
if (`${resource}.${action}` === "notebook.save-sql") {
|
|
1169
|
+
return "dss notebook delete-sql <id> --if-exists";
|
|
1170
|
+
}
|
|
880
1171
|
if (`${resource}.${action}` === "project.import") {
|
|
881
1172
|
return "dss project delete <used-project-key> --if-exists --expect-project-incarnation <hash>";
|
|
882
1173
|
}
|
|
@@ -911,6 +1202,7 @@ export function supportsCleanupLedger(resource, action) {
|
|
|
911
1202
|
*/
|
|
912
1203
|
const EXPLICIT_DESTRUCTIVE_KEYS = {
|
|
913
1204
|
"dataset.upload-file": true,
|
|
1205
|
+
"sql.query": true,
|
|
914
1206
|
};
|
|
915
1207
|
function inferDestructiveLevel(resource, sideEffect, action) {
|
|
916
1208
|
if (sideEffect !== "write")
|
|
@@ -930,6 +1222,8 @@ function inferAsyncKind(resource, action) {
|
|
|
930
1222
|
}
|
|
931
1223
|
if (resource === "recipe" && action === "run")
|
|
932
1224
|
return "job";
|
|
1225
|
+
if (resource === "ml-task" && action === "train")
|
|
1226
|
+
return "job";
|
|
933
1227
|
if (resource === "future" && ["get", "peek", "wait", "abort",].includes(action))
|
|
934
1228
|
return "future";
|
|
935
1229
|
if (resource === "scenario" && ["run", "run-and-wait", "status",].includes(action)) {
|
|
@@ -943,6 +1237,11 @@ function inferAsyncKind(resource, action) {
|
|
|
943
1237
|
return "future";
|
|
944
1238
|
if (resource === "code" && action === "run")
|
|
945
1239
|
return "future";
|
|
1240
|
+
if (resource === "webapp" && action === "restart-backend")
|
|
1241
|
+
return "future";
|
|
1242
|
+
if (resource === "code-env"
|
|
1243
|
+
&& ["create", "update-packages", "update-images", "set-jupyter", "delete",].includes(action))
|
|
1244
|
+
return "future";
|
|
946
1245
|
if (resource === "app"
|
|
947
1246
|
&& ["create-instance", "create-successor-instance", "delete-instance",].includes(action)) {
|
|
948
1247
|
return "future";
|
|
@@ -952,6 +1251,8 @@ function inferAsyncKind(resource, action) {
|
|
|
952
1251
|
function inferIdempotency(resource, sideEffect, action, usage) {
|
|
953
1252
|
if (sideEffect === "read")
|
|
954
1253
|
return "safe";
|
|
1254
|
+
if (`${resource}.${action}` === "install-skill.run")
|
|
1255
|
+
return "convergent";
|
|
955
1256
|
if (action.startsWith("create") && usage.includes("--if-not-exists"))
|
|
956
1257
|
return "if-not-exists";
|
|
957
1258
|
if (action.startsWith("delete") && usage.includes("--if-exists"))
|
|
@@ -990,25 +1291,33 @@ export function inferCleanupHint(resource, action) {
|
|
|
990
1291
|
// tag create has a generic `delete` command to close it out.
|
|
991
1292
|
if (resource === "project-git")
|
|
992
1293
|
return undefined;
|
|
1294
|
+
const key = `${resource}.${action}`;
|
|
1295
|
+
if (key === "notebook.save-jupyter") {
|
|
1296
|
+
return "If created:true, delete with `dss notebook delete-jupyter <name> --if-exists`.";
|
|
1297
|
+
}
|
|
1298
|
+
if (key === "notebook.save-sql") {
|
|
1299
|
+
return "If created:true, delete with `dss notebook delete-sql <id> --if-exists`.";
|
|
1300
|
+
}
|
|
993
1301
|
if (!(action.startsWith("create") || action === "clone"))
|
|
994
1302
|
return undefined;
|
|
995
|
-
if (LEDGER_ONLY_CLEANUP_KEYS[
|
|
1303
|
+
if (LEDGER_ONLY_CLEANUP_KEYS[key] === true)
|
|
996
1304
|
return LEDGER_ONLY_CLEANUP_HINT;
|
|
997
|
-
}
|
|
998
1305
|
const deleteAction = action === "create-rule"
|
|
999
1306
|
? "delete-rule"
|
|
1000
1307
|
: action === "create-instance" || action === "create-successor-instance"
|
|
1001
1308
|
? "delete-instance"
|
|
1002
1309
|
: "delete";
|
|
1003
1310
|
const deleteUsage = commands[resource]?.[deleteAction]?.usage;
|
|
1004
|
-
|
|
1311
|
+
if (!deleteUsage)
|
|
1312
|
+
return undefined;
|
|
1313
|
+
const ifExists = deleteUsage.includes("--if-exists") ? " --if-exists" : "";
|
|
1005
1314
|
if (resource === "code-env") {
|
|
1006
1315
|
return `Delete with \`dss code-env delete <lang> <name>${ifExists}\`.`;
|
|
1007
1316
|
}
|
|
1008
1317
|
if (resource === "data-quality") {
|
|
1009
1318
|
return `Delete with \`dss data-quality delete-rule <dataset> <rule-id>${ifExists}\`.`;
|
|
1010
1319
|
}
|
|
1011
|
-
return `
|
|
1320
|
+
return `For disposable creates: \`dss ${resource} delete <id>${ifExists}\`.`;
|
|
1012
1321
|
}
|
|
1013
1322
|
function buildRegistryEntry(resource, action, meta) {
|
|
1014
1323
|
const requiresAuth = meta.localHandler === undefined && inferRequiresAuth(resource);
|
|
@@ -1074,7 +1383,9 @@ function buildRegistryEntry(resource, action, meta) {
|
|
|
1074
1383
|
...allowEmptyPart,
|
|
1075
1384
|
};
|
|
1076
1385
|
});
|
|
1077
|
-
const
|
|
1386
|
+
const positionalArguments = extractPositionalArguments(meta.usage);
|
|
1387
|
+
const positionals = positionalArguments.map((positional) => positional.name);
|
|
1388
|
+
const inputGroups = requiredInputGroups(resource, action);
|
|
1078
1389
|
const outputShape = inferOutputShape(resource, action);
|
|
1079
1390
|
const producesLocalFile = meta.usage.includes("--output PATH")
|
|
1080
1391
|
|| meta.usage.includes("--output-file PATH");
|
|
@@ -1090,6 +1401,7 @@ function buildRegistryEntry(resource, action, meta) {
|
|
|
1090
1401
|
structuredExamples: structuredExamples(meta.examples, examplePayload),
|
|
1091
1402
|
flags: flagMetadata,
|
|
1092
1403
|
positionals,
|
|
1404
|
+
positionalArguments,
|
|
1093
1405
|
sideEffect,
|
|
1094
1406
|
requiresAuth,
|
|
1095
1407
|
requiresProject,
|
|
@@ -1104,6 +1416,7 @@ function buildRegistryEntry(resource, action, meta) {
|
|
|
1104
1416
|
requiredFlags: uniqueRequiredFlags,
|
|
1105
1417
|
optionalFlags: uniqueOptionalFlags,
|
|
1106
1418
|
...(requiredOneOf.length > 0 ? { requiredOneOf, } : {}),
|
|
1419
|
+
...(inputGroups.length > 0 ? { requiredInputGroups: inputGroups, } : {}),
|
|
1107
1420
|
...(payloadSchema ? { payloadSchema, } : {}),
|
|
1108
1421
|
schemas: buildCommandSchemas(resource, action, flagMetadata, uniqueRequiredFlags, requiredOneOf, payloadSchema, outputShape, meta.usage),
|
|
1109
1422
|
...(unsafe ? { unsafeOutputs: unsafe, } : {}),
|
|
@@ -1114,81 +1427,99 @@ function buildRegistryEntry(resource, action, meta) {
|
|
|
1114
1427
|
agentContractVersion: AGENT_CONTRACT_VERSION,
|
|
1115
1428
|
};
|
|
1116
1429
|
}
|
|
1117
|
-
export function buildCommandRegistry() {
|
|
1430
|
+
export function buildCommandRegistry(resourceFilter) {
|
|
1118
1431
|
const registry = {};
|
|
1119
1432
|
for (const [resource, actions,] of Object.entries(commands)) {
|
|
1433
|
+
if (resourceFilter !== undefined && resource !== resourceFilter)
|
|
1434
|
+
continue;
|
|
1120
1435
|
registry[resource] = {};
|
|
1121
1436
|
for (const [action, meta,] of Object.entries(actions)) {
|
|
1122
1437
|
registry[resource][action] = buildRegistryEntry(resource, action, meta);
|
|
1123
1438
|
}
|
|
1124
1439
|
}
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1440
|
+
if (resourceFilter === undefined || resourceFilter === "commands") {
|
|
1441
|
+
registry.commands = {
|
|
1442
|
+
run: buildRegistryEntry("commands", "run", {
|
|
1443
|
+
handler: async () => undefined,
|
|
1444
|
+
usage: COMMANDS_USAGE,
|
|
1445
|
+
description: COMMANDS_DESCRIPTION,
|
|
1446
|
+
examples: COMMANDS_EXAMPLES,
|
|
1447
|
+
}),
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
if (resourceFilter === undefined || resourceFilter === "agent") {
|
|
1451
|
+
registry.agent = {
|
|
1452
|
+
contract: buildRegistryEntry("agent", "contract", {
|
|
1453
|
+
handler: async () => undefined,
|
|
1454
|
+
usage: AGENT_CONTRACT_USAGE,
|
|
1455
|
+
description: AGENT_CONTRACT_DESCRIPTION,
|
|
1456
|
+
examples: AGENT_CONTRACT_EXAMPLES,
|
|
1457
|
+
}),
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
if (resourceFilter === undefined || resourceFilter === "version") {
|
|
1461
|
+
registry.version = {
|
|
1462
|
+
run: buildRegistryEntry("version", "run", {
|
|
1463
|
+
handler: async () => undefined,
|
|
1464
|
+
usage: VERSION_USAGE,
|
|
1465
|
+
description: VERSION_DESCRIPTION,
|
|
1466
|
+
examples: VERSION_EXAMPLES,
|
|
1467
|
+
}),
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
if (resourceFilter === undefined || resourceFilter === "install-skill") {
|
|
1471
|
+
registry["install-skill"] = {
|
|
1472
|
+
run: buildRegistryEntry("install-skill", "run", {
|
|
1473
|
+
handler: async () => undefined,
|
|
1474
|
+
usage: INSTALL_SKILL_USAGE,
|
|
1475
|
+
description: INSTALL_SKILL_DESCRIPTION,
|
|
1476
|
+
examples: INSTALL_SKILL_EXAMPLES,
|
|
1477
|
+
}),
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
if (resourceFilter === undefined || resourceFilter === "cleanup") {
|
|
1481
|
+
registry.cleanup = {
|
|
1482
|
+
run: buildRegistryEntry("cleanup", "run", {
|
|
1483
|
+
handler: async () => undefined,
|
|
1484
|
+
usage: CLEANUP_USAGE,
|
|
1485
|
+
description: CLEANUP_DESCRIPTION,
|
|
1486
|
+
examples: CLEANUP_EXAMPLES,
|
|
1487
|
+
}),
|
|
1488
|
+
};
|
|
1489
|
+
}
|
|
1490
|
+
if (resourceFilter === undefined || resourceFilter === "fixtures") {
|
|
1491
|
+
registry.fixtures = {
|
|
1492
|
+
run: buildRegistryEntry("fixtures", "run", {
|
|
1493
|
+
handler: async () => undefined,
|
|
1494
|
+
usage: FIXTURES_USAGE,
|
|
1495
|
+
description: FIXTURES_DESCRIPTION,
|
|
1496
|
+
examples: FIXTURES_EXAMPLES,
|
|
1497
|
+
}),
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
if (resourceFilter === undefined || resourceFilter === "batch") {
|
|
1501
|
+
registry.batch = {
|
|
1502
|
+
run: buildRegistryEntry("batch", "run", {
|
|
1503
|
+
handler: async () => undefined,
|
|
1504
|
+
usage: BATCH_USAGE,
|
|
1505
|
+
description: BATCH_DESCRIPTION,
|
|
1506
|
+
examples: BATCH_EXAMPLES,
|
|
1507
|
+
examplePayload: BATCH_EXAMPLE_PAYLOAD,
|
|
1508
|
+
payloadSchema: { stdin: true, dataFlag: true, dataFileFlag: true, jsonShape: "array", },
|
|
1509
|
+
}),
|
|
1510
|
+
};
|
|
1511
|
+
}
|
|
1512
|
+
if (resourceFilter === undefined || resourceFilter === "auth") {
|
|
1513
|
+
registry.auth = {};
|
|
1514
|
+
for (const [action, meta,] of Object.entries(AUTH_ACTIONS)) {
|
|
1515
|
+
registry.auth[action] = buildRegistryEntry("auth", action, {
|
|
1516
|
+
handler: async () => undefined,
|
|
1517
|
+
usage: meta.usage,
|
|
1518
|
+
description: meta.description,
|
|
1519
|
+
examples: meta.examples,
|
|
1520
|
+
requiredFlags: meta.requiredFlags,
|
|
1521
|
+
});
|
|
1522
|
+
}
|
|
1192
1523
|
}
|
|
1193
1524
|
return registry;
|
|
1194
1525
|
}
|
|
@@ -1216,6 +1547,7 @@ function commandRegistryEntryJsonSchema() {
|
|
|
1216
1547
|
"usage",
|
|
1217
1548
|
"flags",
|
|
1218
1549
|
"positionals",
|
|
1550
|
+
"positionalArguments",
|
|
1219
1551
|
"sideEffect",
|
|
1220
1552
|
"requiresAuth",
|
|
1221
1553
|
"requiresProject",
|
|
@@ -1235,6 +1567,15 @@ function commandRegistryEntryJsonSchema() {
|
|
|
1235
1567
|
structuredExamples: { type: "array", items: { type: "object", additionalProperties: true, }, },
|
|
1236
1568
|
flags: { type: "array", items: commandFlagJsonSchema(), },
|
|
1237
1569
|
positionals: { type: "array", items: { type: "string", }, },
|
|
1570
|
+
positionalArguments: {
|
|
1571
|
+
type: "array",
|
|
1572
|
+
items: {
|
|
1573
|
+
type: "object",
|
|
1574
|
+
required: ["name", "required",],
|
|
1575
|
+
additionalProperties: false,
|
|
1576
|
+
properties: { name: { type: "string", }, required: { type: "boolean", }, },
|
|
1577
|
+
},
|
|
1578
|
+
},
|
|
1238
1579
|
sideEffect: { enum: ["read", "write", "auth",], },
|
|
1239
1580
|
requiresAuth: { type: "boolean", },
|
|
1240
1581
|
requiresProject: { type: "boolean", },
|
|
@@ -1247,6 +1588,7 @@ function commandRegistryEntryJsonSchema() {
|
|
|
1247
1588
|
idempotency: { enum: ["safe", "convergent", "if-not-exists", "if-exists", "none",], },
|
|
1248
1589
|
dryRun: { type: "boolean", },
|
|
1249
1590
|
requiredFlags: { type: "array", items: { type: "string", }, },
|
|
1591
|
+
requiredInputGroups: { type: "array", items: { type: "object", additionalProperties: true, }, },
|
|
1250
1592
|
optionalFlags: { type: "array", items: { type: "string", }, },
|
|
1251
1593
|
schemas: { type: "object", additionalProperties: true, },
|
|
1252
1594
|
unsafeOutputs: { type: "array", items: { type: "object", additionalProperties: true, }, },
|
|
@@ -1275,8 +1617,13 @@ function errorEnvelopeJsonSchema() {
|
|
|
1275
1617
|
ok: { const: false, },
|
|
1276
1618
|
error: { type: "string", },
|
|
1277
1619
|
code: { type: "string", },
|
|
1278
|
-
category: { enum: ["usage", "dss", "internal",], },
|
|
1620
|
+
category: { enum: ["usage", "permission_or_environment", "dss", "internal",], },
|
|
1279
1621
|
exitCode: { type: "number", },
|
|
1622
|
+
hint: { type: "string", },
|
|
1623
|
+
status: { type: "number", },
|
|
1624
|
+
retryable: { type: "boolean", },
|
|
1625
|
+
requestId: { type: "string", },
|
|
1626
|
+
details: { type: "object", additionalProperties: true, },
|
|
1280
1627
|
resource: { type: "string", },
|
|
1281
1628
|
action: { type: "string", },
|
|
1282
1629
|
projectKey: { type: "string", },
|
|
@@ -1351,7 +1698,7 @@ export function buildAgentContract() {
|
|
|
1351
1698
|
"dss commands run --fields dataset",
|
|
1352
1699
|
"dss commands run --fields dataset.create",
|
|
1353
1700
|
],
|
|
1354
|
-
scopedDiscoveryHint: "
|
|
1701
|
+
scopedDiscoveryHint: "Default: resource/action summary. --fields RESOURCE: all resource entries; RESOURCE.ACTION: one entry keyed by that path; append .FIELD for nested metadata. Comma-separate paths. --output PATH exports the full registry.",
|
|
1355
1702
|
actions: commandActionSummary(registry),
|
|
1356
1703
|
},
|
|
1357
1704
|
schemas: {
|
|
@@ -1367,7 +1714,9 @@ export function buildAgentContract() {
|
|
|
1367
1714
|
format: "compact-json",
|
|
1368
1715
|
success: "single-json-value",
|
|
1369
1716
|
failure: "structured-error-object",
|
|
1370
|
-
|
|
1717
|
+
failureResultDetailLimitBytes: 65_536,
|
|
1718
|
+
fieldProjection: "Missing --fields paths: null on stdout; field_projection_missing on stderr.",
|
|
1719
|
+
richFailureResults: "doctor/batch/cleanup failures: own compact {ok:false,...} result on stdout and command exit code; no wrapper.",
|
|
1371
1720
|
},
|
|
1372
1721
|
stderr: {
|
|
1373
1722
|
format: "jsonl",
|
|
@@ -1384,7 +1733,7 @@ export function buildAgentContract() {
|
|
|
1384
1733
|
},
|
|
1385
1734
|
compatibility: {
|
|
1386
1735
|
fieldsAreAdditiveWithinMajor: true,
|
|
1387
|
-
failFastWhenUnsupported: "Check agentContractVersion before planning
|
|
1736
|
+
failFastWhenUnsupported: "Check agentContractVersion before planning.",
|
|
1388
1737
|
},
|
|
1389
1738
|
};
|
|
1390
1739
|
}
|
|
@@ -1454,7 +1803,9 @@ function requiredPlanJsonInput(flags, usage) {
|
|
|
1454
1803
|
return requiredJsonInput(flags, `--data, --data-file, or --stdin is required. Usage: ${usage}`);
|
|
1455
1804
|
}
|
|
1456
1805
|
function requiredPlanPositionals(usage) {
|
|
1457
|
-
return
|
|
1806
|
+
return extractPositionalArguments(usage)
|
|
1807
|
+
.filter((positional) => positional.required)
|
|
1808
|
+
.map((positional) => positional.name);
|
|
1458
1809
|
}
|
|
1459
1810
|
function dataQualityEndpoint(projectKey, datasetName, suffix) {
|
|
1460
1811
|
return encodedProjectEndpointForPlan(projectKey, `/datasets/${encodeURIComponent(datasetName)}/data-quality${suffix}`);
|
|
@@ -1482,11 +1833,6 @@ function projectGitEndpoint(projectKey, suffix) {
|
|
|
1482
1833
|
function projectGitFutureEndpoint(jobId) {
|
|
1483
1834
|
return `${PROJECT_GIT_API_ROOT}/futures/${encodeURIComponent(jobId)}`;
|
|
1484
1835
|
}
|
|
1485
|
-
/** Encode a library reference path per segment, mirroring the resource helper. */
|
|
1486
|
-
function encodeGitReferencePath(pathValue) {
|
|
1487
|
-
const normalized = pathValue.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
1488
|
-
return normalized.split("/").map((segment) => encodeURIComponent(segment)).join("/");
|
|
1489
|
-
}
|
|
1490
1836
|
/**
|
|
1491
1837
|
* `--plan` bypasses the SDK boundary guard, so HTTP(S) URLs with embedded
|
|
1492
1838
|
* userinfo are rejected here before any plan is printed. SSH/scp-style URLs
|
|
@@ -1566,10 +1912,33 @@ export function commandPlanShape(resource, action, args, flags, entry, projectKe
|
|
|
1566
1912
|
return encodedProjectEndpointForPlan(projectKey, suffix);
|
|
1567
1913
|
};
|
|
1568
1914
|
const id = args[0];
|
|
1569
|
-
const codeEnvEndpoint = (suffix = "") => `/public/api/admin/code-envs/${encodeURIComponent(args[0])}/${encodeURIComponent(args[1])}${suffix}`;
|
|
1915
|
+
const codeEnvEndpoint = (suffix = "") => `/public/api/admin/code-envs/${encodeURIComponent(codeEnvLang(args[0], entry.usage))}/${encodeURIComponent(args[1])}${suffix}`;
|
|
1570
1916
|
const statisticsWorksheetsEndpoint = (datasetName) => projectEndpoint(`/datasets/${encodeURIComponent(datasetName)}/statistics/worksheets/`);
|
|
1571
1917
|
const statisticsWorksheetEndpoint = (datasetName, worksheetId) => `${statisticsWorksheetsEndpoint(datasetName)}${encodeURIComponent(worksheetId)}`;
|
|
1572
1918
|
switch (`${resource}.${action}`) {
|
|
1919
|
+
case "sql.query": {
|
|
1920
|
+
const payload = resolveSqlQueryInvocation(args, flags, planProjectKeyFromArgs(flags));
|
|
1921
|
+
return {
|
|
1922
|
+
method: "POST",
|
|
1923
|
+
endpoint: "/public/api/sql/queries/",
|
|
1924
|
+
identifiers: {
|
|
1925
|
+
connection: payload.connection,
|
|
1926
|
+
dataset: payload.datasetFullName,
|
|
1927
|
+
},
|
|
1928
|
+
payload,
|
|
1929
|
+
};
|
|
1930
|
+
}
|
|
1931
|
+
case "ml-task.train":
|
|
1932
|
+
return {
|
|
1933
|
+
method: "POST",
|
|
1934
|
+
endpoint: projectEndpoint(`/models/lab/${encodeURIComponent(args[0])}/${encodeURIComponent(args[1])}/train`),
|
|
1935
|
+
identifiers: { analysisId: args[0], mlTaskId: args[1], },
|
|
1936
|
+
payload: {
|
|
1937
|
+
sessionName: flags["session-name"],
|
|
1938
|
+
runQueue: false,
|
|
1939
|
+
},
|
|
1940
|
+
wait: flags["wait"] === true,
|
|
1941
|
+
};
|
|
1573
1942
|
case "wiki.create": {
|
|
1574
1943
|
const name = requiredPlanFlag(flags, "name", entry.usage);
|
|
1575
1944
|
return {
|
|
@@ -1939,17 +2308,72 @@ export function commandPlanShape(resource, action, args, flags, entry, projectKe
|
|
|
1939
2308
|
}
|
|
1940
2309
|
case "recipe.run":
|
|
1941
2310
|
return {
|
|
2311
|
+
exact: false,
|
|
2312
|
+
reason: "The job endpoint is exact, but DSS reads the recipe and its outputs before constructing the job payload; use recipe run --dry-run for a resolved payload.",
|
|
1942
2313
|
method: "POST",
|
|
1943
2314
|
endpoint: projectEndpoint("/jobs/"),
|
|
1944
2315
|
identifiers: { recipe: id, },
|
|
1945
|
-
payload: {
|
|
1946
|
-
recipe: id,
|
|
1947
|
-
outputResolution: "dynamic",
|
|
1948
|
-
projectKey,
|
|
1949
|
-
partition: flags["partition"],
|
|
1950
|
-
},
|
|
1951
2316
|
wait: recipeRunShouldWait(flags),
|
|
1952
2317
|
};
|
|
2318
|
+
case "code.run": {
|
|
2319
|
+
const { script, source, } = resolveCodeInputWithSource(args, flags);
|
|
2320
|
+
const sourceSha256 = sha256Hex(script);
|
|
2321
|
+
const scenarioBase = projectEndpoint("/scenarios/{generatedScenarioId}");
|
|
2322
|
+
const envName = flags["env"];
|
|
2323
|
+
const keepScenario = flags["keep"] === true;
|
|
2324
|
+
const timeoutMs = parseCodeRunIntegerFlag(flags["timeout"], "--timeout") ?? 120_000;
|
|
2325
|
+
const maxLogBytes = flags["full-log"] === true
|
|
2326
|
+
? 0
|
|
2327
|
+
: parseCodeRunIntegerFlag(flags["max-log-bytes"], "--max-log-bytes") ?? 1_048_576;
|
|
2328
|
+
return {
|
|
2329
|
+
method: "POST",
|
|
2330
|
+
endpoint: projectEndpoint("/scenarios/"),
|
|
2331
|
+
identifiers: {
|
|
2332
|
+
source,
|
|
2333
|
+
sourceSha256,
|
|
2334
|
+
sourceBytes: Buffer.byteLength(script),
|
|
2335
|
+
},
|
|
2336
|
+
requests: [
|
|
2337
|
+
{
|
|
2338
|
+
method: "POST",
|
|
2339
|
+
endpoint: projectEndpoint("/scenarios/"),
|
|
2340
|
+
payload: {
|
|
2341
|
+
id: "{generatedScenarioId}",
|
|
2342
|
+
name: "dss code run ({generatedScenarioId})",
|
|
2343
|
+
projectKey,
|
|
2344
|
+
type: "custom_python",
|
|
2345
|
+
params: {
|
|
2346
|
+
envSelection: envName
|
|
2347
|
+
? { envMode: "EXPLICIT_ENV", envName, }
|
|
2348
|
+
: { envMode: "INHERIT", },
|
|
2349
|
+
},
|
|
2350
|
+
},
|
|
2351
|
+
},
|
|
2352
|
+
{
|
|
2353
|
+
method: "PUT",
|
|
2354
|
+
endpoint: `${scenarioBase}/payload`,
|
|
2355
|
+
payload: { extension: "py", script: "<omitted>", },
|
|
2356
|
+
redactedFields: ["payload.script",],
|
|
2357
|
+
},
|
|
2358
|
+
{ method: "POST", endpoint: `${scenarioBase}/run/`, payload: {}, },
|
|
2359
|
+
{
|
|
2360
|
+
method: "GET",
|
|
2361
|
+
endpoint: `${scenarioBase}/get-run-for-trigger?triggerId={triggerId}&triggerRunId={triggerRunId}`,
|
|
2362
|
+
repeat: "until scenarioRun.result.outcome or timeout",
|
|
2363
|
+
},
|
|
2364
|
+
{
|
|
2365
|
+
method: "GET",
|
|
2366
|
+
endpoint: `${scenarioBase}/{runId}/log`,
|
|
2367
|
+
boundedBytes: maxLogBytes,
|
|
2368
|
+
},
|
|
2369
|
+
...keepScenario ? [] : [{ method: "DELETE", endpoint: scenarioBase, cleanup: true, },],
|
|
2370
|
+
],
|
|
2371
|
+
wait: {
|
|
2372
|
+
timeoutMs,
|
|
2373
|
+
pollEndpoint: `${scenarioBase}/get-run-for-trigger`,
|
|
2374
|
+
},
|
|
2375
|
+
};
|
|
2376
|
+
}
|
|
1953
2377
|
case "recipe.update":
|
|
1954
2378
|
return {
|
|
1955
2379
|
method: "PUT",
|
|
@@ -2710,27 +3134,187 @@ export function commandPlanShape(resource, action, args, flags, entry, projectKe
|
|
|
2710
3134
|
identifiers: { dataset: args[0], worksheetId: args[1], },
|
|
2711
3135
|
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
2712
3136
|
};
|
|
2713
|
-
case "
|
|
3137
|
+
case "webapp.create":
|
|
3138
|
+
return {
|
|
3139
|
+
method: "POST",
|
|
3140
|
+
endpoint: projectEndpoint("/webapps/"),
|
|
3141
|
+
payload: requiredPlanJsonInput(flags, entry.usage),
|
|
3142
|
+
};
|
|
3143
|
+
case "webapp.update-settings": {
|
|
3144
|
+
const patch = requiredPlanJsonInput(flags, entry.usage);
|
|
3145
|
+
const expectHash = flags["expect-hash"];
|
|
3146
|
+
if (expectHash !== undefined && !/^[a-fA-F0-9]{64}$/.test(expectHash)) {
|
|
3147
|
+
throw new UsageError("Expected webapp hash must be a 64-character SHA-256 hex digest.");
|
|
3148
|
+
}
|
|
3149
|
+
const endpoint = projectEndpoint(`/webapps/${encodeURIComponent(id)}`);
|
|
3150
|
+
return {
|
|
3151
|
+
exact: false,
|
|
3152
|
+
reason: "Apply GETs the current settings, deep-merges the patch, then PUTs the full object.",
|
|
3153
|
+
method: "PUT",
|
|
3154
|
+
endpoint,
|
|
3155
|
+
identifiers: {
|
|
3156
|
+
webappId: id,
|
|
3157
|
+
patchHash: stableHash(patch),
|
|
3158
|
+
...(expectHash ? { expectHash: expectHash.toLowerCase(), } : {}),
|
|
3159
|
+
},
|
|
3160
|
+
payload: { patch: "<omitted>", patchHash: stableHash(patch), },
|
|
3161
|
+
requests: [
|
|
3162
|
+
{ method: "GET", endpoint, purpose: "read full settings and verify expectHash", },
|
|
3163
|
+
{
|
|
3164
|
+
method: "PUT",
|
|
3165
|
+
endpoint,
|
|
3166
|
+
condition: "settings read and expected hash matched",
|
|
3167
|
+
payload: "<merged full settings>",
|
|
3168
|
+
},
|
|
3169
|
+
],
|
|
3170
|
+
};
|
|
3171
|
+
}
|
|
3172
|
+
case "webapp.stop-backend":
|
|
2714
3173
|
return {
|
|
2715
3174
|
method: "PUT",
|
|
2716
|
-
endpoint: projectEndpoint(`/
|
|
3175
|
+
endpoint: projectEndpoint(`/webapps/${encodeURIComponent(id)}/backend/actions/stop`),
|
|
3176
|
+
identifiers: { webappId: id, },
|
|
3177
|
+
payload: {},
|
|
3178
|
+
};
|
|
3179
|
+
case "webapp.restart-backend": {
|
|
3180
|
+
const endpoint = projectEndpoint(`/webapps/${encodeURIComponent(id)}/backend/actions/restart`);
|
|
3181
|
+
return {
|
|
3182
|
+
method: "PUT",
|
|
3183
|
+
endpoint,
|
|
3184
|
+
identifiers: { webappId: id, },
|
|
3185
|
+
payload: {},
|
|
3186
|
+
wait: {
|
|
3187
|
+
requested: flags["wait"] === true,
|
|
3188
|
+
timeoutMs: num(flags["timeout"], "--timeout"),
|
|
3189
|
+
pollIntervalMs: num(flags["poll-interval"], "--poll-interval"),
|
|
3190
|
+
},
|
|
3191
|
+
};
|
|
3192
|
+
}
|
|
3193
|
+
case "api-service.create":
|
|
3194
|
+
return {
|
|
3195
|
+
method: "POST",
|
|
3196
|
+
endpoint: projectEndpoint(`/apiservices/${encodeURIComponent(id)}`),
|
|
3197
|
+
identifiers: { serviceId: id, },
|
|
3198
|
+
payload: {},
|
|
3199
|
+
};
|
|
3200
|
+
case "api-service.save-settings": {
|
|
3201
|
+
const settings = requiredPlanJsonInput(flags, entry.usage);
|
|
3202
|
+
const expectHash = flags["expect-hash"];
|
|
3203
|
+
if (expectHash !== undefined && !/^[a-fA-F0-9]{64}$/.test(expectHash)) {
|
|
3204
|
+
throw new UsageError("Expected API service settings hash must be a 64-character SHA-256 hex digest.");
|
|
3205
|
+
}
|
|
3206
|
+
const endpoint = projectEndpoint(`/apiservices/${encodeURIComponent(id)}/settings`);
|
|
3207
|
+
const payload = {
|
|
3208
|
+
settings: "<omitted>",
|
|
3209
|
+
settingsHash: stableHash(settings),
|
|
3210
|
+
...(expectHash ? { expectHash: expectHash.toLowerCase(), } : {}),
|
|
3211
|
+
};
|
|
3212
|
+
return {
|
|
3213
|
+
method: "PUT",
|
|
3214
|
+
endpoint,
|
|
3215
|
+
identifiers: { serviceId: id, },
|
|
3216
|
+
payload,
|
|
3217
|
+
requests: [
|
|
3218
|
+
...(expectHash
|
|
3219
|
+
? [{ method: "GET", endpoint, purpose: "verify expectHash", },]
|
|
3220
|
+
: []),
|
|
3221
|
+
{
|
|
3222
|
+
method: "PUT",
|
|
3223
|
+
endpoint,
|
|
3224
|
+
condition: expectHash ? "hash matched" : "unconditional",
|
|
3225
|
+
payload,
|
|
3226
|
+
},
|
|
3227
|
+
],
|
|
3228
|
+
};
|
|
3229
|
+
}
|
|
3230
|
+
case "api-service.add-prediction-endpoint": {
|
|
3231
|
+
const endpoint = projectEndpoint(`/apiservices/${encodeURIComponent(id)}/settings`);
|
|
3232
|
+
return {
|
|
3233
|
+
exact: false,
|
|
3234
|
+
reason: "Apply GETs the full settings, appends one endpoint, then PUTs the full object.",
|
|
3235
|
+
method: "PUT",
|
|
3236
|
+
endpoint,
|
|
3237
|
+
identifiers: { serviceId: id, endpointId: args[1], savedModelId: args[2], },
|
|
3238
|
+
payload: { id: args[1], type: "STD_PREDICTION", modelRef: args[2], },
|
|
3239
|
+
requests: [
|
|
3240
|
+
{ method: "GET", endpoint, purpose: "read full settings", },
|
|
3241
|
+
{ method: "PUT", endpoint, payload: "<merged full settings>", },
|
|
3242
|
+
],
|
|
3243
|
+
};
|
|
3244
|
+
}
|
|
3245
|
+
case "api-service.create-package":
|
|
3246
|
+
case "api-service.delete-package":
|
|
3247
|
+
case "api-service.publish-package": {
|
|
3248
|
+
const serviceId = args[0];
|
|
3249
|
+
const packageId = args[1];
|
|
3250
|
+
const packageEndpoint = projectEndpoint(`/apiservices/${encodeURIComponent(serviceId)}/packages/${encodeURIComponent(packageId)}`);
|
|
3251
|
+
if (action === "delete-package") {
|
|
3252
|
+
return {
|
|
3253
|
+
method: "DELETE",
|
|
3254
|
+
endpoint: packageEndpoint,
|
|
3255
|
+
identifiers: { serviceId, packageId, },
|
|
3256
|
+
};
|
|
3257
|
+
}
|
|
3258
|
+
if (action === "publish-package") {
|
|
3259
|
+
return {
|
|
3260
|
+
method: "POST",
|
|
3261
|
+
endpoint: `${packageEndpoint}/publish${querySuffix({
|
|
3262
|
+
publishedServiceId: flags["published-service-id"],
|
|
3263
|
+
})}`,
|
|
3264
|
+
identifiers: { serviceId, packageId, },
|
|
3265
|
+
};
|
|
3266
|
+
}
|
|
3267
|
+
return {
|
|
3268
|
+
method: "POST",
|
|
3269
|
+
endpoint: packageEndpoint + querySuffix({
|
|
3270
|
+
releaseNotes: flags["release-notes"],
|
|
3271
|
+
}),
|
|
3272
|
+
identifiers: { serviceId, packageId, },
|
|
3273
|
+
};
|
|
3274
|
+
}
|
|
3275
|
+
case "bundle.export": {
|
|
3276
|
+
const evaluateProjectStandardsChecks = parseBooleanOption(flags["evaluate-standards-checks"], "--evaluate-standards-checks") ?? true;
|
|
3277
|
+
return {
|
|
3278
|
+
method: "PUT",
|
|
3279
|
+
endpoint: projectEndpoint("/bundles/exported/" + encodeURIComponent(id)) + querySuffix({
|
|
3280
|
+
releaseNotes: flags["release-notes"],
|
|
3281
|
+
evaluateProjectStandardsChecks,
|
|
3282
|
+
}),
|
|
2717
3283
|
identifiers: { bundleId: id, },
|
|
2718
3284
|
payload: {},
|
|
2719
3285
|
};
|
|
3286
|
+
}
|
|
2720
3287
|
case "bundle.publish":
|
|
2721
3288
|
return {
|
|
2722
3289
|
method: "POST",
|
|
2723
|
-
endpoint: projectEndpoint(
|
|
3290
|
+
endpoint: projectEndpoint("/bundles/" + encodeURIComponent(id) + "/publish") + querySuffix({
|
|
3291
|
+
publishedProjectKey: flags["published-project-key"],
|
|
3292
|
+
}),
|
|
2724
3293
|
identifiers: { bundleId: id, },
|
|
2725
3294
|
payload: {},
|
|
2726
3295
|
};
|
|
2727
|
-
case "bundle.activate":
|
|
3296
|
+
case "bundle.activate": {
|
|
3297
|
+
const rawScenarios = flags["scenarios"];
|
|
3298
|
+
let scenariosToEnable;
|
|
3299
|
+
if (rawScenarios !== undefined && rawScenarios !== false) {
|
|
3300
|
+
const parsed = json(rawScenarios);
|
|
3301
|
+
if (typeof parsed !== "object"
|
|
3302
|
+
|| parsed === null
|
|
3303
|
+
|| Array.isArray(parsed)
|
|
3304
|
+
|| !Object.values(parsed).every((value) => typeof value === "boolean")) {
|
|
3305
|
+
throw new UsageError("--scenarios must be a JSON object mapping scenario IDs to true|false.");
|
|
3306
|
+
}
|
|
3307
|
+
scenariosToEnable = parsed;
|
|
3308
|
+
}
|
|
2728
3309
|
return {
|
|
2729
3310
|
method: "POST",
|
|
2730
3311
|
endpoint: projectEndpoint(`/bundles/imported/${encodeURIComponent(id)}/actions/activate`),
|
|
2731
3312
|
identifiers: { bundleId: id, },
|
|
2732
|
-
payload:
|
|
3313
|
+
payload: scenariosToEnable === undefined
|
|
3314
|
+
? {}
|
|
3315
|
+
: { scenariosActiveOnActivation: scenariosToEnable, },
|
|
2733
3316
|
};
|
|
3317
|
+
}
|
|
2734
3318
|
case "bundle.preload":
|
|
2735
3319
|
return {
|
|
2736
3320
|
method: "POST",
|
|
@@ -2738,40 +3322,151 @@ export function commandPlanShape(resource, action, args, flags, entry, projectKe
|
|
|
2738
3322
|
identifiers: { bundleId: id, },
|
|
2739
3323
|
payload: {},
|
|
2740
3324
|
};
|
|
2741
|
-
case "
|
|
3325
|
+
case "project-library.create-file":
|
|
3326
|
+
case "project-library.create-folder": {
|
|
3327
|
+
const libraryPath = validateLibraryPath(id);
|
|
3328
|
+
const kind = action === "create-file" ? "contents" : "folders";
|
|
2742
3329
|
return {
|
|
3330
|
+
exact: false,
|
|
3331
|
+
reason: "Apply performs a live absence check before POST; --if-not-exists may stop after that read, and create never overwrites an existing item.",
|
|
2743
3332
|
method: "POST",
|
|
2744
|
-
endpoint:
|
|
2745
|
-
identifiers: {
|
|
3333
|
+
endpoint: projectEndpoint(`/libraries/${kind}/${encodeLibraryPath(libraryPath)}`),
|
|
3334
|
+
identifiers: { path: libraryPath, },
|
|
3335
|
+
};
|
|
3336
|
+
}
|
|
3337
|
+
case "project-library.put": {
|
|
3338
|
+
const libraryPath = validateLibraryPath(id);
|
|
3339
|
+
const endpoint = projectEndpoint(`/libraries/contents/${encodeLibraryPath(libraryPath)}`);
|
|
3340
|
+
const payload = projectLibraryPutPayload(flags);
|
|
3341
|
+
return {
|
|
3342
|
+
method: "POST",
|
|
3343
|
+
endpoint,
|
|
3344
|
+
identifiers: {
|
|
3345
|
+
path: libraryPath,
|
|
3346
|
+
concurrencyControl: payload.expectSha256
|
|
3347
|
+
? PROJECT_LIBRARY_CONCURRENCY_CONTROL
|
|
3348
|
+
: "none",
|
|
3349
|
+
},
|
|
3350
|
+
payload,
|
|
3351
|
+
...(payload.expectSha256
|
|
3352
|
+
? {
|
|
3353
|
+
requests: [
|
|
3354
|
+
{
|
|
3355
|
+
method: "GET",
|
|
3356
|
+
endpoint: `${endpoint}?dataEncoding=base64`,
|
|
3357
|
+
purpose: "verify expectSha256",
|
|
3358
|
+
},
|
|
3359
|
+
{ method: "POST", endpoint, condition: "hash matched", payload, },
|
|
3360
|
+
],
|
|
3361
|
+
}
|
|
3362
|
+
: {}),
|
|
3363
|
+
};
|
|
3364
|
+
}
|
|
3365
|
+
case "project-library.delete": {
|
|
3366
|
+
const libraryPath = validateLibraryPath(id);
|
|
3367
|
+
return {
|
|
3368
|
+
method: "DELETE",
|
|
3369
|
+
endpoint: projectEndpoint(`/libraries/contents/${encodeLibraryPath(libraryPath)}`),
|
|
3370
|
+
identifiers: { path: libraryPath, },
|
|
3371
|
+
};
|
|
3372
|
+
}
|
|
3373
|
+
case "project-library.rename": {
|
|
3374
|
+
const libraryPath = validateLibraryPath(id);
|
|
3375
|
+
const newName = validateLibraryName(args[1]);
|
|
3376
|
+
return {
|
|
3377
|
+
method: "POST",
|
|
3378
|
+
endpoint: projectEndpoint("/libraries/contents-actions/rename/"),
|
|
3379
|
+
identifiers: { path: libraryPath, newName, },
|
|
3380
|
+
payload: { oldPath: `/${libraryPath}`, newName, },
|
|
3381
|
+
};
|
|
3382
|
+
}
|
|
3383
|
+
case "project-library.move": {
|
|
3384
|
+
const libraryPath = validateLibraryPath(id);
|
|
3385
|
+
const destinationFolder = validateLibraryDestinationPath(args[1]);
|
|
3386
|
+
return {
|
|
3387
|
+
method: "POST",
|
|
3388
|
+
endpoint: projectEndpoint("/libraries/contents-actions/move"),
|
|
3389
|
+
identifiers: { path: libraryPath, destinationFolder, },
|
|
3390
|
+
payload: { oldPath: `/${libraryPath}`, newPath: destinationFolder, },
|
|
3391
|
+
};
|
|
3392
|
+
}
|
|
3393
|
+
case "code-env.create": {
|
|
3394
|
+
const wait = codeEnvWait(flags);
|
|
3395
|
+
return {
|
|
3396
|
+
method: "POST",
|
|
3397
|
+
endpoint: `${codeEnvEndpoint()}?wait=${wait}`,
|
|
3398
|
+
identifiers: { lang: codeEnvLang(args[0], entry.usage), name: args[1], },
|
|
2746
3399
|
payload: {
|
|
2747
|
-
|
|
2748
|
-
envName: args[1],
|
|
3400
|
+
...codeEnvParams(flags),
|
|
2749
3401
|
deploymentMode: requiredPlanFlag(flags, "deployment-mode", entry.usage),
|
|
2750
|
-
params: codeEnvParams(flags),
|
|
2751
|
-
wait: codeEnvWait(flags),
|
|
2752
3402
|
},
|
|
2753
|
-
wait
|
|
3403
|
+
wait,
|
|
2754
3404
|
};
|
|
2755
|
-
|
|
3405
|
+
}
|
|
3406
|
+
case "code-env.set-definition": {
|
|
3407
|
+
const definition = requiredPlanJsonInput(flags, entry.usage);
|
|
3408
|
+
const expectHash = flags["expect-hash"];
|
|
3409
|
+
if (expectHash !== undefined && !/^[a-fA-F0-9]{64}$/.test(expectHash)) {
|
|
3410
|
+
throw new UsageError("--expect-hash must be a 64-character SHA-256 hex digest.");
|
|
3411
|
+
}
|
|
3412
|
+
const endpoint = codeEnvEndpoint();
|
|
3413
|
+
const definitionHash = stableHash(definition);
|
|
3414
|
+
const normalizedExpectHash = expectHash?.toLowerCase();
|
|
2756
3415
|
return {
|
|
3416
|
+
exact: false,
|
|
3417
|
+
reason: "Apply PUTs the supplied definition object unchanged; this plan omits that body and reports only its hash.",
|
|
2757
3418
|
method: "PUT",
|
|
2758
|
-
endpoint
|
|
2759
|
-
identifiers: {
|
|
2760
|
-
|
|
3419
|
+
endpoint,
|
|
3420
|
+
identifiers: {
|
|
3421
|
+
lang: codeEnvLang(args[0], entry.usage),
|
|
3422
|
+
name: args[1],
|
|
3423
|
+
definitionHash,
|
|
3424
|
+
...(normalizedExpectHash ? { expectHash: normalizedExpectHash, } : {}),
|
|
3425
|
+
},
|
|
3426
|
+
payload: "<omitted>",
|
|
3427
|
+
...(normalizedExpectHash
|
|
3428
|
+
? {
|
|
3429
|
+
requests: [
|
|
3430
|
+
{ method: "GET", endpoint, purpose: "verify expectHash", },
|
|
3431
|
+
{
|
|
3432
|
+
method: "PUT",
|
|
3433
|
+
endpoint,
|
|
3434
|
+
condition: "hash matched",
|
|
3435
|
+
payload: "<omitted>",
|
|
3436
|
+
redactedFields: ["payload",],
|
|
3437
|
+
},
|
|
3438
|
+
],
|
|
3439
|
+
}
|
|
3440
|
+
: {}),
|
|
2761
3441
|
};
|
|
3442
|
+
}
|
|
2762
3443
|
case "code-env.set-packages": {
|
|
2763
3444
|
const installCorePackages = parseBooleanOption(flags["install-core-packages"], "--install-core-packages");
|
|
2764
|
-
const
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
if (installCorePackages !== undefined) {
|
|
2768
|
-
payload.desc = { installCorePackages, };
|
|
3445
|
+
const expectHash = flags["expect-hash"];
|
|
3446
|
+
if (expectHash !== undefined && !/^[a-fA-F0-9]{64}$/.test(expectHash)) {
|
|
3447
|
+
throw new UsageError("--expect-hash must be a 64-character SHA-256 hex digest.");
|
|
2769
3448
|
}
|
|
3449
|
+
const endpoint = codeEnvEndpoint();
|
|
2770
3450
|
return {
|
|
3451
|
+
exact: false,
|
|
3452
|
+
reason: "Apply GETs the full definition, merges only package fields, then PUTs the full result.",
|
|
2771
3453
|
method: "PUT",
|
|
2772
|
-
endpoint
|
|
2773
|
-
identifiers: { lang: args[0], name: args[1], },
|
|
2774
|
-
payload
|
|
3454
|
+
endpoint,
|
|
3455
|
+
identifiers: { lang: codeEnvLang(args[0], entry.usage), name: args[1], },
|
|
3456
|
+
payload: {
|
|
3457
|
+
packages: codeEnvPackageList(flags),
|
|
3458
|
+
...(installCorePackages !== undefined ? { installCorePackages, } : {}),
|
|
3459
|
+
...(expectHash ? { expectHash: expectHash.toLowerCase(), } : {}),
|
|
3460
|
+
},
|
|
3461
|
+
requests: [
|
|
3462
|
+
{ method: "GET", endpoint, purpose: "read full definition and verify expectHash", },
|
|
3463
|
+
{
|
|
3464
|
+
method: "PUT",
|
|
3465
|
+
endpoint,
|
|
3466
|
+
condition: "definition read and hash matched",
|
|
3467
|
+
payload: "<merged full definition>",
|
|
3468
|
+
},
|
|
3469
|
+
],
|
|
2775
3470
|
};
|
|
2776
3471
|
}
|
|
2777
3472
|
case "code-env.update-packages": {
|
|
@@ -2780,15 +3475,25 @@ export function commandPlanShape(resource, action, args, flags, entry, projectKe
|
|
|
2780
3475
|
: typeof flags["version"] === "string"
|
|
2781
3476
|
? flags["version"]
|
|
2782
3477
|
: undefined;
|
|
3478
|
+
const wait = codeEnvWait(flags);
|
|
2783
3479
|
return {
|
|
2784
3480
|
method: "POST",
|
|
2785
3481
|
endpoint: `${codeEnvEndpoint("/packages")}${querySuffix({
|
|
2786
3482
|
forceRebuildEnv: flags["force-rebuild"] === true,
|
|
2787
3483
|
versionToUpdate,
|
|
2788
|
-
wait
|
|
3484
|
+
wait,
|
|
2789
3485
|
})}`,
|
|
2790
|
-
identifiers: { lang: args[0], name: args[1], },
|
|
2791
|
-
wait
|
|
3486
|
+
identifiers: { lang: codeEnvLang(args[0], entry.usage), name: args[1], },
|
|
3487
|
+
wait,
|
|
3488
|
+
};
|
|
3489
|
+
}
|
|
3490
|
+
case "code-env.update-images": {
|
|
3491
|
+
const wait = codeEnvWait(flags);
|
|
3492
|
+
return {
|
|
3493
|
+
method: "POST",
|
|
3494
|
+
endpoint: `${codeEnvEndpoint("/images")}${querySuffix({ envVersion: flags["env-version"], wait, })}`,
|
|
3495
|
+
identifiers: { lang: codeEnvLang(args[0], entry.usage), name: args[1], },
|
|
3496
|
+
wait,
|
|
2792
3497
|
};
|
|
2793
3498
|
}
|
|
2794
3499
|
case "code-env.set-jupyter": {
|
|
@@ -2796,27 +3501,52 @@ export function commandPlanShape(resource, action, args, flags, entry, projectKe
|
|
|
2796
3501
|
if (active === undefined) {
|
|
2797
3502
|
throw new UsageError("--active is required. Usage: dss code-env set-jupyter <lang> <name> --active true|false");
|
|
2798
3503
|
}
|
|
3504
|
+
const wait = codeEnvWait(flags);
|
|
2799
3505
|
return {
|
|
2800
3506
|
method: "POST",
|
|
2801
|
-
endpoint: `${codeEnvEndpoint("/jupyter")}${querySuffix({ active, wait
|
|
2802
|
-
identifiers: { lang: args[0], name: args[1], },
|
|
2803
|
-
wait
|
|
3507
|
+
endpoint: `${codeEnvEndpoint("/jupyter")}${querySuffix({ active, wait, })}`,
|
|
3508
|
+
identifiers: { lang: codeEnvLang(args[0], entry.usage), name: args[1], },
|
|
3509
|
+
wait,
|
|
2804
3510
|
};
|
|
2805
3511
|
}
|
|
2806
|
-
case "code-env.delete":
|
|
3512
|
+
case "code-env.delete": {
|
|
3513
|
+
const wait = codeEnvWait(flags);
|
|
2807
3514
|
return {
|
|
2808
3515
|
method: "DELETE",
|
|
2809
|
-
endpoint:
|
|
2810
|
-
identifiers: { lang: args[0], name: args[1], },
|
|
2811
|
-
wait
|
|
3516
|
+
endpoint: `${codeEnvEndpoint()}?wait=${wait}`,
|
|
3517
|
+
identifiers: { lang: codeEnvLang(args[0], entry.usage), name: args[1], },
|
|
3518
|
+
wait,
|
|
2812
3519
|
};
|
|
2813
|
-
|
|
3520
|
+
}
|
|
3521
|
+
case "notebook.save-jupyter": {
|
|
3522
|
+
const content = requiredPlanJsonInput(flags, entry.usage);
|
|
3523
|
+
const expectHash = flags["expect-hash"];
|
|
3524
|
+
if (expectHash !== undefined && !/^[a-fA-F0-9]{64}$/.test(expectHash)) {
|
|
3525
|
+
throw new UsageError("Expected notebook hash must be a 64-character SHA-256 hex digest.");
|
|
3526
|
+
}
|
|
3527
|
+
const endpoint = projectEndpoint(`/jupyter-notebooks/${encodeURIComponent(id)}`);
|
|
2814
3528
|
return {
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
3529
|
+
exact: false,
|
|
3530
|
+
reason: "A fresh GET selects POST when absent or PUT when present; a confirming GET supplies the persisted hash.",
|
|
3531
|
+
endpoint,
|
|
3532
|
+
identifiers: {
|
|
3533
|
+
name: id,
|
|
3534
|
+
contentHash: stableHash(content),
|
|
3535
|
+
...(expectHash ? { expectHash: expectHash.toLowerCase(), } : {}),
|
|
3536
|
+
},
|
|
3537
|
+
requests: [
|
|
3538
|
+
{ method: "GET", endpoint, purpose: "resolve create/update and check --expect-hash", },
|
|
3539
|
+
{
|
|
3540
|
+
method: "POST|PUT",
|
|
3541
|
+
endpoint,
|
|
3542
|
+
condition: "POST after not_found; otherwise PUT",
|
|
3543
|
+
payload: "<omitted>",
|
|
3544
|
+
redactedFields: ["payload",],
|
|
3545
|
+
},
|
|
3546
|
+
{ method: "GET", endpoint, purpose: "confirm persisted hash", },
|
|
3547
|
+
],
|
|
2819
3548
|
};
|
|
3549
|
+
}
|
|
2820
3550
|
case "notebook.delete-jupyter":
|
|
2821
3551
|
return {
|
|
2822
3552
|
method: "DELETE",
|
|
@@ -2825,24 +3555,75 @@ export function commandPlanShape(resource, action, args, flags, entry, projectKe
|
|
|
2825
3555
|
};
|
|
2826
3556
|
case "notebook.clear-jupyter-outputs":
|
|
2827
3557
|
return {
|
|
2828
|
-
method: "
|
|
2829
|
-
endpoint: projectEndpoint(`/jupyter-notebooks/${encodeURIComponent(id)}`),
|
|
3558
|
+
method: "DELETE",
|
|
3559
|
+
endpoint: projectEndpoint(`/jupyter-notebooks/${encodeURIComponent(id)}/outputs`),
|
|
2830
3560
|
identifiers: { name: id, },
|
|
2831
|
-
payload: { clearOutputs: true, },
|
|
2832
3561
|
};
|
|
2833
3562
|
case "notebook.unload-jupyter":
|
|
3563
|
+
if (flags["all"] === true) {
|
|
3564
|
+
if (args.length > 0)
|
|
3565
|
+
throw new UsageError(entry.usage);
|
|
3566
|
+
return {
|
|
3567
|
+
exact: false,
|
|
3568
|
+
reason: "DSS has no unload-all endpoint; apply lists active notebooks and sessions, then issues one verified session DELETE per result.",
|
|
3569
|
+
identifiers: { all: true, },
|
|
3570
|
+
requests: [
|
|
3571
|
+
{ method: "GET", endpoint: projectEndpoint("/jupyter-notebooks/?active=true"), },
|
|
3572
|
+
{
|
|
3573
|
+
method: "GET",
|
|
3574
|
+
endpoint: projectEndpoint("/jupyter-notebooks/{name}/sessions"),
|
|
3575
|
+
forEach: "active notebook",
|
|
3576
|
+
},
|
|
3577
|
+
{
|
|
3578
|
+
method: "DELETE",
|
|
3579
|
+
endpoint: projectEndpoint("/jupyter-notebooks/{name}/sessions/{sessionId}"),
|
|
3580
|
+
forEach: "listed session",
|
|
3581
|
+
},
|
|
3582
|
+
],
|
|
3583
|
+
};
|
|
3584
|
+
}
|
|
3585
|
+
requireArgs(args, 2, entry.usage);
|
|
2834
3586
|
return {
|
|
2835
|
-
method: "
|
|
2836
|
-
endpoint: projectEndpoint(`/jupyter-notebooks/${encodeURIComponent(args[0])}/sessions/${encodeURIComponent(args[1])}
|
|
3587
|
+
method: "DELETE",
|
|
3588
|
+
endpoint: projectEndpoint(`/jupyter-notebooks/${encodeURIComponent(args[0])}/sessions/${encodeURIComponent(args[1])}`),
|
|
2837
3589
|
identifiers: { name: args[0], sessionId: args[1], },
|
|
2838
3590
|
};
|
|
2839
|
-
case "notebook.save-sql":
|
|
3591
|
+
case "notebook.save-sql": {
|
|
3592
|
+
const content = requiredPlanJsonInput(flags, entry.usage);
|
|
3593
|
+
const expectHash = flags["expect-hash"];
|
|
3594
|
+
if (expectHash !== undefined && !/^[a-fA-F0-9]{64}$/.test(expectHash)) {
|
|
3595
|
+
throw new UsageError("Expected notebook hash must be a 64-character SHA-256 hex digest.");
|
|
3596
|
+
}
|
|
3597
|
+
const endpoint = projectEndpoint(`/sql-notebooks/${encodeURIComponent(id)}`);
|
|
2840
3598
|
return {
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
3599
|
+
exact: false,
|
|
3600
|
+
reason: "A fresh GET selects collection POST when absent or entity PUT when present; a confirming GET supplies the persisted hash.",
|
|
3601
|
+
endpoint,
|
|
3602
|
+
identifiers: {
|
|
3603
|
+
id,
|
|
3604
|
+
contentHash: stableHash(content),
|
|
3605
|
+
...(expectHash ? { expectHash: expectHash.toLowerCase(), } : {}),
|
|
3606
|
+
},
|
|
3607
|
+
requests: [
|
|
3608
|
+
{ method: "GET", endpoint, purpose: "resolve create/update and check --expect-hash", },
|
|
3609
|
+
{
|
|
3610
|
+
method: "POST",
|
|
3611
|
+
endpoint: projectEndpoint("/sql-notebooks/"),
|
|
3612
|
+
condition: "after not_found",
|
|
3613
|
+
payload: "<omitted; includes id and projectKey>",
|
|
3614
|
+
redactedFields: ["payload",],
|
|
3615
|
+
},
|
|
3616
|
+
{
|
|
3617
|
+
method: "PUT",
|
|
3618
|
+
endpoint,
|
|
3619
|
+
condition: "when present",
|
|
3620
|
+
payload: "<omitted>",
|
|
3621
|
+
redactedFields: ["payload",],
|
|
3622
|
+
},
|
|
3623
|
+
{ method: "GET", endpoint, purpose: "confirm persisted hash", },
|
|
3624
|
+
],
|
|
2845
3625
|
};
|
|
3626
|
+
}
|
|
2846
3627
|
case "notebook.delete-sql":
|
|
2847
3628
|
return {
|
|
2848
3629
|
method: "DELETE",
|
|
@@ -2851,10 +3632,13 @@ export function commandPlanShape(resource, action, args, flags, entry, projectKe
|
|
|
2851
3632
|
};
|
|
2852
3633
|
case "notebook.clear-sql-history":
|
|
2853
3634
|
return {
|
|
2854
|
-
method: "
|
|
2855
|
-
endpoint: projectEndpoint(`/sql-notebooks/${encodeURIComponent(id)}/history`),
|
|
2856
|
-
identifiers: { id,
|
|
2857
|
-
payload: {
|
|
3635
|
+
method: "POST",
|
|
3636
|
+
endpoint: projectEndpoint(`/sql-notebooks/${encodeURIComponent(id)}/history/clear`),
|
|
3637
|
+
identifiers: { id, },
|
|
3638
|
+
payload: {
|
|
3639
|
+
cellId: flags["cell-id"],
|
|
3640
|
+
numRunsToRetain: num(flags["retain"], "--retain"),
|
|
3641
|
+
},
|
|
2858
3642
|
};
|
|
2859
3643
|
case "project.create": {
|
|
2860
3644
|
const settings = jsonInput(flags) ?? null;
|
|
@@ -2888,7 +3672,7 @@ export function commandPlanShape(resource, action, args, flags, entry, projectKe
|
|
|
2888
3672
|
wait: true,
|
|
2889
3673
|
})}`;
|
|
2890
3674
|
const guarded = flags["if-exists"] === true
|
|
2891
|
-
|| flags
|
|
3675
|
+
|| executionMode(flags).dryRun
|
|
2892
3676
|
|| expectedProjectIncarnation !== undefined;
|
|
2893
3677
|
if (!guarded) {
|
|
2894
3678
|
return {
|
|
@@ -2905,7 +3689,7 @@ export function commandPlanShape(resource, action, args, flags, entry, projectKe
|
|
|
2905
3689
|
provided: true,
|
|
2906
3690
|
expectedHash: expectedProjectIncarnation,
|
|
2907
3691
|
};
|
|
2908
|
-
if (flags
|
|
3692
|
+
if (executionMode(flags).dryRun) {
|
|
2909
3693
|
return {
|
|
2910
3694
|
method: "GET",
|
|
2911
3695
|
endpoint: projectProbe,
|
|
@@ -3225,7 +4009,7 @@ export function commandPlanShape(resource, action, args, flags, entry, projectKe
|
|
|
3225
4009
|
};
|
|
3226
4010
|
}
|
|
3227
4011
|
case "project-git.set-library": {
|
|
3228
|
-
const targetPath = id;
|
|
4012
|
+
const targetPath = validateGitReferencePath(id);
|
|
3229
4013
|
return {
|
|
3230
4014
|
method: "PUT",
|
|
3231
4015
|
endpoint: projectGitEndpoint(projectKey, `/lib-git-refs/${encodeGitReferencePath(targetPath)}`),
|
|
@@ -3240,7 +4024,7 @@ export function commandPlanShape(resource, action, args, flags, entry, projectKe
|
|
|
3240
4024
|
};
|
|
3241
4025
|
}
|
|
3242
4026
|
case "project-git.remove-library": {
|
|
3243
|
-
const targetPath = id;
|
|
4027
|
+
const targetPath = validateGitReferencePath(id);
|
|
3244
4028
|
return {
|
|
3245
4029
|
method: "DELETE",
|
|
3246
4030
|
endpoint: projectGitEndpoint(projectKey, `/lib-git-refs/${encodeGitReferencePath(targetPath)}${querySuffix({
|
|
@@ -3250,7 +4034,7 @@ export function commandPlanShape(resource, action, args, flags, entry, projectKe
|
|
|
3250
4034
|
};
|
|
3251
4035
|
}
|
|
3252
4036
|
case "project-git.reset-library": {
|
|
3253
|
-
const targetPath = id;
|
|
4037
|
+
const targetPath = validateGitReferencePath(id);
|
|
3254
4038
|
return {
|
|
3255
4039
|
method: "POST",
|
|
3256
4040
|
endpoint: projectGitEndpoint(projectKey, "/lib-git-refs/action/reset"),
|
|
@@ -3260,7 +4044,7 @@ export function commandPlanShape(resource, action, args, flags, entry, projectKe
|
|
|
3260
4044
|
};
|
|
3261
4045
|
}
|
|
3262
4046
|
case "project-git.push-library": {
|
|
3263
|
-
const targetPath = id;
|
|
4047
|
+
const targetPath = validateGitReferencePath(id);
|
|
3264
4048
|
const message = requiredPlanFlag(flags, "message", entry.usage);
|
|
3265
4049
|
return {
|
|
3266
4050
|
method: "POST",
|
|
@@ -3294,12 +4078,9 @@ export function commandPlanShape(resource, action, args, flags, entry, projectKe
|
|
|
3294
4078
|
};
|
|
3295
4079
|
default:
|
|
3296
4080
|
return {
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
? projectEndpoint(`/${resource}s/${id ? encodeURIComponent(id) : ""}`)
|
|
3300
|
-
: undefined,
|
|
4081
|
+
exact: false,
|
|
4082
|
+
reason: `No exact offline request shape is defined for ${resource}.${action}; no endpoint was guessed.`,
|
|
3301
4083
|
identifiers: id ? { id, } : undefined,
|
|
3302
|
-
payload: jsonInput(flags),
|
|
3303
4084
|
};
|
|
3304
4085
|
}
|
|
3305
4086
|
}
|
|
@@ -3317,7 +4098,7 @@ export function buildMutationPlan(resource, action, meta, args, flags) {
|
|
|
3317
4098
|
asyncKind: entry.async,
|
|
3318
4099
|
exitCodesOnFailure: exitCodesOnFailure(entry),
|
|
3319
4100
|
idempotency: entry.idempotency,
|
|
3320
|
-
plannedAndDryRun: flags
|
|
4101
|
+
plannedAndDryRun: executionMode(flags).dryRun,
|
|
3321
4102
|
});
|
|
3322
4103
|
}
|
|
3323
4104
|
/**
|
|
@@ -3333,7 +4114,7 @@ export const BATCH_PLAN_EXIT_CODES = {
|
|
|
3333
4114
|
assertionFailure: 4,
|
|
3334
4115
|
};
|
|
3335
4116
|
export const BATCH_USAGE = "dss batch (--data JSON|--data-file PATH|--stdin) [--continue-on-error] [--dry-run]";
|
|
3336
|
-
const BATCH_DESCRIPTION = "Run
|
|
4117
|
+
const BATCH_DESCRIPTION = "Run dss argv arrays fail-fast by default. The result aggregates failed/retryable/failureCodes; process exit remains the first failed step's exit code.";
|
|
3337
4118
|
export const BATCH_HINT = 'Pass a JSON array of argv arrays, e.g. [["dataset","list"],["recipe","update","r","--data-file","p.json"]].';
|
|
3338
4119
|
export const BATCH_EXAMPLE_PAYLOAD = [
|
|
3339
4120
|
["recipe", "set-payload", "compute_orders", "--file", "code.py", "--no-backup",],
|