datagrok-tools 6.4.2 → 6.4.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Datagrok-tools changelog
2
2
 
3
+ ## 6.4.4 (2026-06-22)
4
+
5
+ * `grok publish` — fixed every publish failing with a silent `exit 1` after a successful upload: a stray `fs.unlinkSync('zip')` threw `ENOENT` (the archive is streamed in-memory, no `zip` file is ever written), and the surrounding `catch` only logged under `--verbose`. The errant unlink is removed and publish errors are now always surfaced.
6
+
7
+ ## 6.4.3 (2026-06-22)
8
+
9
+ * `grok api` — numeric IVP model inputs are now generated with `nullable: false`, so an emptied input field fails form validation instead of running the solver with a null.
10
+
3
11
  ## 6.4.2 (2026-06-18)
4
12
 
5
13
  * `grok publish` — registry-aware Docker fallback: when a package's image isn't built locally and the target server has no compatible record, `grok publish` now checks the configured registry and Docker Hub (`docker manifest inspect`) for the expected `datagrok/<name>:<version>` (and content-hashed) tag and uses it, instead of reporting "No fallback available" and failing. Fixes dependency publishes (e.g. Bio → @datagrok/chem) on CI runners where the image exists in the registry but not locally.
@@ -457,7 +457,7 @@ async function processPackage(debug, rebuild, host, devKey, packageName, dropDb,
457
457
  }
458
458
  if (debug) timestamps = checkData;
459
459
  } catch (error) {
460
- if (utils.isConnectivityError(error)) color.error(`Server is possibly offline: ${host}`);
460
+ color.error(utils.isConnectivityError(error) ? `Server is possibly offline: ${host}` : `Failed to validate package on ${host}: ${error?.message ?? error}`);
461
461
  if (color.isVerbose()) console.error(error);
462
462
  return 1;
463
463
  }
@@ -582,7 +582,6 @@ async function processPackage(debug, rebuild, host, devKey, packageName, dropDb,
582
582
  body: zipBuffer
583
583
  });
584
584
  const log = JSON.parse(await body.text());
585
- _fs.default.unlinkSync('zip');
586
585
  if (log != undefined) {
587
586
  if (log['#type'] === 'ApiError') {
588
587
  color.error(log['message']);
@@ -595,7 +594,7 @@ async function processPackage(debug, rebuild, host, devKey, packageName, dropDb,
595
594
  }
596
595
  }
597
596
  } catch (error) {
598
- if (utils.isConnectivityError(error)) color.error(`Server is possibly offline: ${url}`);
597
+ color.error(utils.isConnectivityError(error) ? `Server is possibly offline: ${url}` : `Publish failed: ${error?.message ?? error}`);
599
598
  if (color.isVerbose()) console.error(error);
600
599
  return 1;
601
600
  }
@@ -157,7 +157,13 @@ async function runPlaywrightTests(pkgDir, testDir, args, hostKey) {
157
157
  const candidate = _path.default.join(testDir, args.category);
158
158
  if (_fs.default.existsSync(candidate)) testDirFinal = candidate;
159
159
  }
160
- if (testDirFinal !== testDir) cliArgs.push(testDirFinal);
160
+ if (testDirFinal !== testDir)
161
+ // Normalize Windows backslashes to forward slashes — Playwright CLI on Windows
162
+ // treats backslash positional args as regex patterns and emits "No tests found"
163
+ // when the resolved path contains backslashes. Linux path.join already emits
164
+ // forward slashes; this no-ops there. Per
165
+ // .claude/plan/investigator-handback-autocomplete-no-tests-2026-05-24.md.
166
+ cliArgs.push(testDirFinal.replace(/\\/g, '/'));
161
167
  const env = {
162
168
  ...process.env,
163
169
  DATAGROK_URL: webUrl,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datagrok-tools",
3
- "version": "6.4.2",
3
+ "version": "6.4.4",
4
4
  "description": "Utility to upload and publish packages to Datagrok",
5
5
  "homepage": "https://github.com/datagrok-ai/public/tree/master/tools#readme",
6
6
  "dependencies": {
@@ -51,9 +51,19 @@ function preparseIvpModel(parser, text) {
51
51
  // Input names use the script-form names (arg bounds/step `_`-prefixed, loop count `_count`) so the
52
52
  // run path, the diff-grok fitting/SA pipeline, and `propagateChoice` lookups all agree on one set
53
53
  // of names. `scriptKey` mirrors `name`; it is kept only for the value-forwarding map below.
54
+ // Numeric IVP inputs are always required: mark them `nullable: false` so an emptied field fails
55
+ // form validation instead of running with a null (which throws in the solver).
56
+ const withNullable = (annot) => {
57
+ const a = (annot ?? '').trim();
58
+ if (!a.startsWith('{')) return '{nullable: false}'; // no options block
59
+ if (/[{;\s]nullable\s*:/.test(a)) return a; // already declares nullable (any value)
60
+ if (/^\{\s*\}$/.test(a)) return '{nullable: false}'; // empty {}
61
+ return `{nullable: false; ${a.slice(1).trimStart()}`; // everything after '{' untouched
62
+ };
63
+
54
64
  const mk = (type, name, scriptKey, input) =>
55
65
  ({tsType: 'number', name, scriptKey,
56
- annotation: `//input: ${type} ${name} = ${input.value} ${input.annot ?? ''}`.trim()});
66
+ annotation: `//input: ${type} ${name} = ${input.value} ${withNullable(input.annot)}`.trim()});
57
67
 
58
68
  const inputs = [];
59
69
  const a = ivp.arg.name;