dataiku-sdk 3.9.0 → 4.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 (74) hide show
  1. package/README.md +4 -3
  2. package/dist/build-metadata.json +1 -1
  3. package/dist/packages/types/src/index.d.ts +6 -0
  4. package/dist/packages/types/src/index.js +6 -0
  5. package/dist/src/cli/coerce.d.ts +6 -0
  6. package/dist/src/cli/coerce.js +9 -0
  7. package/dist/src/cli/command-syntax.json +216 -0
  8. package/dist/src/cli/commands/app.js +2 -2
  9. package/dist/src/cli/commands/code-env.js +10 -9
  10. package/dist/src/cli/commands/code.js +16 -2
  11. package/dist/src/cli/commands/dashboard.js +1 -2
  12. package/dist/src/cli/commands/dataset.js +6 -4
  13. package/dist/src/cli/commands/flow-zone.js +1 -1
  14. package/dist/src/cli/commands/job.js +70 -16
  15. package/dist/src/cli/commands/plugin.js +7 -7
  16. package/dist/src/cli/commands/project-library.js +2 -2
  17. package/dist/src/cli/commands/project.js +21 -4
  18. package/dist/src/cli/commands/recipe.js +34 -21
  19. package/dist/src/cli/commands/scenario.js +78 -12
  20. package/dist/src/cli/contract.js +30 -7
  21. package/dist/src/cli/env.d.ts +6 -0
  22. package/dist/src/cli/env.js +10 -3
  23. package/dist/src/cli/helpers/app-permissions.d.ts +1 -1
  24. package/dist/src/cli/helpers/app-permissions.js +2 -2
  25. package/dist/src/cli/helpers/cleanup.d.ts +2 -0
  26. package/dist/src/cli/helpers/cleanup.js +122 -8
  27. package/dist/src/cli/helpers/flow-zone.d.ts +1 -1
  28. package/dist/src/cli/helpers/flow-zone.js +3 -4
  29. package/dist/src/cli/list-output.d.ts +5 -0
  30. package/dist/src/cli/list-output.js +11 -2
  31. package/dist/src/cli/list-shapes.d.ts +6 -0
  32. package/dist/src/cli/list-shapes.js +7 -1
  33. package/dist/src/cli/output-schemas.d.ts +1 -1
  34. package/dist/src/cli/output-schemas.js +1 -1
  35. package/dist/src/cli/output.d.ts +2 -0
  36. package/dist/src/cli/output.js +31 -4
  37. package/dist/src/cli/read-shapes.js +90 -0
  38. package/dist/src/cli/result-shapes.d.ts +19 -1
  39. package/dist/src/cli/result-shapes.js +227 -4
  40. package/dist/src/cli/selector-suggestions.d.ts +14 -0
  41. package/dist/src/cli/selector-suggestions.js +56 -0
  42. package/dist/src/cli/usage.d.ts +1 -1
  43. package/dist/src/cli/usage.js +29 -4
  44. package/dist/src/cli/version.d.ts +2 -2
  45. package/dist/src/cli/version.js +4 -5
  46. package/dist/src/cli.js +128 -30
  47. package/dist/src/client.d.ts +15 -2
  48. package/dist/src/client.js +36 -11
  49. package/dist/src/errors.d.ts +2 -0
  50. package/dist/src/errors.js +12 -2
  51. package/dist/src/generated/action-output-schemas.json +232 -0
  52. package/dist/src/index.d.ts +1 -1
  53. package/dist/src/resources/datasets.d.ts +11 -1
  54. package/dist/src/resources/datasets.js +91 -30
  55. package/dist/src/resources/jobs.d.ts +35 -5
  56. package/dist/src/resources/jobs.js +68 -41
  57. package/dist/src/resources/projects.js +2 -2
  58. package/dist/src/resources/recipe-create.d.ts +4 -1
  59. package/dist/src/resources/recipe-create.js +11 -2
  60. package/dist/src/resources/recipes.d.ts +12 -1
  61. package/dist/src/resources/recipes.js +39 -12
  62. package/dist/src/resources/scenarios.d.ts +8 -1
  63. package/dist/src/resources/scenarios.js +51 -12
  64. package/dist/src/resources/sql.js +3 -3
  65. package/dist/src/resources/wiki.js +3 -7
  66. package/dist/src/skill.js +1 -2
  67. package/dist/src/utils/project-archive.d.ts +25 -0
  68. package/dist/src/utils/project-archive.js +216 -5
  69. package/dist/src/utils/response-file.js +15 -8
  70. package/package.json +12 -12
  71. package/plugin.json +1 -1
  72. package/skills/dataiku-dss/SKILL.md +15 -17
  73. package/skills/dataiku-dss/references/discovery.md +2 -2
  74. package/skills/dataiku-dss/references/troubleshooting.md +1 -0
