dataiku-sdk 2.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/LICENSE +107 -17
  2. package/README.md +144 -17
  3. package/dist/build-metadata.json +1 -1
  4. package/dist/packages/types/src/index.d.ts +39 -4
  5. package/dist/packages/types/src/index.js +31 -2
  6. package/dist/src/cli/commands/api-service.js +62 -16
  7. package/dist/src/cli/commands/bundle.js +49 -15
  8. package/dist/src/cli/commands/code-env.js +210 -49
  9. package/dist/src/cli/commands/code.d.ts +19 -0
  10. package/dist/src/cli/commands/code.js +87 -15
  11. package/dist/src/cli/commands/dataset.js +8 -3
  12. package/dist/src/cli/commands/flow-zone.js +33 -5
  13. package/dist/src/cli/commands/notebook.js +72 -41
  14. package/dist/src/cli/commands/project-git.js +8 -5
  15. package/dist/src/cli/commands/project-library.d.ts +21 -0
  16. package/dist/src/cli/commands/project-library.js +121 -50
  17. package/dist/src/cli/commands/project.js +16 -2
  18. package/dist/src/cli/commands/recipe.js +37 -12
  19. package/dist/src/cli/commands/sql.d.ts +10 -0
  20. package/dist/src/cli/commands/sql.js +39 -17
  21. package/dist/src/cli/commands/webapp.js +67 -13
  22. package/dist/src/cli/contract.d.ts +15 -0
  23. package/dist/src/cli/contract.js +870 -107
  24. package/dist/src/cli/env.d.ts +9 -0
  25. package/dist/src/cli/env.js +20 -2
  26. package/dist/src/cli/flags.js +9 -0
  27. package/dist/src/cli/helpers/cleanup.js +104 -3
  28. package/dist/src/cli/helpers/flow-zone.d.ts +3 -0
  29. package/dist/src/cli/helpers/flow-zone.js +33 -3
  30. package/dist/src/cli/helpers/recipe.d.ts +20 -0
  31. package/dist/src/cli/helpers/recipe.js +158 -3
  32. package/dist/src/cli/output.d.ts +2 -0
  33. package/dist/src/cli/output.js +33 -6
  34. package/dist/src/cli/runtime.d.ts +35 -1
  35. package/dist/src/cli/runtime.js +125 -18
  36. package/dist/src/cli/types.d.ts +7 -0
  37. package/dist/src/cli.js +135 -28
  38. package/dist/src/client.d.ts +60 -0
  39. package/dist/src/client.js +237 -42
  40. package/dist/src/errors.d.ts +8 -2
  41. package/dist/src/errors.js +40 -0
  42. package/dist/src/index.d.ts +4 -3
  43. package/dist/src/index.js +2 -1
  44. package/dist/src/resources/api-services.d.ts +48 -6
  45. package/dist/src/resources/api-services.js +54 -8
  46. package/dist/src/resources/bundles.d.ts +51 -6
  47. package/dist/src/resources/bundles.js +39 -9
  48. package/dist/src/resources/code-envs.d.ts +25 -3
  49. package/dist/src/resources/code-envs.js +104 -2
  50. package/dist/src/resources/datasets.d.ts +20 -0
  51. package/dist/src/resources/datasets.js +232 -52
  52. package/dist/src/resources/jobs.d.ts +35 -10
  53. package/dist/src/resources/jobs.js +92 -17
  54. package/dist/src/resources/notebooks.d.ts +77 -7
  55. package/dist/src/resources/notebooks.js +143 -19
  56. package/dist/src/resources/project-git.d.ts +12 -0
  57. package/dist/src/resources/project-git.js +39 -8
  58. package/dist/src/resources/project-library.d.ts +122 -7
  59. package/dist/src/resources/project-library.js +494 -25
  60. package/dist/src/resources/projects.d.ts +5 -2
  61. package/dist/src/resources/projects.js +18 -2
  62. package/dist/src/resources/scenarios.d.ts +30 -0
  63. package/dist/src/resources/scenarios.js +73 -27
  64. package/dist/src/resources/sql.d.ts +6 -0
  65. package/dist/src/resources/sql.js +22 -2
  66. package/dist/src/resources/webapps.d.ts +35 -4
  67. package/dist/src/resources/webapps.js +54 -5
  68. package/dist/src/schemas.d.ts +2 -2
  69. package/dist/src/schemas.js +1 -1
  70. package/dist/src/skill.d.ts +9 -0
  71. package/dist/src/skill.js +37 -4
  72. package/dist/src/utils/flow-analysis.d.ts +53 -0
  73. package/dist/src/utils/flow-analysis.js +382 -0
  74. package/dist/src/utils/project-archive.d.ts +41 -2
  75. package/dist/src/utils/project-archive.js +159 -16
  76. package/package.json +5 -5
  77. package/packages/types/dist/index.d.ts +39 -4
  78. package/packages/types/dist/index.js +31 -2
  79. package/plugin.json +2 -2
  80. package/skills/dataiku-dss/SKILL.md +75 -48
