dataiku-sdk 0.2.2 → 0.2.4

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.
@@ -14,9 +14,9 @@ export type SafeParseResult<T> = {
14
14
  errors: string[];
15
15
  };
16
16
  /**
17
- * Validate `data` against a TypeBox schema without throwing.
18
- * Always returns the data (cast as T) — on mismatch, includes human-readable
19
- * error strings so callers can warn instead of crash.
17
+ * Validate `data` against a TypeBox schema without throwing, even when invalid
18
+ * values are not JSON-serializable. Always returns the original data (cast as T)
19
+ * and includes human-readable error strings so callers can warn instead of crash.
20
20
  */
21
21
  export declare function safeParseSchema<S extends TSchema>(schema: S, data: unknown): SafeParseResult<Static<S>>;
22
22
  export declare const ProjectSummarySchema: import("@sinclair/typebox").TObject<{
@@ -12,15 +12,65 @@ export function parseSchema(schema, data) {
12
12
  return data;
13
13
  }
14
14
  /**
15
- * Validate `data` against a TypeBox schema without throwing.
16
- * Always returns the data (cast as T) — on mismatch, includes human-readable
17
- * error strings so callers can warn instead of crash.
15
+ * Format invalid values for validation errors without throwing on BigInt, circular,
16
+ * function, symbol, or other non-JSON-serializable input.
17
+ */
18
+ function formatInvalidValue(value) {
19
+ if (value === undefined)
20
+ return "undefined";
21
+ if (typeof value === "bigint")
22
+ return `${value.toString()}n`;
23
+ if (typeof value === "symbol") {
24
+ return value.description === undefined ? "Symbol()" : `Symbol(${value.description})`;
25
+ }
26
+ if (typeof value === "function") {
27
+ return value.name ? `[Function ${value.name}]` : "[Function anonymous]";
28
+ }
29
+ const seen = new WeakSet();
30
+ try {
31
+ const json = JSON.stringify(value, (_key, nestedValue) => {
32
+ if (typeof nestedValue === "bigint")
33
+ return `${nestedValue.toString()}n`;
34
+ if (typeof nestedValue === "symbol") {
35
+ return nestedValue.description === undefined
36
+ ? "Symbol()"
37
+ : `Symbol(${nestedValue.description})`;
38
+ }
39
+ if (typeof nestedValue === "function") {
40
+ return nestedValue.name
41
+ ? `[Function ${nestedValue.name}]`
42
+ : "[Function anonymous]";
43
+ }
44
+ if (nestedValue !== null && typeof nestedValue === "object") {
45
+ if (seen.has(nestedValue))
46
+ return "[Circular]";
47
+ seen.add(nestedValue);
48
+ }
49
+ return nestedValue;
50
+ });
51
+ if (json !== undefined)
52
+ return json;
53
+ }
54
+ catch {
55
+ // Ignore serialization failures and fall back to a safer summary below.
56
+ }
57
+ try {
58
+ return Object.prototype.toString.call(value);
59
+ }
60
+ catch {
61
+ return "[Unformattable value]";
62
+ }
63
+ }
64
+ /**
65
+ * Validate `data` against a TypeBox schema without throwing, even when invalid
66
+ * values are not JSON-serializable. Always returns the original data (cast as T)
67
+ * and includes human-readable error strings so callers can warn instead of crash.
18
68
  */
19
69
  export function safeParseSchema(schema, data) {
20
70
  if (Value.Check(schema, data)) {
21
71
  return { success: true, data: data, };
22
72
  }
23
- const errors = [...Value.Errors(schema, data),].map((e) => `${e.path}: ${e.message} (got ${JSON.stringify(e.value)})`);
73
+ const errors = [...Value.Errors(schema, data),].map((e) => `${e.path}: ${e.message} (got ${formatInvalidValue(e.value)})`);
24
74
  return { success: false, data: data, errors, };
25
75
  }
26
76
  // ---------------------------------------------------------------------------
@@ -1,4 +1,7 @@
1
- export declare function validateCredentials(url: string, apiKey: string): Promise<{
1
+ import { DataikuError } from "./errors.js";
2
+ export interface CredentialValidationResult {
2
3
  valid: boolean;
3
4
  error?: string;
4
- }>;
5
+ dataikuError?: DataikuError;
6
+ }
7
+ export declare function validateCredentials(url: string, apiKey: string): Promise<CredentialValidationResult>;
package/dist/src/auth.js CHANGED
@@ -13,7 +13,7 @@ export async function validateCredentials(url, apiKey) {
13
13
  }
14
14
  catch (err) {
15
15
  if (err instanceof DataikuError) {
16
- return { valid: false, error: err.message, };
16
+ return { valid: false, error: err.message, dataikuError: err, };
17
17
  }
18
18
  return { valid: false, error: err instanceof Error ? err.message : String(err), };
19
19
  }
package/dist/src/cli.js CHANGED
@@ -9,7 +9,7 @@ import { validateCredentials, } from "./auth.js";
9
9
  import { DataikuClient, } from "./client.js";
10
10
  import { deleteCredentials, getCredentialsPath, loadCredentials, maskApiKey, saveCredentials, } from "./config.js";
11
11
  import { DataikuError, } from "./errors.js";
12
- import { AGENTS, detectAgents, installSkill, } from "./skill.js";
12
+ import { AGENTS, detectAgents, findWorkspaceRoot, installSkill, } from "./skill.js";
13
13
  // ---------------------------------------------------------------------------
14
14
  // Utility helpers
15
15
  // ---------------------------------------------------------------------------
@@ -150,7 +150,18 @@ function writeCommandResult(result, format) {
150
150
  // ---------------------------------------------------------------------------
151
151
  // Arg parsing
152
152
  // ---------------------------------------------------------------------------
153
- const BOOLEAN_FLAGS = new Set(["help", "verbose", "version", "stdin", "global", "list-agents",]);
153
+ const BOOLEAN_FLAGS = new Set([
154
+ "help",
155
+ "verbose",
156
+ "version",
157
+ "stdin",
158
+ "global",
159
+ "list-agents",
160
+ "include-raw",
161
+ "include-payload",
162
+ "include-logs",
163
+ "replace",
164
+ ]);
154
165
  const SHORT_FLAGS = {
155
166
  h: "help",
156
167
  v: "verbose",
@@ -162,6 +173,15 @@ const SHORT_FLAGS = {
162
173
  const FLAG_ALIASES = {
163
174
  project: "project-key",
164
175
  };
176
+ function isNegativeNumberToken(value) {
177
+ return value.startsWith("-") && Number.isFinite(Number(value));
178
+ }
179
+ function requireFlagValue(flagLabel, next) {
180
+ if (next === undefined || (next.startsWith("-") && !isNegativeNumberToken(next))) {
181
+ throw new UsageError(`Flag ${flagLabel} requires a value.`);
182
+ }
183
+ return next;
184
+ }
165
185
  function parseArgs(argv) {
166
186
  const positional = [];
167
187
  const flags = {};
@@ -179,19 +199,15 @@ function parseArgs(argv) {
179
199
  flags[FLAG_ALIASES[raw] ?? raw] = arg.slice(eqIdx + 1);
180
200
  }
181
201
  else {
182
- const flagName = FLAG_ALIASES[arg.slice(2)] ?? arg.slice(2);
202
+ const rawFlagName = arg.slice(2);
203
+ const flagName = FLAG_ALIASES[rawFlagName] ?? rawFlagName;
183
204
  if (BOOLEAN_FLAGS.has(flagName)) {
184
205
  flags[flagName] = true;
185
206
  }
186
207
  else {
187
- const next = argv[i + 1];
188
- if (next !== undefined && !next.startsWith("-")) {
189
- flags[flagName] = next;
190
- i++;
191
- }
192
- else {
193
- flags[flagName] = true;
194
- }
208
+ const next = requireFlagValue(`--${rawFlagName}`, argv[i + 1]);
209
+ flags[flagName] = next;
210
+ i++;
195
211
  }
196
212
  }
197
213
  }
@@ -202,14 +218,9 @@ function parseArgs(argv) {
202
218
  flags[long] = true;
203
219
  }
204
220
  else {
205
- const next = argv[i + 1];
206
- if (next !== undefined && !next.startsWith("-")) {
207
- flags[long] = next;
208
- i++;
209
- }
210
- else {
211
- flags[long] = true;
212
- }
221
+ const next = requireFlagValue(`-${arg[1]}`, argv[i + 1]);
222
+ flags[long] = next;
223
+ i++;
213
224
  }
214
225
  }
215
226
  else {
@@ -886,6 +897,8 @@ const AUTH_ACTIONS = {
886
897
  const result = await validateCredentials(url, apiKey);
887
898
  if (!result.valid) {
888
899
  process.stderr.write(`✗ Failed\n`);
900
+ if (result.dataikuError)
901
+ throw result.dataikuError;
889
902
  throw new DataikuError(0, "Authentication Failed", result.error ?? "Credential validation failed");
890
903
  }
891
904
  process.stderr.write("\u2713 Connected\n");
@@ -1021,13 +1034,14 @@ async function main() {
1021
1034
  if (resource === "install-skill") {
1022
1035
  if (flags["help"] === true) {
1023
1036
  const lines = [
1024
- "Usage: dss install-skill [--global] [--agent NAME] [--list-agents]",
1037
+ "Usage: dss install-skill [--global] [--agent NAME] [--target PATH] [--list-agents]",
1025
1038
  "",
1026
1039
  "Install the dataiku-dss agent skill for detected coding agents.",
1027
1040
  "",
1028
1041
  "Flags:",
1029
1042
  " --global Install to user-level global scope (default: project)",
1030
1043
  " --agent NAME Target a specific agent: claude, codex, cursor, pi, omp",
1044
+ " --target PATH Project directory to install into (default: workspace root)",
1031
1045
  " --list-agents Print detected agents and exit",
1032
1046
  ];
1033
1047
  process.stderr.write(`${lines.join("\n")}\n`);
@@ -1036,6 +1050,7 @@ async function main() {
1036
1050
  const listOnly = flags["list-agents"] === true;
1037
1051
  const agentFilter = typeof flags["agent"] === "string" ? flags["agent"] : undefined;
1038
1052
  const isGlobal = flags["global"] === true;
1053
+ const targetDir = typeof flags["target"] === "string" ? flags["target"] : undefined;
1039
1054
  // Resolve target agents
1040
1055
  let targets;
1041
1056
  if (agentFilter) {
@@ -1064,8 +1079,9 @@ async function main() {
1064
1079
  throw new UsageError("No coding agents detected. Install one (claude, codex, cursor, pi, omp) or use --agent NAME.");
1065
1080
  }
1066
1081
  const scope = isGlobal ? "global" : "project";
1082
+ const cwd = targetDir ?? (isGlobal ? process.cwd() : findWorkspaceRoot(process.cwd()));
1067
1083
  process.stderr.write(`Installing dataiku-dss skill (${scope} scope):\n`);
1068
- const results = installSkill(targets, { global: isGlobal, cwd: process.cwd(), });
1084
+ const results = installSkill(targets, { global: isGlobal, cwd, });
1069
1085
  for (const r of results) {
1070
1086
  process.stderr.write(` ${r.agent} \u2192 ${r.path}\n`);
1071
1087
  }
@@ -81,9 +81,10 @@ export declare class DataikuClient {
81
81
  */
82
82
  parse<S extends TSchema>(schema: S, data: unknown): Static<S>;
83
83
  /**
84
- * Validate raw data against a TypeBox schema without throwing.
85
- * Always returns the data. On mismatch, fires onValidationWarning callback
86
- * with the method name and error details.
84
+ * Validate raw data against a TypeBox schema without throwing, even when
85
+ * mismatched values are not JSON-serializable. Always returns the original
86
+ * data, and on mismatch emits onValidationWarning with the method name and
87
+ * error details. If the callback throws, that error still propagates.
87
88
  */
88
89
  safeParse<S extends TSchema>(schema: S, data: unknown, method: string): Static<S>;
89
90
  /** Emit a validation warning via the configured callback. */
@@ -223,9 +223,10 @@ export class DataikuClient {
223
223
  return data;
224
224
  }
225
225
  /**
226
- * Validate raw data against a TypeBox schema without throwing.
227
- * Always returns the data. On mismatch, fires onValidationWarning callback
228
- * with the method name and error details.
226
+ * Validate raw data against a TypeBox schema without throwing, even when
227
+ * mismatched values are not JSON-serializable. Always returns the original
228
+ * data, and on mismatch emits onValidationWarning with the method name and
229
+ * error details. If the callback throws, that error still propagates.
229
230
  */
230
231
  safeParse(schema, data, method) {
231
232
  const result = safeParseSchema(schema, data);
@@ -23,6 +23,11 @@ export interface DetectedAgent {
23
23
  via: "binary" | "config-dir" | "flag";
24
24
  }
25
25
  export declare function detectAgents(): DetectedAgent[];
26
+ /**
27
+ * Walk upward from startDir looking for common workspace markers.
28
+ * Returns the first directory containing a marker, or startDir if none found.
29
+ */
30
+ export declare function findWorkspaceRoot(startDir: string): string;
26
31
  export interface InstallResult {
27
32
  agent: string;
28
33
  path: string;
package/dist/src/skill.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { execFileSync, } from "node:child_process";
2
2
  import { existsSync, mkdirSync, writeFileSync, } from "node:fs";
3
3
  import { homedir, } from "node:os";
4
- import { join, } from "node:path";
4
+ import { dirname, join, } from "node:path";
5
5
  const SKILL_BODY = `# Dataiku DSS CLI
6
6
 
7
7
  The \`dss\` CLI (npm: dataiku-sdk) manages Dataiku DSS resources from the terminal.
@@ -36,7 +36,7 @@ dss auth login --url https://dss.example.com --api-key YOUR_KEY
36
36
  dss auth status # verify connection
37
37
  \`\`\`
38
38
 
39
- Credentials are saved to \`~/.dss/credentials.json\`. Alternatively set environment variables:
39
+ Credentials are saved to \`~/.config/dataiku/credentials.json\`. Alternatively set environment variables:
40
40
 
41
41
  \`\`\`bash
42
42
  export DATAIKU_URL=https://dss.example.com
@@ -200,6 +200,31 @@ export function detectAgents() {
200
200
  }
201
201
  return found;
202
202
  }
203
+ // ---------------------------------------------------------------------------
204
+ // Skill installation
205
+ // ---------------------------------------------------------------------------
206
+ // ---------------------------------------------------------------------------
207
+ // Workspace root detection
208
+ // ---------------------------------------------------------------------------
209
+ const WORKSPACE_MARKERS = [".git", ".cursor", ".claude", ".codex", ".pi", ".omp", ".vscode",];
210
+ /**
211
+ * Walk upward from startDir looking for common workspace markers.
212
+ * Returns the first directory containing a marker, or startDir if none found.
213
+ */
214
+ export function findWorkspaceRoot(startDir) {
215
+ let dir = startDir;
216
+ for (let i = 0; i < 20; i++) {
217
+ for (const marker of WORKSPACE_MARKERS) {
218
+ if (existsSync(join(dir, marker)))
219
+ return dir;
220
+ }
221
+ const parent = dirname(dir);
222
+ if (parent === dir)
223
+ break;
224
+ dir = parent;
225
+ }
226
+ return startDir;
227
+ }
203
228
  export function installSkill(agents, opts) {
204
229
  const home = homedir();
205
230
  const results = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dataiku-sdk",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "Dataiku DSS SDK and CLI for programmatic access to DSS REST APIs",
5
5
  "type": "module",
6
6
  "workspaces": [
@@ -14,9 +14,9 @@ export type SafeParseResult<T> = {
14
14
  errors: string[];
15
15
  };
16
16
  /**
17
- * Validate `data` against a TypeBox schema without throwing.
18
- * Always returns the data (cast as T) — on mismatch, includes human-readable
19
- * error strings so callers can warn instead of crash.
17
+ * Validate `data` against a TypeBox schema without throwing, even when invalid
18
+ * values are not JSON-serializable. Always returns the original data (cast as T)
19
+ * and includes human-readable error strings so callers can warn instead of crash.
20
20
  */
21
21
  export declare function safeParseSchema<S extends TSchema>(schema: S, data: unknown): SafeParseResult<Static<S>>;
22
22
  export declare const ProjectSummarySchema: import("@sinclair/typebox").TObject<{
@@ -12,15 +12,65 @@ export function parseSchema(schema, data) {
12
12
  return data;
13
13
  }
14
14
  /**
15
- * Validate `data` against a TypeBox schema without throwing.
16
- * Always returns the data (cast as T) — on mismatch, includes human-readable
17
- * error strings so callers can warn instead of crash.
15
+ * Format invalid values for validation errors without throwing on BigInt, circular,
16
+ * function, symbol, or other non-JSON-serializable input.
17
+ */
18
+ function formatInvalidValue(value) {
19
+ if (value === undefined)
20
+ return "undefined";
21
+ if (typeof value === "bigint")
22
+ return `${value.toString()}n`;
23
+ if (typeof value === "symbol") {
24
+ return value.description === undefined ? "Symbol()" : `Symbol(${value.description})`;
25
+ }
26
+ if (typeof value === "function") {
27
+ return value.name ? `[Function ${value.name}]` : "[Function anonymous]";
28
+ }
29
+ const seen = new WeakSet();
30
+ try {
31
+ const json = JSON.stringify(value, (_key, nestedValue) => {
32
+ if (typeof nestedValue === "bigint")
33
+ return `${nestedValue.toString()}n`;
34
+ if (typeof nestedValue === "symbol") {
35
+ return nestedValue.description === undefined
36
+ ? "Symbol()"
37
+ : `Symbol(${nestedValue.description})`;
38
+ }
39
+ if (typeof nestedValue === "function") {
40
+ return nestedValue.name
41
+ ? `[Function ${nestedValue.name}]`
42
+ : "[Function anonymous]";
43
+ }
44
+ if (nestedValue !== null && typeof nestedValue === "object") {
45
+ if (seen.has(nestedValue))
46
+ return "[Circular]";
47
+ seen.add(nestedValue);
48
+ }
49
+ return nestedValue;
50
+ });
51
+ if (json !== undefined)
52
+ return json;
53
+ }
54
+ catch {
55
+ // Ignore serialization failures and fall back to a safer summary below.
56
+ }
57
+ try {
58
+ return Object.prototype.toString.call(value);
59
+ }
60
+ catch {
61
+ return "[Unformattable value]";
62
+ }
63
+ }
64
+ /**
65
+ * Validate `data` against a TypeBox schema without throwing, even when invalid
66
+ * values are not JSON-serializable. Always returns the original data (cast as T)
67
+ * and includes human-readable error strings so callers can warn instead of crash.
18
68
  */
19
69
  export function safeParseSchema(schema, data) {
20
70
  if (Value.Check(schema, data)) {
21
71
  return { success: true, data: data, };
22
72
  }
23
- const errors = [...Value.Errors(schema, data),].map((e) => `${e.path}: ${e.message} (got ${JSON.stringify(e.value)})`);
73
+ const errors = [...Value.Errors(schema, data),].map((e) => `${e.path}: ${e.message} (got ${formatInvalidValue(e.value)})`);
24
74
  return { success: false, data: data, errors, };
25
75
  }
26
76
  // ---------------------------------------------------------------------------