package/README.md CHANGED
@@ -16,7 +16,7 @@ Malformed user/group listings and scenario run histories fail explicitly instead
16
16
 
17
17
  ## Platform support
18
18
 
19
- The published `dss` CLI requires Bun >= 1.4.2 and supports Linux, macOS, and Windows. CI runs Bun 1.4.2 on all three operating systems. The runtime dependency is pure JavaScript, so the same package also runs on every Bun-supported x64 and ARM64 system.
19
+ The published `dss` CLI requires Bun >= 1.4.3 and supports Linux, macOS, and Windows. CI runs Bun 1.4.3 on all three operating systems. The runtime dependency is pure JavaScript, so the same package also runs on every Bun-supported x64 and ARM64 system.
20
20
 
21
21
  Run directly with Bun:
22
22
 
@@ -29,7 +29,7 @@ Or install the npm binary:
29
29
  ```text
30
30
  npm install --global dataiku-sdk
31
31
  ```
32
- The installed `dss` bin bootstraps Bun with automatic `.env` preloading disabled, so Bun >= 1.4.2 must be on `PATH`; the CLI's own `.env` handling stays authoritative. `bunx --bun` forces Bun's Node-compatibility mode, which provides the same no-preload guarantee across operating systems.
32
+ The installed `dss` bin bootstraps Bun with automatic `.env` preloading disabled, so Bun >= 1.4.3 must be on `PATH`; the CLI's own `.env` handling stays authoritative. `bunx --bun` forces Bun's Node-compatibility mode, which provides the same no-preload guarantee across operating systems.
33
33
 
34
34
  Bun is the only supported runtime and the package manager. Examples below assume an installed `dss` binary. From a checkout, use `bun --no-env-file src/cli.ts ...` or the packaged launcher `bun --no-env-file ./bin/dss.js ...`. From another working directory, pass the checkout's absolute `bin/dss.js` path to Bun.
35
35
  `--no-env-file` disables Bun's automatic preloading only; the CLI still applies its documented `.env` handling unless `DATAIKU_DISABLE_ENV=1` is set.
@@ -181,7 +181,7 @@ then update `tests/live-coverage.ts` when the
181
181
  registry changes; catalogue drift fails the offline gate. Plan/dry-run calls do not count
182
182
  as executed live coverage.
183
183
 
184
- Regular `bun run check` and `bun run lint` include the live runner and fixtures.
184
+ Regular `bun run verify` and `bun run lint` include the live runner and fixtures.
185
185
  Lint includes project-owned rules in `tools/oxlint/index.ts`: accumulator-copy, widen-then-assert, and chained-assertion errors, alongside the native accumulating-spread check.
186
186
  For focused verification:
187
187
 
