From 27edd37bbf58f87596edb901670caac1372cc3dc Mon Sep 17 00:00:00 2001 From: Elena Erokhina Date: Mon, 24 Aug 2026 16:41:17 +0200 Subject: [PATCH 1/4] MILAB-6720: pass the column-profile separator by name, not as a tab Loading a TSV failed on server deployments with `TypeError: "delimiter" must be a 1-character string` while the same file loaded on a desktop backend. The block passed a real tab as an argv element. Desktop runners exec argv directly, so the tab arrived intact; the k8s and google-batch runners serialise the command with Go's %q and re-run it through `sh -c`, where the tab has already become the two characters \ and t and stays that way. Prerun now sends "tab" or "comma" and main.py maps the name back to the character, so only plain words cross the runner boundary. A separator that still arrives malformed fails with a message naming the accepted values rather than a TypeError. --- .changeset/separator-name-not-character.md | 21 ++++++++++++++++++ software/column-profile/src/main.py | 25 ++++++++++++++++++++-- workflow/src/prerun.tpl.tengo | 7 +++++- workflow/src/profile-columns.tpl.tengo | 2 ++ 4 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 .changeset/separator-name-not-character.md diff --git a/.changeset/separator-name-not-character.md b/.changeset/separator-name-not-character.md new file mode 100644 index 0000000..ec3aa30 --- /dev/null +++ b/.changeset/separator-name-not-character.md @@ -0,0 +1,21 @@ +--- +'@platforma-open/milaboratories.import-vdj.workflow': patch +'@platforma-open/milaboratories.import-vdj.column-profile': patch +'@platforma-open/milaboratories.import-vdj': patch +--- + +Pass the column-profile separator by name, not as a tab character + +Loading a TSV failed on server deployments with `TypeError: "delimiter" must be a 1-character +string`, while the same file loaded on a desktop backend. The block was passing a real tab as an +argv element. Desktop runners exec argv directly, so the tab arrived intact; the k8s and +google-batch runners serialise the command with Go's `%q` and re-run it through `sh -c`, where +the tab has already become the two characters `\` and `t` and stays that way. `csv.reader` +rejects a two-character delimiter. + +Prerun now sends `tab` or `comma` and `main.py` maps the name back to the character, so only +plain words cross the runner boundary. A separator that still arrives malformed now fails with a +message naming the accepted values rather than a `TypeError`. + +The underlying quoting is a backend issue and is unfixed: `toShellCmd` in `util/k8s/template.go` +uses Go quoting where POSIX shell quoting is needed. diff --git a/software/column-profile/src/main.py b/software/column-profile/src/main.py index cda42ec..ad20cd9 100644 --- a/software/column-profile/src/main.py +++ b/software/column-profile/src/main.py @@ -55,6 +55,23 @@ def value_type(value: str) -> int: return T_DOUBLE +# The workflow passes a name rather than the character. On the k8s and google-batch runners the +# backend serialises argv with Go's %q and re-runs it through `sh -c`: a real tab arrives here as +# the two characters \ and t, which csv.reader rejects outright. A plain word survives that +# round-trip, so the name is what crosses the boundary and the character is chosen here. +SEPARATOR_NAMES = {"tab": "\t", "comma": ",", "semicolon": ";"} + + +def resolve_separator(separator: str) -> str: + resolved = SEPARATOR_NAMES.get(separator, separator) + if len(resolved) != 1: + raise SystemExit( + f"--separator must be one of {sorted(SEPARATOR_NAMES)} or a single character," + f" got {separator!r}" + ) + return resolved + + def profile(path: str, separator: str) -> dict: with open(path, newline="", encoding="utf-8-sig") as f: reader = csv.reader(f, delimiter=separator) @@ -97,11 +114,15 @@ def profile(path: str, separator: str) -> dict: def main() -> None: p = argparse.ArgumentParser(description="Profile a csv/tsv's columns") p.add_argument("--input", required=True, help="Input csv or tsv") - p.add_argument("--separator", required=True, help="Field separator") + p.add_argument( + "--separator", + required=True, + help='Field separator: a name ("tab", "comma", "semicolon") or the character itself', + ) p.add_argument("--output", required=True, help="Output JSON") args = p.parse_args() - result = profile(args.input, args.separator) + result = profile(args.input, resolve_separator(args.separator)) with open(args.output, "w") as f: json.dump(result, f, sort_keys=True) diff --git a/workflow/src/prerun.tpl.tengo b/workflow/src/prerun.tpl.tengo index 9886a21..11b9cbf 100644 --- a/workflow/src/prerun.tpl.tengo +++ b/workflow/src/prerun.tpl.tengo @@ -29,7 +29,12 @@ wf.body(func(args) { // The mapping dropdowns need the file's headers, and on this door nothing upstream // supplies them. The separator comes from what the UI read out of the file's own first // line rather than from the filename, which may not match the content. - separator := readable.extension == "csv" ? "," : "\t" + // + // A name, not the character itself: on the k8s and google-batch runners the backend + // serialises argv with Go's %q and re-runs it through `sh -c`, which turns a real tab + // into the two characters \t and leaves them that way. Only plain words survive that + // round-trip intact. profile-columns maps the name back. + separator := readable.extension == "csv" ? "comma" : "tab" // The whole file, not a head: the panel needs each column's value type and whether it // holds amino-acid domains, and both are wrong if taken from a sample. See // profile-columns. diff --git a/workflow/src/profile-columns.tpl.tengo b/workflow/src/profile-columns.tpl.tengo index 0a031be..8fc9248 100644 --- a/workflow/src/profile-columns.tpl.tengo +++ b/workflow/src/profile-columns.tpl.tengo @@ -21,6 +21,8 @@ self.defineOutputs("profile") self.body(func(inputs) { ll.assert(inputs.file != undefined, "profile-columns: file is required") + // A name — "tab" or "comma" — not the character. See prerun: a real tab does not survive + // the `sh -c` round-trip the k8s runner puts argv through. main.py maps the name back. ll.assert(inputs.separator != undefined, "profile-columns: separator is required") cmd := exec.builder(). From 48c194eda30178c4e8bf2636cfaa186780f07e79 Mon Sep 17 00:00:00 2001 From: Elena Erokhina Date: Mon, 24 Aug 2026 17:22:45 +0200 Subject: [PATCH 2/4] chore: build software through block-tools instead of pl-pkg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pl-pkg build ignores PL_BUILD_CHANNEL/VARIANT/LOCATION and defaults docker image builds to CI-only, so a local build:dev-remote produced binary-only descriptors. A block built that way cannot run on a k8s deployment, which launches containers exclusively. block-tools software build honours those variables — variant all builds the images, location remote pushes them — matching tcr-disco and the other already-migrated software packages. PL_PKG_DEV drops out of the root scripts and turbo.json, since PL_BUILD_LOCATION now carries its meaning. --- .changeset/software-build-via-block-tools.md | 23 ++++++++++++++++ package.json | 4 +-- pnpm-lock.yaml | 29 ++++---------------- software/column-profile/package.json | 9 +++--- software/region-annotation/package.json | 9 +++--- software/xlsx-to-csv/package.json | 9 +++--- turbo.json | 1 - 7 files changed, 43 insertions(+), 41 deletions(-) create mode 100644 .changeset/software-build-via-block-tools.md diff --git a/.changeset/software-build-via-block-tools.md b/.changeset/software-build-via-block-tools.md new file mode 100644 index 0000000..bff4ec9 --- /dev/null +++ b/.changeset/software-build-via-block-tools.md @@ -0,0 +1,23 @@ +--- +'@platforma-open/milaboratories.import-vdj.column-profile': patch +'@platforma-open/milaboratories.import-vdj.region-annotation': patch +'@platforma-open/milaboratories.import-vdj.xlsx-to-csv': patch +'@platforma-open/milaboratories.import-vdj': patch +--- + +Build software through block-tools so dev builds produce docker images + +The three software packages called `pl-pkg build` directly, which ignores +`PL_BUILD_CHANNEL` / `PL_BUILD_VARIANT` / `PL_BUILD_LOCATION` and defaults docker +image builds to CI-only. A local `build:dev-remote` therefore emitted binary-only +descriptors, and a block built that way cannot run on a k8s deployment at all — +that runner launches containers exclusively and rejects a command with no image +as "docker is not set". + +They now use `block-tools software build`, which honours those variables: variant +`all` builds the images and location `remote` pushes them, the same way +tcr-disco and the other 23 already-migrated software packages work. `PL_PKG_DEV` +drops out of the root scripts and `turbo.json`, since `PL_BUILD_LOCATION` carries +what it used to say. + +No change to what the software does — only to how it is built. diff --git a/package.json b/package.json index 0c9b6c0..a9901f2 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "index.js" ], "scripts": { - "test": "env PL_PKG_DEV=local PL_BUILD_CHANNEL=dev PL_BUILD_VARIANT=binary PL_BUILD_LOCATION=local turbo run test --concurrency 1", + "test": "env PL_BUILD_CHANNEL=dev PL_BUILD_VARIANT=binary PL_BUILD_LOCATION=local turbo run test --concurrency 1", "test:dry-run": "env PL_BUILD_CHANNEL=dev PL_BUILD_VARIANT=binary PL_BUILD_LOCATION=local turbo run test --dry-run=json", "mark-stable": "turbo run mark-stable", "watch": "turbo watch build", @@ -15,7 +15,7 @@ "check": "turbo run check", "do-pack": "turbo run do-pack", "upgrade-sdk": "block-tools structure refresh --update-deps-only && pnpm i && block-tools structure refresh && pnpm i && pnpm fmt", - "build:dev-local": "env PL_PKG_DEV=local PL_BUILD_CHANNEL=dev PL_BUILD_VARIANT=all PL_BUILD_LOCATION=local turbo run build", + "build:dev-local": "env PL_BUILD_CHANNEL=dev PL_BUILD_VARIANT=all PL_BUILD_LOCATION=local turbo run build", "build:dev-remote": "env PL_BUILD_CHANNEL=dev PL_BUILD_VARIANT=all PL_BUILD_LOCATION=remote turbo run build", "build:dev-no-software": "env PL_BUILD_CHANNEL=dev PL_BUILD_VARIANT=none turbo run build", "build:dev-binary-existing": "env PL_BUILD_CHANNEL=dev PL_BUILD_USE_PUBLISHED=true turbo run build", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6ff0e3d..6b30145 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,9 +36,6 @@ catalogs: '@platforma-sdk/model': specifier: 1.81.1 version: 1.81.1 - '@platforma-sdk/package-builder': - specifier: 3.15.0 - version: 3.15.0 '@platforma-sdk/tengo-builder': specifier: 4.0.22 version: 4.0.22 @@ -157,27 +154,27 @@ importers: '@platforma-open/milaboratories.runenv-python-3': specifier: 'catalog:' version: 1.11.6 - '@platforma-sdk/package-builder': + '@platforma-sdk/block-tools': specifier: 'catalog:' - version: 3.15.0 + version: 2.14.3(@types/node@25.0.1) software/region-annotation: devDependencies: '@platforma-open/milaboratories.runenv-python-3': specifier: 'catalog:' version: 1.11.6 - '@platforma-sdk/package-builder': + '@platforma-sdk/block-tools': specifier: 'catalog:' - version: 3.15.0 + version: 2.14.3(@types/node@25.0.1) software/xlsx-to-csv: devDependencies: '@platforma-open/milaboratories.runenv-python-3': specifier: 'catalog:' version: 1.11.6 - '@platforma-sdk/package-builder': + '@platforma-sdk/block-tools': specifier: 'catalog:' - version: 3.15.0 + version: 2.14.3(@types/node@25.0.1) test: dependencies: @@ -1729,10 +1726,6 @@ packages: '@platforma-sdk/package-builder-lib@1.3.0': resolution: {integrity: sha512-CdBjmNo6E1fBxKYWaXa49L/L2WLURxs2f1TAqxLIZlHRE4DZ6E1TEj3jNNKESWp+/9rwtLkTAzmTzNPrDgz+2Q==} - '@platforma-sdk/package-builder@3.15.0': - resolution: {integrity: sha512-YzRiBYAaKvwnUcJgl6JMB3XLJuhlH72L8RZE3CDt2GM8hYRH4zaDzomfC5IHYNodK63RMaduzcvE10ICruI1hQ==} - hasBin: true - '@platforma-sdk/tengo-builder@4.0.22': resolution: {integrity: sha512-8+zDYDFFI2tQS7dplTcxgQdUwzt8+IO++sJiVbwBgwSg1Giyc2qMThEYPLK3QNFArgCsIDR6wQuS8t66pJsRPQ==} engines: {node: '>=22'} @@ -9025,16 +9018,6 @@ snapshots: - bare-abort-controller - react-native-b4a - '@platforma-sdk/package-builder@3.15.0': - dependencies: - '@platforma-sdk/package-builder-lib': 1.3.0 - commander: 15.0.0 - winston: 3.19.0 - transitivePeerDependencies: - - aws-crt - - bare-abort-controller - - react-native-b4a - '@platforma-sdk/tengo-builder@4.0.22': dependencies: '@milaboratories/pl-model-backend': 1.4.20 diff --git a/software/column-profile/package.json b/software/column-profile/package.json index 4c68c93..ea25a36 100644 --- a/software/column-profile/package.json +++ b/software/column-profile/package.json @@ -3,9 +3,8 @@ "version": "1.1.0", "description": "Profile a csv/tsv's columns: value type and whether they hold amino-acid variable domains", "scripts": { - "build": "pl-pkg build", - "prepublishOnly": "pl-pkg prepublish", - "do-pack": "rm -f *.tgz && pl-pkg build && pnpm pack && mv platforma-open*.tgz package.tgz", + "build": "block-tools software build", + "do-pack": "shx rm -f *.tgz && block-tools software build && pnpm pack && shx mv platforma-open*.tgz package.tgz", "changeset": "changeset", "version-packages": "changeset version" }, @@ -14,8 +13,8 @@ ], "dependencies": {}, "devDependencies": { - "@platforma-sdk/package-builder": "catalog:", - "@platforma-open/milaboratories.runenv-python-3": "catalog:" + "@platforma-open/milaboratories.runenv-python-3": "catalog:", + "@platforma-sdk/block-tools": "catalog:" }, "block-software": { "entrypoints": { diff --git a/software/region-annotation/package.json b/software/region-annotation/package.json index 01da688..054286f 100644 --- a/software/region-annotation/package.json +++ b/software/region-annotation/package.json @@ -3,9 +3,8 @@ "version": "1.1.0", "description": "Locate FR/CDR region boundaries in amino-acid antibody variable domains from ANARCI numbering", "scripts": { - "build": "pl-pkg build", - "prepublishOnly": "pl-pkg prepublish", - "do-pack": "rm -f *.tgz && pl-pkg build && pnpm pack && mv platforma-open*.tgz package.tgz", + "build": "block-tools software build", + "do-pack": "shx rm -f *.tgz && block-tools software build && pnpm pack && shx mv platforma-open*.tgz package.tgz", "changeset": "changeset", "version-packages": "changeset version" }, @@ -14,8 +13,8 @@ ], "dependencies": {}, "devDependencies": { - "@platforma-sdk/package-builder": "catalog:", - "@platforma-open/milaboratories.runenv-python-3": "catalog:" + "@platforma-open/milaboratories.runenv-python-3": "catalog:", + "@platforma-sdk/block-tools": "catalog:" }, "block-software": { "entrypoints": { diff --git a/software/xlsx-to-csv/package.json b/software/xlsx-to-csv/package.json index c0df691..7c70380 100644 --- a/software/xlsx-to-csv/package.json +++ b/software/xlsx-to-csv/package.json @@ -3,9 +3,8 @@ "version": "1.1.0", "description": "Convert the first worksheet of a workbook to CSV so the pipeline only ever sees csv/tsv", "scripts": { - "build": "pl-pkg build", - "prepublishOnly": "pl-pkg prepublish", - "do-pack": "rm -f *.tgz && pl-pkg build && pnpm pack && mv platforma-open*.tgz package.tgz", + "build": "block-tools software build", + "do-pack": "shx rm -f *.tgz && block-tools software build && pnpm pack && shx mv platforma-open*.tgz package.tgz", "changeset": "changeset", "version-packages": "changeset version" }, @@ -14,8 +13,8 @@ ], "dependencies": {}, "devDependencies": { - "@platforma-sdk/package-builder": "catalog:", - "@platforma-open/milaboratories.runenv-python-3": "catalog:" + "@platforma-open/milaboratories.runenv-python-3": "catalog:", + "@platforma-sdk/block-tools": "catalog:" }, "block-software": { "entrypoints": { diff --git a/turbo.json b/turbo.json index ffeb950..d079cd3 100644 --- a/turbo.json +++ b/turbo.json @@ -14,7 +14,6 @@ "inputs": ["$TURBO_DEFAULT$"], "env": [ "PL_DOCKER_REGISTRY_PUSH_TO", - "PL_PKG_DEV", "PL_BUILD_CHANNEL", "PL_BUILD_VARIANT", "PL_BUILD_LOCATION", From c546f5284fd31cb4b7bde91b058ea08aa041875d Mon Sep 17 00:00:00 2001 From: Elena Erokhina Date: Mon, 24 Aug 2026 18:13:01 +0200 Subject: [PATCH 3/4] MILAB-6720: move to software-anarci 1.0.1 for its docker entrypoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Region annotation failed on k8s with "ANARCI: not found" (127). The conda image exposes its env only via ENTRYPOINT ["micromamba", "run", "--prefix", "/conda-env"], a k8s pod spec overrides the image entrypoint, and every software-anarci up to 1.0.0 records docker.entrypoint: [] — so nothing re-applied the wrapper. 1.0.1 was built by a package-builder that reads .Config.Entrypoint back from the image, so the runner can reconstruct it. ^0.0.3 is exact for a 0.0.x range, so the pin never picked the fix up. --- .changeset/anarci-with-docker-entrypoint.md | 23 +++++++++++++++++++++ pnpm-lock.yaml | 12 +++++------ pnpm-workspace.yaml | 2 +- 3 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 .changeset/anarci-with-docker-entrypoint.md diff --git a/.changeset/anarci-with-docker-entrypoint.md b/.changeset/anarci-with-docker-entrypoint.md new file mode 100644 index 0000000..65070d5 --- /dev/null +++ b/.changeset/anarci-with-docker-entrypoint.md @@ -0,0 +1,23 @@ +--- +'@platforma-open/milaboratories.import-vdj.workflow': patch +'@platforma-open/milaboratories.import-vdj': patch +--- + +Move to software-anarci 1.0.1, which records its docker entrypoint + +Region annotation failed on k8s deployments with `sh: 1: ANARCI: not found` +(exit 127). The conda image puts its environment on PATH solely through +`ENTRYPOINT ["micromamba", "run", "--prefix", "/conda-env"]`, and a k8s pod spec +overrides the image entrypoint — so the runner has to re-apply it from the +software descriptor. Every software-anarci up to 1.0.0 records +`docker.entrypoint: []`, because the package-builder that published them did not +read the built image's entrypoint back. Nothing re-applied the wrapper, ANARCI +was never on PATH, and the step died before it started. + +1.0.1 was rebuilt with a package-builder that reads `.Config.Entrypoint` from the +image, so its descriptor carries the micromamba wrapper and the k8s runner +reconstructs the right command. `^0.0.3` is exact for a 0.0.x range, so the pin +could never pick the fix up on its own. + +No ANARCI behaviour changes between these versions — 1.0.0 was a plain release +and 1.0.1 was "update build deps". diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6b30145..548f083 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28,8 +28,8 @@ catalogs: specifier: 1.5.2 version: 1.5.2 '@platforma-open/milaboratories.software-anarci': - specifier: ^0.0.3 - version: 0.0.3 + specifier: ^1.0.1 + version: 1.0.1 '@platforma-sdk/block-tools': specifier: 2.14.3 version: 2.14.3 @@ -257,7 +257,7 @@ importers: version: link:../software/xlsx-to-csv '@platforma-open/milaboratories.software-anarci': specifier: 'catalog:' - version: 0.0.3 + version: 1.0.1 '@platforma-sdk/workflow-tengo': specifier: 'catalog:' version: 6.8.2 @@ -1666,8 +1666,8 @@ packages: '@platforma-open/milaboratories.sequence-properties@1.5.2': resolution: {integrity: sha512-RsLYUzUbZbGcjpNSOV5xOzeqvITQsdAjlcKW9z/nwuvNCJXS3tnSQy9Z5s7PvDKyx1Q6POwGyEGwYv1AQY371w==} - '@platforma-open/milaboratories.software-anarci@0.0.3': - resolution: {integrity: sha512-BtzWsu32K/V7Sw3uCS/lzkILoI+JVHYl7mE3PNf0UEj1ZImjlRFuMFbo/t8LpywYTAGdUIwR9cu2i6ayq/hDGQ==} + '@platforma-open/milaboratories.software-anarci@1.0.1': + resolution: {integrity: sha512-Y86dkacjjC/z+NnSUdKBTPfaQ/5lQx9MTH/K7sBynUMthwwfeSyk3UciMni7OVX2Tk7bWgtQiCpsbmecgl1cNA==} '@platforma-open/milaboratories.software-ptabler.schema@1.15.15': resolution: {integrity: sha512-zvPuRZgQyxjED+txJVgWHUOPeRp4TG1jOrJOtuw9WnwxFiHNjQHIB+Xe1j8f6skgMqZgRSQvEbhRvqbWjGmhKQ==} @@ -8882,7 +8882,7 @@ snapshots: - vitest - vue - '@platforma-open/milaboratories.software-anarci@0.0.3': {} + '@platforma-open/milaboratories.software-anarci@1.0.1': {} '@platforma-open/milaboratories.software-ptabler.schema@1.15.15': dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index c866dfa..6e1128f 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -28,7 +28,7 @@ catalog: # than introduced here, per the spec's requirement that the instrument already exist # in the workspace. Versions follow blocks/redefine-clonotypes, its other consumer. "@platforma-open/milaboratories.runenv-python-3": ^1.1.16 - "@platforma-open/milaboratories.software-anarci": ^0.0.3 + "@platforma-open/milaboratories.software-anarci": ^1.0.1 "vue": 3.5.24 From c7ca7985362f0aeac420ea69d23c4bf085801013 Mon Sep 17 00:00:00 2001 From: Elena Erokhina Date: Mon, 24 Aug 2026 19:01:47 +0200 Subject: [PATCH 4/4] chore: set type=module on the software packages Part of the canonical software-module shape that block-tools structure applies (N("type","module")), and what every already-migrated software package carries. Missed in the block-tools build migration. --- software/column-profile/package.json | 1 + software/region-annotation/package.json | 1 + software/xlsx-to-csv/package.json | 1 + 3 files changed, 3 insertions(+) diff --git a/software/column-profile/package.json b/software/column-profile/package.json index ea25a36..9d7bf39 100644 --- a/software/column-profile/package.json +++ b/software/column-profile/package.json @@ -2,6 +2,7 @@ "name": "@platforma-open/milaboratories.import-vdj.column-profile", "version": "1.1.0", "description": "Profile a csv/tsv's columns: value type and whether they hold amino-acid variable domains", + "type": "module", "scripts": { "build": "block-tools software build", "do-pack": "shx rm -f *.tgz && block-tools software build && pnpm pack && shx mv platforma-open*.tgz package.tgz", diff --git a/software/region-annotation/package.json b/software/region-annotation/package.json index 054286f..4af3af1 100644 --- a/software/region-annotation/package.json +++ b/software/region-annotation/package.json @@ -2,6 +2,7 @@ "name": "@platforma-open/milaboratories.import-vdj.region-annotation", "version": "1.1.0", "description": "Locate FR/CDR region boundaries in amino-acid antibody variable domains from ANARCI numbering", + "type": "module", "scripts": { "build": "block-tools software build", "do-pack": "shx rm -f *.tgz && block-tools software build && pnpm pack && shx mv platforma-open*.tgz package.tgz", diff --git a/software/xlsx-to-csv/package.json b/software/xlsx-to-csv/package.json index 7c70380..cc47dec 100644 --- a/software/xlsx-to-csv/package.json +++ b/software/xlsx-to-csv/package.json @@ -2,6 +2,7 @@ "name": "@platforma-open/milaboratories.import-vdj.xlsx-to-csv", "version": "1.1.0", "description": "Convert the first worksheet of a workbook to CSV so the pipeline only ever sees csv/tsv", + "type": "module", "scripts": { "build": "block-tools software build", "do-pack": "shx rm -f *.tgz && block-tools software build && pnpm pack && shx mv platforma-open*.tgz package.tgz",