@myelinbridge/cli 0.11.1 → 0.12.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 (3) hide show
  1. package/README.md +9 -0
  2. package/bin/myelin.js +30 -0
  3. package/package.json +23 -23
package/README.md CHANGED
@@ -43,6 +43,15 @@ npx @myelinbridge/cli push ./run_042 --dataset onco1-wes --submit
43
43
  every later delivery reconciles against it — a partial delivery (93 of 96) is
44
44
  reported as a state, never as a failure.
45
45
 
46
+ - **Your client's own fields show up, read-only (0.12.0).** Clients can define
47
+ their own metadata fields on datasets (a sponsor study code, a work order, a
48
+ therapeutic area). `contract` prints them under CLIENT FIELDS, and `check`
49
+ tells you when required ones are not filled in yet — informational only:
50
+ their team fills them in Myelin, there is nothing to change in your delivery,
51
+ and metadata never moves the exit code. In `--json`, datasets carry a
52
+ `metadata` object (`{key: {label, type, value}}`) and preflight carries
53
+ `metadata.missing_required`.
54
+
46
55
  - **A missing path in `roles set` is refused, not guessed (0.11.1).** Flags are
47
56
  not positional arguments: `roles set samplesheet --dataset onco1-wes` (path
48
57
  omitted) used to declare the samplesheet at the literal path `--dataset` and
package/bin/myelin.js CHANGED
@@ -17,6 +17,12 @@
17
17
  // cannot validate either without deciding by hand, and hearing "all checks
18
18
  // pass" before uploading is the green-before-sending / red-after trap this
19
19
  // release exists to close.
20
+ //
21
+ // 0.12.0 — clients can define their own fields on datasets (sprint 22).
22
+ // `contract` shows them read-only, and `check` reports the required ones the
23
+ // client has not filled in yet — informational ONLY: metadata never moves the
24
+ // exit code (the client fills these in Myelin; nothing for a partner to fix,
25
+ // and a pipeline must never halt on it).
20
26
 
21
27
  import { readdirSync, statSync, createReadStream, readFileSync } from 'node:fs'
22
28
  import { resolve, join, relative, sep, basename } from 'node:path'
@@ -102,6 +108,11 @@ const VERDICT_LABEL = {
102
108
  const verdictMark = (v) => VERDICT_MARK[v] ?? '?'
103
109
  const verdictLabel = (v) => VERDICT_LABEL[v] ?? v
104
110
 
111
+ // A client field value in human mode (0.12.0). Arrays joined, booleans said
112
+ // in words, everything else printed as-is — never JSON punctuation.
113
+ const fmtFieldValue = (v) =>
114
+ Array.isArray(v) ? v.join(', ') : v === true ? 'yes' : v === false ? 'no' : String(v ?? '—')
115
+
105
116
  // Column widths come from the content. padEnd() alone silently ran a long
106
117
  // value into the next column — a 28-character dataset slug swallowed the
107
118
  // STATUS header's gutter. Pass headers = null for an unheadered list.
@@ -565,6 +576,15 @@ async function cmdContract() {
565
576
  for (const c of manual) out(` · ${c.name}`)
566
577
  out('')
567
578
  }
579
+ // 0.12.0 — the client's own fields on this dataset, read-only (their team
580
+ // writes them in Myelin; the API never accepts them from a partner key).
581
+ const meta = dataset.metadata ?? {}
582
+ const metaKeys = Object.keys(meta)
583
+ if (metaKeys.length > 0) {
584
+ out('CLIENT FIELDS — how your client describes this dataset (read-only)')
585
+ for (const k of metaKeys) out(` · ${meta[k].label}: ${fmtFieldValue(meta[k].value)}`)
586
+ out('')
587
+ }
568
588
  out(`Run "myelin check <dir> --dataset ${dsRef}" to test ${s.checkable_before_upload} of these locally.`)
569
589
  }
570
590
 
@@ -662,6 +682,16 @@ async function cmdCheck() {
662
682
  if (j.must_acknowledge_failures > 0) {
663
683
  out(`${j.must_acknowledge_failures} check(s) your client asked to be told about — nothing to fix; their reviewer records a decision. Not a blocker.`)
664
684
  }
685
+ // 0.12.0 — required client fields not filled in yet. Informational ONLY:
686
+ // their team fills these in Myelin, nothing changes in the delivery, and
687
+ // metadata never moves the exit code (warn, never block — by design).
688
+ const gaps = j.metadata?.missing_required ?? []
689
+ if (gaps.length > 0) {
690
+ out(
691
+ `${gaps.length} field(s) your client asks for on this dataset ${gaps.length === 1 ? 'is' : 'are'} ` +
692
+ `not filled in yet: ${gaps.map((g) => g.label).join(', ')}. Their team fills these in Myelin — not a blocker.`,
693
+ )
694
+ }
665
695
 
666
696
  const k = j.counts
667
697
  // "All checks that run before upload pass" was written when every check
package/package.json CHANGED
@@ -1,23 +1,23 @@
1
- {
2
- "name": "@myelinbridge/cli",
3
- "version": "0.11.1",
4
- "description": "Myelin Partner Ingestion CLI — push R&D data deliveries from a pipeline: preflight against the client's quality rules, resumable upload, submit, track review outcomes.",
5
- "type": "module",
6
- "bin": {
7
- "myelin": "bin/myelin.js"
8
- },
9
- "files": [
10
- "bin/",
11
- "README.md"
12
- ],
13
- "engines": {
14
- "node": ">=20"
15
- },
16
- "keywords": [
17
- "myelin",
18
- "pharma",
19
- "ingestion",
20
- "s3"
21
- ],
22
- "license": "UNLICENSED"
23
- }
1
+ {
2
+ "name": "@myelinbridge/cli",
3
+ "version": "0.12.0",
4
+ "description": "Myelin Partner Ingestion CLI — push R&D data deliveries from a pipeline: preflight against the client's quality rules, resumable upload, submit, track review outcomes.",
5
+ "type": "module",
6
+ "bin": {
7
+ "myelin": "bin/myelin.js"
8
+ },
9
+ "files": [
10
+ "bin/",
11
+ "README.md"
12
+ ],
13
+ "engines": {
14
+ "node": ">=20"
15
+ },
16
+ "keywords": [
17
+ "myelin",
18
+ "pharma",
19
+ "ingestion",
20
+ "s3"
21
+ ],
22
+ "license": "UNLICENSED"
23
+ }