@@ -291,6 +291,7 @@ Use environment variables for ephemeral runs. For disposable agent tests, set `D
291
291
  Credential precedence is flags first, then `DATAIKU_*` environment variables, then saved credentials in `DSS_CONFIG_DIR` or the platform config directory.
292
292
  Set `DATAIKU_DISABLE_ENV=1` when a test must ignore both `.env` files and `DATAIKU_*` environment variables.
293
293
  When `.env` loading is enabled, the CLI reads `.env` from the CLI build/root directory and from the command's current working directory; put test-specific `.env` files in the directory where you invoke `dss`. Only `DATAIKU_*`, `NODE_TLS_REJECT_UNAUTHORIZED`, and `NODE_EXTRA_CA_CERTS` are read from `.env`; other keys are ignored.
294
+ Set `DSS_PRETTY=1` to indent stdout JSON (still one JSON value). Use it when the shell or agent harness cuts long lines (omp's bash tool cuts each line at 768 bytes), so a one-line result is not truncated. It is read from the process environment only, not from `.env`.
294
295
 
295
296
  POSIX shell:
296
297
 
@@ -1 +1 @@
1
- {"format":1,"buildRevision":"3f9f0582b0fa45ee3708215954761d75f6edf9b7"}
1
+ {"format":1,"buildRevision":"88fd13012a34de8687737c530fbe86469d8e3f5d"}
@@ -284,6 +284,12 @@ export declare const JobWaitResultSchema: import("@sinclair/typebox").TObject<{
284
284
  pollCount: import("@sinclair/typebox").TNumber;
285
285
  success: import("@sinclair/typebox").TBoolean;
286
286
  timedOut: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
287
+ /** Present on a wait timeout: the wait never cancels the job, so this is `false`. */
288
+ cancelled: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
289
+ /** CLI only, on a wait timeout: POSIX display form of the command that resumes waiting for the still-running job. */
290
+ resume: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
291
+ /** CLI only, on a wait timeout: the resume command as argv, runnable without a shell on any OS. */
292
+ resumeArgv: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
287
293
  progress: import("@sinclair/typebox").TObject<{
288
294
  done: import("@sinclair/typebox").TNumber;
289
295
  failed: import("@sinclair/typebox").TNumber;
@@ -308,6 +308,12 @@ export const JobWaitResultSchema = Type.Object({
308
308
  pollCount: Type.Number(),
309
309
  success: Type.Boolean(),
310
310
  timedOut: Type.Optional(Type.Boolean()),
311
+ /** Present on a wait timeout: the wait never cancels the job, so this is `false`. */
312
+ cancelled: Type.Optional(Type.Boolean()),
313
+ /** CLI only, on a wait timeout: POSIX display form of the command that resumes waiting for the still-running job. */
314
+ resume: Type.Optional(Type.String()),
315
+ /** CLI only, on a wait timeout: the resume command as argv, runnable without a shell on any OS. */
316
+ resumeArgv: Type.Optional(Type.Array(Type.String())),
311
317
  progress: Type.Object({
312
318
  done: Type.Number(),
313
319
  failed: Type.Number(),
@@ -21,6 +21,12 @@ export declare function parseJsonObject(text: string, source: string): Record<st
21
21
  export declare function json(v: string | boolean | undefined, source?: string): Record<string, unknown> | undefined;
22
22
  export declare function readStdinText(): string;
23
23
  export declare function readInputText(path: string, flag: string): string;
24
+ /**
25
+ * Async UTF-8 read of a user-supplied path (BOM kept, like `readFileSync`).
26
+ * Stays on node:fs: Bun 1.4.3 `Bun.file(path)` reads of a missing path ended the
27
+ * process on Windows CI instead of rejecting with ENOENT.
28
+ */
29
+ export declare function readTextFile(path: string): Promise<string>;
24
30
  export declare function seenJsonInputCredentials(): readonly string[];
25
31
  export declare function jsonInput(flags: Record<string, string | boolean>): Record<string, unknown> | undefined;
26
32
  export declare function unknownJsonInput(flags: Record<string, string | boolean>): unknown;
@@ -1,4 +1,5 @@
1
1
  import { readFileSync, } from "node:fs";
2
+ import { readFile, } from "node:fs/promises";
2
3
  import { credentialValues, } from "../utils/secret-sanitize.js";
3
4
  import { UsageError, } from "./usage.js";
4
5
  function safeValuePreview(value) {
@@ -174,6 +175,14 @@ export function readInputText(path, flag) {
174
175
  throw new UsageError(`Could not read ${flag} file: ${path}`, "validation_failed", "Verify that the path names an existing, readable file.", { flag, path, ...(cause ? { cause, } : {}), });
175
176
  }
176
177
  }
178
+ /**
179
+ * Async UTF-8 read of a user-supplied path (BOM kept, like `readFileSync`).
180
+ * Stays on node:fs: Bun 1.4.3 `Bun.file(path)` reads of a missing path ended the
181
+ * process on Windows CI instead of rejecting with ENOENT.
182
+ */
183
+ export async function readTextFile(path) {
184
+ return readFile(path, "utf-8");
185
+ }
177
186
  /**
178
187
  * Credential values seen in this process's JSON inputs. DSS error text can
179
188
  * echo the request payload, so error reports redact these.
@@ -87,6 +87,15 @@
87
87
  {
88
88
  "arg": "analysisId"
89
89
  },
90
+ {
91
+ "optional": [
92
+ [
93
+ {
94
+ "flag": "full"
95
+ }
96
+ ]
97
+ ]
98
+ },
90
99
  {
91
100
  "optional": [
92
101
  [
@@ -1699,6 +1708,15 @@
1699
1708
  "get",
1700
1709
  {
1701
1710
  "arg": "id"
1711
+ },
1712
+ {
1713
+ "optional": [
1714
+ [
1715
+ {
1716
+ "flag": "full"
1717
+ }
1718
+ ]
1719
+ ]
1702
1720
  }
1703
1721
  ],
1704
1722
  "business-app.install-from-archive": [
@@ -1956,6 +1974,15 @@
1956
1974
  },
1957
1975
  {
1958
1976
  "arg": "name"
1977
+ },
1978
+ {
1979
+ "optional": [
1980
+ [
1981
+ {
1982
+ "flag": "full"
1983
+ }
1984
+ ]
1985
+ ]
1959
1986
  }
1960
1987
  ],
1961
1988
  "code-env.get-definition": [
@@ -3106,6 +3133,15 @@
3106
3133
  {
3107
3134
  "arg": "id"
3108
3135
  },
3136
+ {
3137
+ "optional": [
3138
+ [
3139
+ {
3140
+ "flag": "full"
3141
+ }
3142
+ ]
3143
+ ]
3144
+ },
3109
3145
  {
3110
3146
  "optional": [
3111
3147
  [
@@ -3320,6 +3356,15 @@
3320
3356
  "get",
3321
3357
  {
3322
3358
  "arg": "dataCollectionId"
3359
+ },
3360
+ {
3361
+ "optional": [
3362
+ [
3363
+ {
3364
+ "flag": "full"
3365
+ }
3366
+ ]
3367
+ ]
3323
3368
  }
3324
3369
  ],
3325
3370
  "data-collection.list": [
@@ -5033,6 +5078,15 @@
5033
5078
  {
5034
5079
  "arg": "discussionId"
5035
5080
  },
5081
+ {
5082
+ "optional": [
5083
+ [
5084
+ {
5085
+ "flag": "full"
5086
+ }
5087
+ ]
5088
+ ]
5089
+ },
5036
5090
  {
5037
5091
  "optional": [
5038
5092
  [
@@ -5373,6 +5427,15 @@
5373
5427
  {
5374
5428
  "arg": "id"
5375
5429
  },
5430
+ {
5431
+ "optional": [
5432
+ [
5433
+ {
5434
+ "flag": "full"
5435
+ }
5436
+ ]
5437
+ ]
5438
+ },
5376
5439
  {
5377
5440
  "optional": [
5378
5441
  [
@@ -6092,6 +6155,15 @@
6092
6155
  {
6093
6156
  "arg": "name-or-id"
6094
6157
  },
6158
+ {
6159
+ "optional": [
6160
+ [
6161
+ {
6162
+ "flag": "full"
6163
+ }
6164
+ ]
6165
+ ]
6166
+ },
6095
6167
  {
6096
6168
  "optional": [
6097
6169
  [
@@ -6409,6 +6481,15 @@
6409
6481
  "get",
6410
6482
  {
6411
6483
  "arg": "name"
6484
+ },
6485
+ {
6486
+ "optional": [
6487
+ [
6488
+ {
6489
+ "flag": "full"
6490
+ }
6491
+ ]
6492
+ ]
6412
6493
  }
6413
6494
  ],
6414
6495
  "group.list": [
@@ -6634,6 +6715,15 @@
6634
6715
  {
6635
6716
  "arg": "id"
6636
6717
  },
6718
+ {
6719
+ "optional": [
6720
+ [
6721
+ {
6722
+ "flag": "full"
6723
+ }
6724
+ ]
6725
+ ]
6726
+ },
6637
6727
  {
6638
6728
  "optional": [
6639
6729
  [
@@ -7900,6 +7990,15 @@
7900
7990
  {
7901
7991
  "arg": "macro_id"
7902
7992
  },
7993
+ {
7994
+ "optional": [
7995
+ [
7996
+ {
7997
+ "flag": "full"
7998
+ }
7999
+ ]
8000
+ ]
8001
+ },
7903
8002
  {
7904
8003
  "optional": [
7905
8004
  [
@@ -8209,6 +8308,15 @@
8209
8308
  "get",
8210
8309
  {
8211
8310
  "arg": "meaningId"
8311
+ },
8312
+ {
8313
+ "optional": [
8314
+ [
8315
+ {
8316
+ "flag": "full"
8317
+ }
8318
+ ]
8319
+ ]
8212
8320
  }
8213
8321
  ],
8214
8322
  "meaning.list": [
@@ -9758,6 +9866,15 @@
9758
9866
  {
9759
9867
  "arg": "storeId"
9760
9868
  },
9869
+ {
9870
+ "optional": [
9871
+ [
9872
+ {
9873
+ "flag": "full"
9874
+ }
9875
+ ]
9876
+ ]
9877
+ },
9761
9878
  {
9762
9879
  "optional": [
9763
9880
  [
@@ -11627,6 +11744,15 @@
11627
11744
  "get",
11628
11745
  {
11629
11746
  "arg": "folderId"
11747
+ },
11748
+ {
11749
+ "optional": [
11750
+ [
11751
+ {
11752
+ "flag": "full"
11753
+ }
11754
+ ]
11755
+ ]
11630
11756
  }
11631
11757
  ],
11632
11758
  "project-folder.move": [
@@ -13940,6 +14066,15 @@
13940
14066
  ]
13941
14067
  ]
13942
14068
  },
14069
+ {
14070
+ "optional": [
14071
+ [
14072
+ {
14073
+ "flag": "full"
14074
+ }
14075
+ ]
14076
+ ]
14077
+ },
13943
14078
  {
13944
14079
  "optional": [
13945
14080
  [
@@ -15058,6 +15193,15 @@
15058
15193
  {
15059
15194
  "arg": "modelId"
15060
15195
  },
15196
+ {
15197
+ "optional": [
15198
+ [
15199
+ {
15200
+ "flag": "full"
15201
+ }
15202
+ ]
15203
+ ]
15204
+ },
15061
15205
  {
15062
15206
  "optional": [
15063
15207
  [
@@ -15612,6 +15756,15 @@
15612
15756
  {
15613
15757
  "arg": "id"
15614
15758
  },
15759
+ {
15760
+ "optional": [
15761
+ [
15762
+ {
15763
+ "flag": "full"
15764
+ }
15765
+ ]
15766
+ ]
15767
+ },
15615
15768
  {
15616
15769
  "optional": [
15617
15770
  [
@@ -15633,6 +15786,15 @@
15633
15786
  {
15634
15787
  "arg": "runId"
15635
15788
  },
15789
+ {
15790
+ "optional": [
15791
+ [
15792
+ {
15793
+ "flag": "full"
15794
+ }
15795
+ ]
15796
+ ]
15797
+ },
15636
15798
  {
15637
15799
  "optional": [
15638
15800
  [
@@ -15661,6 +15823,15 @@
15661
15823
  ]
15662
15824
  ]
15663
15825
  },
15826
+ {
15827
+ "optional": [
15828
+ [
15829
+ {
15830
+ "flag": "full"
15831
+ }
15832
+ ]
15833
+ ]
15834
+ },
15664
15835
  {
15665
15836
  "optional": [
15666
15837
  [
@@ -16525,6 +16696,15 @@
16525
16696
  {
16526
16697
  "arg": "id"
16527
16698
  },
16699
+ {
16700
+ "optional": [
16701
+ [
16702
+ {
16703
+ "flag": "full"
16704
+ }
16705
+ ]
16706
+ ]
16707
+ },
16528
16708
  {
16529
16709
  "optional": [
16530
16710
  [
@@ -16784,6 +16964,15 @@
16784
16964
  "get",
16785
16965
  {
16786
16966
  "arg": "login"
16967
+ },
16968
+ {
16969
+ "optional": [
16970
+ [
16971
+ {
16972
+ "flag": "full"
16973
+ }
16974
+ ]
16975
+ ]
16787
16976
  }
16788
16977
  ],
16789
16978
  "user.list": [
@@ -16941,6 +17130,15 @@
16941
17130
  "dss",
16942
17131
  "variable",
16943
17132
  "get",
17133
+ {
17134
+ "optional": [
17135
+ [
17136
+ {
17137
+ "flag": "full"
17138
+ }
17139
+ ]
17140
+ ]
17141
+ },
16944
17142
  {
16945
17143
  "optional": [
16946
17144
  [
@@ -17446,6 +17644,15 @@
17446
17644
  {
17447
17645
  "arg": "id-or-name"
17448
17646
  },
17647
+ {
17648
+ "optional": [
17649
+ [
17650
+ {
17651
+ "flag": "full"
17652
+ }
17653
+ ]
17654
+ ]
17655
+ },
17449
17656
  {
17450
17657
  "optional": [
17451
17658
  [
@@ -17697,6 +17904,15 @@
17697
17904
  "get",
17698
17905
  {
17699
17906
  "arg": "workspaceKey"
17907
+ },
17908
+ {
17909
+ "optional": [
17910
+ [
17911
+ {
17912
+ "flag": "full"
17913
+ }
17914
+ ]
17915
+ ]
17700
17916
  }
17701
17917
  ],
17702
17918
  "workspace.list": [
@@ -754,7 +754,7 @@ export const appCommands = withUsage("app", {
754
754
  const usage = commandUsage("app", "permissions-diff");
755
755
  requireNoArgs(_a, usage);
756
756
  const file = requiredStringFlag(f, "file", usage);
757
- const snapshot = readAppPermissionsSnapshot(file);
757
+ const snapshot = await readAppPermissionsSnapshot(file);
758
758
  const projectKey = c.resolveProjectKey(f["project-key"]);
759
759
  assertAppPermissionsSnapshotBinding(snapshot, projectKey, c.getBaseUrl());
760
760
  const currentProjectIncarnationHash = await requireProjectIncarnationHash(c, projectKey);
@@ -779,7 +779,7 @@ export const appCommands = withUsage("app", {
779
779
  const usage = commandUsage("app", "permissions-restore");
780
780
  requireNoArgs(_a, usage);
781
781
  const file = requiredStringFlag(f, "file", usage);
782
- const snapshot = readAppPermissionsSnapshot(file);
782
+ const snapshot = await readAppPermissionsSnapshot(file);
783
783
  const projectKey = c.resolveProjectKey(f["project-key"]);
784
784
  assertAppPermissionsSnapshotBinding(snapshot, projectKey, c.getBaseUrl());
785
785
  const currentProjectIncarnationHash = await requireProjectIncarnationHash(c, projectKey);
@@ -1,7 +1,6 @@
1
- import { readFileSync, writeFileSync, } from "node:fs";
2
1
  import { ClientValidationError, } from "../../errors.js";
3
2
  import { SHA256_HEX_PATTERN, stableHash, } from "../../utils/stable-hash.js";
4
- import { json, jsonInput, num, numFlag, parseBooleanOption, } from "../coerce.js";
3
+ import { json, jsonInput, num, numFlag, parseBooleanOption, readTextFile, } from "../coerce.js";
5
4
  import { executionMode, } from "../flags.js";
6
5
  import { enqueueCliWarning, isNotFoundError, readIfExists, skipResult, } from "../output.js";
7
6
  import { commandUsage, withUsage, } from "../syntax.js";
@@ -49,9 +48,9 @@ function splitPackageSpec(raw) {
49
48
  * (set-packages replaces specPackageList wholesale); only a call with no
50
49
  * package source flag at all is a usage error.
51
50
  */
52
- function codeEnvPackageList(flags) {
51
+ async function codeEnvPackageList(flags) {
53
52
  const file = flags["file"];
54
- const packages = typeof file === "string" ? splitPackageSpec(readFileSync(file, "utf-8")) : [];
53
+ const packages = typeof file === "string" ? splitPackageSpec(await readTextFile(file)) : [];
55
54
  if (typeof flags["packages"] === "string") {
56
55
  packages.push(...splitPackageSpec(flags["packages"]));
57
56
  }
@@ -80,13 +79,15 @@ export const codeEnvCommands = withUsage("code-env", {
80
79
  examples: ["dss code-env list", "dss code-env list --lang PYTHON",],
81
80
  },
82
81
  get: {
83
- handler: (c, a) => {
82
+ handler: (c, a, f) => {
84
83
  const usage = commandUsage("code-env", "get");
85
84
  requireArgs(a, 2, usage);
86
85
  const envLang = requireEnvLang(a[0], usage);
87
- return c.codeEnvs.get(envLang, a[1]);
86
+ return f["full"] === true
87
+ ? c.codeEnvs.getDefinition(envLang, a[1])
88
+ : c.codeEnvs.get(envLang, a[1]);
88
89
  },
89
- 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.",
90
+ 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. --full returns the raw DSS definition (same as get-definition).",
90
91
  examples: ["dss code-env get PYTHON my_env",],
91
92
  },
92
93
  "get-definition": {
@@ -122,7 +123,7 @@ export const codeEnvCommands = withUsage("code-env", {
122
123
  });
123
124
  const output = f["output"];
124
125
  if (typeof output === "string" && output.trim().length > 0) {
125
- writeFileSync(output, result.log, "utf-8");
126
+ await Bun.write(output, result.log);
126
127
  if (result.truncated || result.tailed) {
127
128
  const limits = [
128
129
  result.tailed ? `tail limited to ${maxLines ?? 500} lines` : undefined,
@@ -257,7 +258,7 @@ export const codeEnvCommands = withUsage("code-env", {
257
258
  const usage = commandUsage("code-env", "set-packages");
258
259
  requireArgs(a, 2, usage);
259
260
  const envLang = requireEnvLang(a[0], usage);
260
- const packages = codeEnvPackageList(f);
261
+ const packages = await codeEnvPackageList(f);
261
262
  const installCorePackages = parseBooleanOption(f["install-core-packages"], "--install-core-packages");
262
263
  const expectHash = validateExpectHash(f["expect-hash"]);
263
264
  if (executionMode(f).dryRun) {
@@ -115,19 +115,33 @@ export const codeCommands = withUsage("code", {
115
115
  maxLogBytes: run.maxLogBytes,
116
116
  cleanup: run.cleanup,
117
117
  ...(run.timedOut === true ? { timedOut: true, timeoutMs: run.timeoutMs, } : {}),
118
+ ...(run.outputTruncated === true ? { outputTruncated: true, } : {}),
119
+ ...(run.outputOmittedBytes !== undefined
120
+ ? { outputOmittedBytes: run.outputOmittedBytes, }
121
+ : {}),
118
122
  };
119
123
  if (f["full-log"] === true || run.output === undefined) {
120
124
  result.log = run.log;
121
125
  }
126
+ if (run.outputTruncated === true) {
127
+ enqueueCliWarning({
128
+ code: "code_run_output_truncated",
129
+ hint: run.outputOmittedBytes !== undefined
130
+ ? `Script output exceeded the capture budget; the first ${run.outputOmittedBytes} bytes were dropped and \`output\` holds the last part. Raise --max-log-bytes (the budget is a quarter of it) or print less.`
131
+ : "The run log exceeded --max-log-bytes, so the start of the script output was cut and `output` holds the last part. Raise --max-log-bytes or print less.",
132
+ ...(run.outputOmittedBytes !== undefined ? { omittedBytes: run.outputOmittedBytes, } : {}),
133
+ maxLogBytes: run.maxLogBytes,
134
+ });
135
+ }
122
136
  if (run.cleanup.status === "failed") {
123
137
  reportCleanupFailure({ scenarioId: run.scenarioId, error: run.cleanup.error ?? "unknown", });
124
138
  }