@@ -1,3 +1,4 @@
1
+ import { json, parseBooleanOption, } from "../coerce.js";
1
2
  import { requireArgs, UsageError, } from "../usage.js";
2
3
  export const bundleCommands = {
3
4
  "list-exported": {
@@ -8,13 +9,24 @@ export const bundleCommands = {
8
9
  },
9
10
  export: {
10
11
  handler: async (c, a, f) => {
11
- requireArgs(a, 1, "dss bundle export <bundleId> [--project-key KEY]");
12
- await c.bundles.exportBundle(a[0], f["project-key"]);
12
+ const usage = "dss bundle export <bundleId> [--release-notes TEXT] [--evaluate-standards-checks true|false] [--project-key KEY]";
13
+ requireArgs(a, 1, usage);
14
+ await c.bundles.exportBundle(a[0], f["project-key"], {
15
+ ...(typeof f["release-notes"] === "string" ? { releaseNotes: f["release-notes"], } : {}),
16
+ ...(f["evaluate-standards-checks"] !== undefined
17
+ ? {
18
+ evaluateProjectStandardsChecks: parseBooleanOption(f["evaluate-standards-checks"], "--evaluate-standards-checks") ?? true,
19
+ }
20
+ : {}),
21
+ });
13
22
  return { exported: a[0], };
14
23
  },
15
- usage: "dss bundle export <bundleId> [--project-key KEY]",
16
- description: "Create (or overwrite) an exported Design-node bundle.",
17
- examples: ["dss bundle export v1",],
24
+ usage: "dss bundle export <bundleId> [--release-notes TEXT] [--evaluate-standards-checks true|false] [--project-key KEY]",
25
+ description: "Create (or overwrite) an exported Design-node bundle. --release-notes forwards the documented releaseNotes parameter; --evaluate-standards-checks toggles the documented Project Standards Checks evaluation (default true).",
26
+ examples: [
27
+ "dss bundle export v1",
28
+ "dss bundle export v1 --release-notes='Adds churn model' --evaluate-standards-checks=false",
29
+ ],
18
30
  },
19
31
  "delete-exported": {
20
32
  handler: async (c, a, f) => {
@@ -45,12 +57,18 @@ export const bundleCommands = {
45
57
  },
46
58
  publish: {
47
59
  handler: (c, a, f) => {
48
- requireArgs(a, 1, "dss bundle publish <bundleId> [--project-key KEY]");
49
- return c.bundles.publish(a[0], f["project-key"]);
60
+ const usage = "dss bundle publish <bundleId> [--published-project-key KEY] [--project-key KEY]";
61
+ requireArgs(a, 1, usage);
62
+ return c.bundles.publish(a[0], f["project-key"], typeof f["published-project-key"] === "string"
63
+ ? { publishedProjectKey: f["published-project-key"], }
64
+ : {});
50
65
  },
51
- usage: "dss bundle publish <bundleId> [--project-key KEY]",
52
- description: "Publish a Design-node bundle to the Project Deployer.",
53
- examples: ["dss bundle publish v1",],
66
+ usage: "dss bundle publish <bundleId> [--published-project-key KEY] [--project-key KEY]",
67
+ description: "Publish a Design-node bundle to the Project Deployer; --published-project-key forwards the documented publishedProjectKey query parameter (a new published project is created when no match exists; the source project's key is the server-side default).",
68
+ examples: [
69
+ "dss bundle publish v1",
70
+ "dss bundle publish v1 --published-project-key=PROD-CHURN",
71
+ ],
54
72
  },
55
73
  "list-imported": {
56
74
  handler: (c, _a, f) => c.bundles.listImported(f["project-key"]),
@@ -79,12 +97,28 @@ export const bundleCommands = {
79
97
  },
80
98
  activate: {
81
99
  handler: (c, a, f) => {
82
- requireArgs(a, 1, "dss bundle activate <bundleId> [--project-key KEY]");
83
- return c.bundles.activate(a[0], f["project-key"]);
100
+ const usage = "dss bundle activate <bundleId> [--scenarios JSON] [--project-key KEY]";
101
+ requireArgs(a, 1, usage);
102
+ const rawScenarios = f["scenarios"];
103
+ let scenariosToEnable;
104
+ if (rawScenarios !== undefined && rawScenarios !== false) {
105
+ const parsed = json(rawScenarios);
106
+ if (typeof parsed !== "object"
107
+ || parsed === null
108
+ || Array.isArray(parsed)
109
+ || !Object.values(parsed).every((value) => typeof value === "boolean")) {
110
+ throw new UsageError("--scenarios must be a JSON object mapping scenario IDs to true|false. Usage: dss bundle activate <bundleId> --scenarios '{\"daily_build\":true}'");
111
+ }
112
+ scenariosToEnable = parsed;
113
+ }
114
+ return c.bundles.activate(a[0], f["project-key"], scenariosToEnable !== undefined ? { scenariosToEnable, } : {});
84
115
  },
85
- usage: "dss bundle activate <bundleId> [--project-key KEY]",
86
- description: "Activate an imported Automation-node bundle.",
87
- examples: ["dss bundle activate v1",],
116
+ usage: "dss bundle activate <bundleId> [--scenarios JSON] [--project-key KEY]",
117
+ description: "Activate an imported Automation-node bundle; --scenarios forwards the documented scenario-ID-to-enabled dict as the scenariosActiveOnActivation body.",
118
+ examples: [
119
+ "dss bundle activate v1",
120
+ 'dss bundle activate v1 --scenarios=\'{"daily_build":true,"hourly_retrain":false}\'',
121
+ ],
88
122
  },
89
123
  preload: {
90
124
  handler: (c, a, f) => {
@@ -1,7 +1,33 @@
1
- import { readFileSync, } from "node:fs";
2
- import { json, jsonInput, parseBooleanOption, } from "../coerce.js";
3
- import { isNotFoundError, readIfExists, skipResult, } from "../output.js";
1
+ import { readFileSync, writeFileSync, } from "node:fs";
2
+ import { ClientValidationError, } from "../../errors.js";
3
+ import { stableHash, } from "../../utils/stable-hash.js";
4
+ import { json, jsonInput, num, numFlag, parseBooleanOption, } from "../coerce.js";
5
+ import { enqueueCliWarning, isNotFoundError, readIfExists, skipResult, } from "../output.js";
4
6
  import { requireArgs, UsageError, } from "../usage.js";
7
+ const CODE_ENV_LANGS = ["PYTHON", "R",];
8
+ /** Validate a positional `<lang>` argument: required, must be PYTHON or R. */
9
+ function requireEnvLang(value, usage) {
10
+ if (value !== "PYTHON" && value !== "R") {
11
+ throw new UsageError(`env language must be one of ${CODE_ENV_LANGS.join(", ")}. Usage: ${usage}`, "invalid_enum", undefined, { value, allowed: CODE_ENV_LANGS, });
12
+ }
13
+ return value;
14
+ }
15
+ function definitionHashMismatch(envLang, envName, expected, current) {
16
+ return new ClientValidationError(`Code env ${envLang}/${envName} changed since the expected definition hash was captured; refusing to overwrite it.`, "validation_failed", "Re-read the definition with dss code-env get-definition (definitionHash comes from code-env get), review the diff, and retry with the fresh hash.", {
17
+ envLang,
18
+ envName,
19
+ expectedDefinitionHash: expected,
20
+ ...(current !== undefined ? { currentDefinitionHash: current, } : {}),
21
+ });
22
+ }
23
+ function validateExpectHash(value) {
24
+ if (value === undefined || value === false)
25
+ return undefined;
26
+ if (typeof value !== "string" || !/^[0-9a-fA-F]{64}$/.test(value)) {
27
+ throw new ClientValidationError("Expected code env definition hash must be a 64-character SHA-256 hex digest.", "validation_failed", "Use the definitionHash value returned by dss code-env get.");
28
+ }
29
+ return value;
30
+ }
5
31
  function codeEnvWait(flags) {
6
32
  return flags["no-wait"] !== true;
7
33
  }
@@ -33,34 +59,116 @@ function codeEnvPackageList(flags) {
33
59
  }
34
60
  export const codeEnvCommands = {
35
61
  list: {
36
- handler: (c, _a, f) => c.codeEnvs.list({
37
- envLang: f["lang"],
38
- }),
39
- usage: "dss code-env list [--lang LANG]",
40
- description: "List code environments.",
62
+ handler: (c, _a, f) => {
63
+ const usage = "dss code-env list [--lang PYTHON|R]";
64
+ const lang = f["lang"];
65
+ return c.codeEnvs.list({
66
+ envLang: typeof lang === "string"
67
+ ? requireEnvLang(lang, usage)
68
+ : undefined,
69
+ });
70
+ },
71
+ usage: "dss code-env list [--lang PYTHON|R]",
72
+ description: "List code environments, optionally filtered to one language.",
41
73
  examples: ["dss code-env list", "dss code-env list --lang PYTHON",],
42
74
  },
43
75
  get: {
44
76
  handler: (c, a) => {
45
- requireArgs(a, 2, "dss code-env get <lang> <name>");
46
- return c.codeEnvs.get(a[0], a[1]);
77
+ const usage = "dss code-env get <lang> <name>";
78
+ requireArgs(a, 2, usage);
79
+ const envLang = requireEnvLang(a[0], usage);
80
+ return c.codeEnvs.get(envLang, a[1]);
47
81
  },
48
82
  usage: "dss code-env get <lang> <name>",
49
- description: "Get code environment details.",
83
+ description: "Get code environment details: requested vs installed packages, Python interpreter, deployment mode, and the stable definition hash (definitionHash) used by set-definition --expect-hash.",
50
84
  examples: ["dss code-env get PYTHON my_env",],
51
85
  },
52
86
  "get-definition": {
53
87
  handler: (c, a) => {
54
- requireArgs(a, 2, "dss code-env get-definition <lang> <name>");
55
- return c.codeEnvs.getDefinition(a[0], a[1]);
88
+ const usage = "dss code-env get-definition <lang> <name>";
89
+ requireArgs(a, 2, usage);
90
+ const envLang = requireEnvLang(a[0], usage);
91
+ return c.codeEnvs.getDefinition(envLang, a[1]);
56
92
  },
57
93
  usage: "dss code-env get-definition <lang> <name>",
58
- description: "Get raw code environment definition.",
94
+ description: "Get the raw code environment definition exactly as DSS stores it; capture its hash (definitionHash from code-env get) before replacing it with set-definition --expect-hash.",
59
95
  examples: ["dss code-env get-definition PYTHON my_env",],
60
96
  },
97
+ "list-logs": {
98
+ handler: (c, a) => {
99
+ const usage = "dss code-env list-logs <lang> <name>";
100
+ requireArgs(a, 2, usage);
101
+ const envLang = requireEnvLang(a[0], usage);
102
+ return c.codeEnvs.listLogs(envLang, a[1]);
103
+ },
104
+ usage: "dss code-env list-logs <lang> <name>",
105
+ description: "List the build log files DSS keeps for a code environment.",
106
+ examples: ["dss code-env list-logs PYTHON my_env",],
107
+ },
108
+ "get-log": {
109
+ handler: async (c, a, f) => {
110
+ const usage = "dss code-env get-log <lang> <name> <logName> [--max-lines N|--max-log-lines N] [--max-log-bytes N] [--output PATH]";
111
+ requireArgs(a, 3, usage);
112
+ const envLang = requireEnvLang(a[0], usage);
113
+ const maxLines = numFlag(f, ["max-lines", "max-log-lines",]);
114
+ const maxBytes = num(f["max-log-bytes"], "--max-log-bytes");
115
+ const result = await c.codeEnvs.getLog(envLang, a[1], a[2], {
116
+ ...(maxLines !== undefined ? { maxLines, } : {}),
117
+ ...(maxBytes !== undefined ? { maxBytes, } : {}),
118
+ });
119
+ const output = f["output"];
120
+ if (typeof output === "string" && output.trim().length > 0) {
121
+ writeFileSync(output, result.log, "utf-8");
122
+ if (result.truncated || result.tailed) {
123
+ const limits = [
124
+ result.tailed ? `tail limited to ${maxLines ?? 500} lines` : undefined,
125
+ result.truncated ? "byte cap reached" : undefined,
126
+ ].filter((part) => part !== undefined);
127
+ enqueueCliWarning({
128
+ code: "code_env_log_truncated",
129
+ message: `Code env ${envLang}/${a[1]} log '${a[2]}' was truncated (${limits.join("; ")},). Pass --max-log-bytes 0 and --max-lines 0 for the full log, or refetch with higher limits.`,
130
+ envLang,
131
+ envName: a[1],
132
+ logName: a[2],
133
+ truncated: result.truncated,
134
+ tailed: result.tailed,
135
+ });
136
+ }
137
+ return {
138
+ path: output,
139
+ bytes: result.bytes,
140
+ truncated: result.truncated,
141
+ tailed: result.tailed,
142
+ envLang,
143
+ envName: a[1],
144
+ logName: a[2],
145
+ };
146
+ }
147
+ return { ...result, envLang, envName: a[1], logName: a[2], };
148
+ },
149
+ usage: "dss code-env get-log <lang> <name> <logName> [--max-lines N|--max-log-lines N] [--max-log-bytes N] [--output PATH]",
150
+ description: "Fetch one code-env build log, bounded for safe output: the last --max-lines lines (default 500, 0 for all) and at most --max-log-bytes bytes (default 10 MiB, 0 for all). --output PATH writes the kept content to a file; stdout then carries the path metadata. A truncation warning names which cap hit.",
151
+ examples: [
152
+ "dss code-env get-log PYTHON my_env install.log --max-lines 200",
153
+ "dss code-env get-log PYTHON my_env install.log --output ./install.log --max-log-bytes 0",
154
+ ],
155
+ },
156
+ version: {
157
+ handler: (c, a) => {
158
+ const usage = "dss code-env version <lang> <name> <projectKey>";
159
+ requireArgs(a, 3, usage);
160
+ const envLang = requireEnvLang(a[0], usage);
161
+ return c.codeEnvs.getVersionForProject(envLang, a[1], a[2]);
162
+ },
163
+ usage: "dss code-env version <lang> <name> <projectKey>",
164
+ description: "Resolve the code environment version a project uses (versioned automation environments); empty version for unversioned environments.",
165
+ examples: ["dss code-env version PYTHON my_env MY_PROJ",],
166
+ },
61
167
  create: {
62
168
  handler: async (c, a, f) => {
63
- requireArgs(a, 2, "dss code-env create <lang> <name> --deployment-mode MODE");
169
+ const usage = "dss code-env create <lang> <name> --deployment-mode MODE";
170
+ requireArgs(a, 2, usage);
171
+ const envLang = requireEnvLang(a[0], usage);
64
172
  const deploymentMode = f["deployment-mode"];
65
173
  if (!deploymentMode) {
66
174
  throw new UsageError("--deployment-mode is required. Usage: dss code-env create <lang> <name> --deployment-mode MODE");
@@ -68,38 +176,38 @@ export const codeEnvCommands = {
68
176
  const params = codeEnvParams(f);
69
177
  const wait = codeEnvWait(f);
70
178
  if (f["if-not-exists"] === true || f["dry-run"] === true) {
71
- const existing = (await c.codeEnvs.list({ envLang: a[0], }))
179
+ const existing = (await c.codeEnvs.list({ envLang, }))
72
180
  .find((env) => env.envName === a[1]);
73
181
  if (existing && f["if-not-exists"] === true && f["dry-run"] !== true) {
74
- return skipResult("code-env", a[1], "exists", { envLang: a[0], current: existing, });
182
+ return skipResult("code-env", a[1], "exists", { envLang, current: existing, });
75
183
  }
76
184
  if (f["dry-run"] === true) {
77
185
  return {
78
186
  dryRun: true,
79
187
  action: "create",
80
188
  resource: "code-env",
81
- envLang: a[0],
189
+ envLang,
82
190
  envName: a[1],
83
191
  payload: {
84
192
  deploymentMode,
85
193
  params,
86
- wait,
87
194
  },
195
+ wait,
88
196
  ...(existing ? { current: existing, } : {}),
89
197
  };
90
198
  }
91
199
  }
92
200
  const created = await c.codeEnvs.create({
93
- envLang: a[0],
201
+ envLang,
94
202
  envName: a[1],
95
203
  deploymentMode,
96
204
  params,
97
205
  wait,
98
206
  });
99
- return { created: a[1], resource: "code-env", envLang: a[0], ...created, };
207
+ return { created: a[1], resource: "code-env", envLang, ...created, };
100
208
  },
101
209
  usage: "dss code-env create <lang> <name> --deployment-mode MODE [--params JSON|--data JSON|--data-file PATH|--stdin] [--python-interpreter PYTHON311] [--no-wait] [--if-not-exists] [--dry-run]",
102
- description: "Create a code environment.",
210
+ description: "Create a code environment; --no-wait hands back a DSS future payload you can settle with dss future wait.",
103
211
  examples: [
104
212
  "dss code-env create PYTHON my_env --deployment-mode DESIGN_MANAGED --python-interpreter PYTHON311",
105
213
  'dss code-env create PYTHON my_env --deployment-mode DESIGN_MANAGED --params \'{"pythonInterpreter":"PYTHON311"}\' --dry-run',
@@ -107,47 +215,67 @@ export const codeEnvCommands = {
107
215
  },
108
216
  "set-definition": {
109
217
  handler: async (c, a, f) => {
110
- requireArgs(a, 2, "dss code-env set-definition <lang> <name> --data JSON");
218
+ const usage = "dss code-env set-definition <lang> <name> (--data JSON|--data-file PATH|--stdin) [--expect-hash SHA256]";
219
+ requireArgs(a, 2, usage);
220
+ const envLang = requireEnvLang(a[0], usage);
111
221
  const definition = jsonInput(f);
112
222
  if (!definition) {
113
223
  throw new UsageError("--data, --data-file, or --stdin is required. Usage: dss code-env set-definition <lang> <name> --data JSON");
114
224
  }
225
+ const expectHash = validateExpectHash(f["expect-hash"]);
226
+ const definitionHash = stableHash(definition);
115
227
  if (f["dry-run"] === true) {
228
+ const current = await readIfExists(() => c.codeEnvs.getDefinition(envLang, a[1]));
229
+ const currentHash = current ? stableHash(current) : undefined;
230
+ if (expectHash !== undefined && currentHash !== expectHash) {
231
+ throw definitionHashMismatch(envLang, a[1], expectHash, currentHash);
232
+ }
116
233
  return {
117
234
  dryRun: true,
118
235
  action: "set-definition",
119
236
  resource: "code-env",
120
- envLang: a[0],
237
+ envLang,
121
238
  envName: a[1],
122
239
  definition,
240
+ definitionHash,
241
+ ...(currentHash !== undefined
242
+ ? { currentDefinitionHash: currentHash, changed: currentHash !== definitionHash, }
243
+ : {}),
244
+ ...(expectHash !== undefined ? { expectHash, provenanceVerified: true, } : {}),
123
245
  };
124
246
  }
125
- return c.codeEnvs.setDefinition(a[0], a[1], definition);
247
+ return c.codeEnvs.setDefinition(envLang, a[1], definition, { expectHash, });
126
248
  },
127
- usage: "dss code-env set-definition <lang> <name> (--data JSON|--data-file PATH|--stdin) [--dry-run]",
128
- description: "Replace a code environment definition previously fetched from DSS.",
129
- examples: ["dss code-env set-definition PYTHON my_env --data-file code-env.json --dry-run",],
249
+ usage: "dss code-env set-definition <lang> <name> (--data JSON|--data-file PATH|--stdin) [--expect-hash SHA256] [--dry-run]",
250
+ description: "Replace a code environment definition previously fetched from DSS (get-definition). --expect-hash SHA256 refuses the PUT unless the current definition still hashes to the hash captured with code-env get, so concurrent edits are never clobbered; --dry-run also fetches the current definition and reports both hashes plus a changed flag.",
251
+ examples: [
252
+ "dss code-env set-definition PYTHON my_env --data-file code-env.json --expect-hash $HASH --dry-run",
253
+ ],
130
254
  },
131
255
  "set-packages": {
132
256
  handler: async (c, a, f) => {
133
- requireArgs(a, 2, "dss code-env set-packages <lang> <name> --packages PKGS");
257
+ const usage = "dss code-env set-packages <lang> <name> (--packages PKGS|--package PKG|--file PATH)";
258
+ requireArgs(a, 2, usage);
259
+ const envLang = requireEnvLang(a[0], usage);
134
260
  const packages = codeEnvPackageList(f);
135
261
  const installCorePackages = parseBooleanOption(f["install-core-packages"], "--install-core-packages");
262
+ const expectHash = validateExpectHash(f["expect-hash"]);
136
263
  if (f["dry-run"] === true) {
137
264
  return {
138
265
  dryRun: true,
139
266
  action: "set-packages",
140
267
  resource: "code-env",
141
- envLang: a[0],
268
+ envLang,
142
269
  envName: a[1],
143
270
  packages,
144
271
  installCorePackages,
272
+ ...(expectHash !== undefined ? { expectHash, } : {}),
145
273
  };
146
274
  }
147
- return c.codeEnvs.setPackages(a[0], a[1], packages, { installCorePackages, });
275
+ return c.codeEnvs.setPackages(envLang, a[1], packages, { installCorePackages, expectHash, });
148
276
  },
149
- usage: "dss code-env set-packages <lang> <name> (--packages PKGS|--package PKG|--file PATH) [--install-core-packages true|false] [--dry-run]",
150
- description: "Update requested package specs without rebuilding packages.",
277
+ usage: "dss code-env set-packages <lang> <name> (--packages PKGS|--package PKG|--file PATH) [--install-core-packages true|false] [--expect-hash SHA256] [--dry-run]",
278
+ description: "Fetch the current definition, merge the requested package specs (and --install-core-packages) into it, then PUT the merged definition, so fields outside the package list are never dropped; --expect-hash refuses the merge when DSS changed since the hash was captured.",
151
279
  examples: [
152
280
  "dss code-env set-packages PYTHON my_env --packages 'tabulate\\nnameparser' --dry-run",
153
281
  "dss code-env set-packages PYTHON my_env --file requirements.txt",
@@ -155,7 +283,9 @@ export const codeEnvCommands = {
155
283
  },
156
284
  "update-packages": {
157
285
  handler: async (c, a, f) => {
158
- requireArgs(a, 2, "dss code-env update-packages <lang> <name>");
286
+ const usage = "dss code-env update-packages <lang> <name>";
287
+ requireArgs(a, 2, usage);
288
+ const envLang = requireEnvLang(a[0], usage);
159
289
  const wait = codeEnvWait(f);
160
290
  const versionToUpdate = typeof f["env-version"] === "string"
161
291
  ? f["env-version"]
@@ -172,20 +302,49 @@ export const codeEnvCommands = {
172
302
  dryRun: true,
173
303
  action: "update-packages",
174
304
  resource: "code-env",
175
- envLang: a[0],
305
+ envLang,
176
306
  envName: a[1],
177
307
  ...opts,
178
308
  };
179
309
  }
180
- return c.codeEnvs.updatePackages(a[0], a[1], opts);
310
+ return c.codeEnvs.updatePackages(envLang, a[1], opts);
181
311
  },
182
312
  usage: "dss code-env update-packages <lang> <name> [--force-rebuild] [--env-version VERSION] [--no-wait] [--dry-run]",
183
- description: "Rebuild or update code environment packages to match the requested specs.",
313
+ description: "Rebuild or update code environment packages to match the requested specs; --no-wait hands back a DSS future payload you can settle with dss future wait.",
184
314
  examples: ["dss code-env update-packages PYTHON my_env --force-rebuild --dry-run",],
185
315
  },
316
+ "update-images": {
317
+ handler: async (c, a, f) => {
318
+ const usage = "dss code-env update-images <lang> <name>";
319
+ requireArgs(a, 2, usage);
320
+ const envLang = requireEnvLang(a[0], usage);
321
+ const wait = codeEnvWait(f);
322
+ const envVersion = typeof f["env-version"] === "string" ? f["env-version"] : undefined;
323
+ if (f["dry-run"] === true) {
324
+ return {
325
+ dryRun: true,
326
+ action: "update-images",
327
+ resource: "code-env",
328
+ envLang,
329
+ envName: a[1],
330
+ envVersion,
331
+ wait,
332
+ };
333
+ }
334
+ return c.codeEnvs.updateImages(envLang, a[1], { envVersion, wait, });
335
+ },
336
+ usage: "dss code-env update-images <lang> <name> [--env-version VERSION] [--no-wait] [--dry-run]",
337
+ description: "Rebuild the Docker image(s) of a code environment to match its settings; --env-version targets one version of a versioned environment and --no-wait hands back a DSS future payload you can settle with dss future wait.",
338
+ examples: [
339
+ "dss code-env update-images PYTHON my_env --dry-run",
340
+ "dss code-env update-images PYTHON my_env --env-version v3 --no-wait",
341
+ ],
342
+ },
186
343
  "set-jupyter": {
187
344
  handler: async (c, a, f) => {
188
- requireArgs(a, 2, "dss code-env set-jupyter <lang> <name> --active true|false");
345
+ const usage = "dss code-env set-jupyter <lang> <name> --active true|false";
346
+ requireArgs(a, 2, usage);
347
+ const envLang = requireEnvLang(a[0], usage);
189
348
  const active = parseBooleanOption(f["active"], "--active");
190
349
  if (active === undefined) {
191
350
  throw new UsageError("--active is required. Usage: dss code-env set-jupyter <lang> <name> --active true|false");
@@ -196,48 +355,50 @@ export const codeEnvCommands = {
196
355
  dryRun: true,
197
356
  action: "set-jupyter",
198
357
  resource: "code-env",
199
- envLang: a[0],
358
+ envLang,
200
359
  envName: a[1],
201
360
  active,
202
361
  wait,
203
362
  };
204
363
  }
205
- return c.codeEnvs.setJupyterSupport(a[0], a[1], active, { wait, });
364
+ return c.codeEnvs.setJupyterSupport(envLang, a[1], active, { wait, });
206
365
  },
207
366
  usage: "dss code-env set-jupyter <lang> <name> --active true|false [--no-wait] [--dry-run]",
208
- description: "Enable or disable Jupyter support for a code environment.",
367
+ description: "Enable or disable Jupyter support for a code environment; --no-wait hands back a DSS future payload you can settle with dss future wait.",
209
368
  examples: ["dss code-env set-jupyter PYTHON my_env --active true --dry-run",],
210
369
  },
211
370
  delete: {
212
371
  handler: async (c, a, f) => {
213
- requireArgs(a, 2, "dss code-env delete <lang> <name>");
372
+ const usage = "dss code-env delete <lang> <name>";
373
+ requireArgs(a, 2, usage);
374
+ const envLang = requireEnvLang(a[0], usage);
214
375
  const wait = codeEnvWait(f);
215
376
  if (f["dry-run"] === true) {
216
- const current = await readIfExists(() => c.codeEnvs.get(a[0], a[1]));
377
+ const current = await readIfExists(() => c.codeEnvs.get(envLang, a[1]));
217
378
  if (!current)
218
- return skipResult("code-env", a[1], "missing", { envLang: a[0], });
379
+ return skipResult("code-env", a[1], "missing", { envLang, });
219
380
  return {
220
381
  dryRun: true,
221
382
  action: "delete",
222
383
  resource: "code-env",
223
- envLang: a[0],
384
+ envLang,
224
385
  envName: a[1],
225
386
  wait,
226
387
  current,
227
388
  };
228
389
  }
229
390
  if (f["if-exists"] === true) {
230
- return await c.codeEnvs.delete(a[0], a[1], { wait, }).catch((error) => {
391
+ return await c.codeEnvs.delete(envLang, a[1], { wait, }).catch((error) => {
231
392
  if (isNotFoundError(error)) {
232
- return skipResult("code-env", a[1], "missing", { envLang: a[0], });
393
+ return skipResult("code-env", a[1], "missing", { envLang, });
233
394
  }
234
395
  throw error;
235
396
  });
236
397
  }
237
- return c.codeEnvs.delete(a[0], a[1], { wait, });
398
+ return c.codeEnvs.delete(envLang, a[1], { wait, });
238
399
  },
239
400
  usage: "dss code-env delete <lang> <name> [--no-wait] [--if-exists] [--dry-run]",
240
- description: "Delete a code environment.",
401
+ description: "Delete a code environment; --no-wait hands back a DSS future payload you can settle with dss future wait.",
241
402
  examples: ["dss code-env delete PYTHON my_env --dry-run",],
242
403
  },
243
404
  usages: {
@@ -1,2 +1,21 @@
1
1
  import type { CommandMeta } from "../types.js";
2
+ export interface CodeInputSource {
3
+ kind: "file" | "stdin";
4
+ path?: string;
5
+ }
6
+ export interface ResolvedCodeInput {
7
+ script: string;
8
+ source: CodeInputSource;
9
+ }
10
+ /**
11
+ * Canonical validation of `code run` input: rejects positional args and
12
+ * conflicting sources, reads the chosen source, strips a UTF-8 BOM, and
13
+ * rejects empty scripts. Returns the script plus source metadata so plan or
14
+ * replay payloads can hash the script and reference the source without
15
+ * embedding its contents.
16
+ */
17
+ export declare function resolveCodeInputWithSource(args: string[], flags: Record<string, string | boolean>): ResolvedCodeInput;
18
+ export declare function resolveCodeInput(args: string[], flags: Record<string, string | boolean>): string;
19
+ /** Parse an integer flag value, rejecting negative and fractional values before any DSS request. */
20
+ export declare function parseCodeRunIntegerFlag(value: string | boolean | undefined, flagName: string): number | undefined;
2
21
  export declare const codeCommands: Record<string, CommandMeta>;