125
139
  return result;
126
140
  },
127
- description: "Run Python through a throwaway custom-python scenario and return captured output plus outcome. --timeout caps waiting; --max-log-bytes caps logs; --full-log returns the capped raw log. Exits 4 unless outcome is SUCCESS.",
141
+ description: "Run Python through a throwaway custom-python scenario and return captured output plus outcome. --timeout caps waiting; --max-log-bytes caps the log tail read (script output keeps its last quarter; a code_run_output_truncated warning reports cuts); --full-log returns the capped raw log. Exits 4 unless outcome is SUCCESS.",
128
142
  examples: [
129
143
  "dss code run --file inspect.py",
130
- "dss code run --file inspect.py --env py39_pandas",
144
+ "dss code run --file inspect.py --env py311_pandas",
131
145
  "cat snippet.py | dss code run --stdin",
132
146
  "dss code run --file inspect.py --full-log",
133
147
  ],
@@ -1,4 +1,3 @@
1
- import * as fs from "node:fs";
2
1
  import { ClientValidationError, } from "../../errors.js";
3
2
  import { deepMerge, } from "../../utils/deep-merge.js";
4
3
  import { jsonInput, parseBooleanOption, } from "../coerce.js";
@@ -73,7 +72,7 @@ export const dashboardCommands = withUsage("dashboard", {
73
72
  if (!isPdf) {
74
73
  throw new ClientValidationError("DSS dashboard export did not return a PDF.", "validation_failed", "Confirm DSS graphics export is configured and retry the export.");
75
74
  }
76
- fs.writeFileSync(outputPath, bytes);
75
+ await Bun.write(outputPath, bytes);
77
76
  return {
78
77
  path: outputPath,
79
78
  bytes: bytes.length,
@@ -225,11 +225,13 @@ export const datasetCommands = withUsage("dataset", {
225
225
  handler: async (c, a, f) => {
226
226
  const previewUsage = commandUsage("dataset", "preview");
227
227
  requireArgs(a, 1, previewUsage);
228
- const maxRows = num(f["max-rows"], "--max-rows");
229
- if (maxRows !== undefined && (!Number.isSafeInteger(maxRows) || maxRows <= 0 || maxRows > 500)) {
230
- throw new UsageError(`--max-rows must be a positive integer no greater than 500 (got "${String(f["max-rows"])}"). `
231
- + `Usage: ${previewUsage}`, "validation_failed");
228
+ const requestedRows = num(f["max-rows"], "--max-rows");
229
+ if (requestedRows !== undefined && (!Number.isSafeInteger(requestedRows) || requestedRows <= 0)) {
230
+ throw new UsageError(`--max-rows must be a positive integer (got "${String(f["max-rows"])}"). Usage: ${previewUsage}`, "validation_failed");
232
231
  }
232
+ // Agents ask for "all rows" with a large number; serve the 500-row public
233
+ // maximum instead of failing, and let the truncation warning say if more exist.
234
+ const maxRows = requestedRows === undefined ? undefined : Math.min(requestedRows, 500);
233
235
  const result = await c.datasets.preview(a[0], {
234
236
  maxRows,
235
237
  projectKey: f["project-key"],
@@ -275,7 +275,7 @@ export const flowZoneCommands = withUsage("flow-zone", {
275
275
  handler: async (c, _a, f) => {
276
276
  const usage = commandUsage("flow-zone", "organize");
277
277
  const pk = f["project-key"];
278
- const parsed = readFlowZoneOrganizePlan(f, usage);
278
+ const parsed = await readFlowZoneOrganizePlan(f, usage);
279
279
  const sync = f["sync"] === true;
280
280
  const validateObjects = f["validate-objects"] === true;
281
281
  const recreateOnMove = f["recreate-on-move"] === true;