@cosyte/cli 0.0.5 → 0.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.
- package/CHANGELOG.md +416 -0
- package/README.md +111 -45
- package/dist/bin/cosyte-mcp.cjs +461 -106
- package/dist/bin/cosyte-mcp.cjs.map +1 -1
- package/dist/bin/cosyte-mcp.mjs +461 -106
- package/dist/bin/cosyte-mcp.mjs.map +1 -1
- package/dist/bin/cosyte.cjs +824 -140
- package/dist/bin/cosyte.cjs.map +1 -1
- package/dist/bin/cosyte.mjs +825 -141
- package/dist/bin/cosyte.mjs.map +1 -1
- package/dist/index.cjs +592 -102
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +515 -281
- package/dist/index.d.ts +515 -281
- package/dist/index.mjs +574 -104
- package/dist/index.mjs.map +1 -1
- package/dist/io-C9bSG2zF.d.cts +381 -0
- package/dist/io-C9bSG2zF.d.ts +381 -0
- package/dist/mcp.cjs +435 -103
- package/dist/mcp.cjs.map +1 -1
- package/dist/mcp.d.cts +70 -9
- package/dist/mcp.d.ts +70 -9
- package/dist/mcp.mjs +435 -103
- package/dist/mcp.mjs.map +1 -1
- package/package.json +61 -37
- package/dist/io-B2EobRzC.d.cts +0 -57
- package/dist/io-B2EobRzC.d.ts +0 -57
package/README.md
CHANGED
|
@@ -48,19 +48,17 @@ releases, not a fault in any command.
|
|
|
48
48
|
sibling packages are now declared as real npm ranges, and the resulting tarball has been installed from
|
|
49
49
|
outside this repository and exercised, which is the check a `npm publish --dry-run` cannot perform.
|
|
50
50
|
|
|
51
|
-
**
|
|
52
|
-
npm
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
> **Status:** pre-alpha (`0.0.x`). `0.0.1` and `0.0.2` are on npm and **cannot be installed** (see
|
|
63
|
-
> above); a later version fixes that. The `cosyte` command wraps **all eight
|
|
51
|
+
**FHIR support arrives through a peer, not a declared dependency.** `@cosyte/fhir` is not in this
|
|
52
|
+
package's manifest. `npm install` brings it in as the peer dependency of `@cosyte/transform`, one of
|
|
53
|
+
this package's optional dependencies, and the FHIR `parse` / `inspect` / `fmt` / `validate` commands
|
|
54
|
+
and `convert` use that copy. If your package manager skips optional dependencies or does not install
|
|
55
|
+
peers, a command whose library is missing reports a value-free `CLI_PARSER_UNAVAILABLE` and exits
|
|
56
|
+
`69`: it never guesses, and it never blames your input. HL7 v2 and `map-codes` run on the two hard
|
|
57
|
+
dependencies, `@cosyte/hl7` and `@cosyte/terminology`, and always work.
|
|
58
|
+
|
|
59
|
+
> **Status:** `0.1`. While the package is below 1.0, a breaking change ships in a minor version and is
|
|
60
|
+
> called out in the changelog. `0.0.1` and `0.0.2` are on npm and **cannot be installed** (see above);
|
|
61
|
+
> every later version installs. The `cosyte` command wraps **all eight
|
|
64
62
|
> cosyte formats** (**HL7 v2**, **FHIR R4**, **X12**, **ASTM**, **NCPDP SCRIPT**, **C-CDA**, **DICOM**,
|
|
65
63
|
> and **MLLP**) plus the `@cosyte/transform` and `@cosyte/terminology` higher-layer libraries, with
|
|
66
64
|
> conservative content-format autodetection and a documented exit-code contract:
|
|
@@ -77,8 +75,9 @@ invoke `dist/bin/cosyte.mjs`), where the FHIR library is supplied locally.
|
|
|
77
75
|
> free issues on stderr, and a non-zero exit on an error-severity conversion issue.
|
|
78
76
|
> - **`map-codes`**: translate a code through a BYO FHIR ConceptMap via `@cosyte/terminology`; the
|
|
79
77
|
> target coding(s) on stdout, or a value-free unmapped signal + exit `1`.
|
|
80
|
-
> - **`redact` / `deid`**:
|
|
81
|
-
> `@cosyte/deid
|
|
78
|
+
> - **`redact` / `deid`**: a de-identified copy on stdout for `ccda`, `fhir`, `hl7`, `x12`, delegated
|
|
79
|
+
> whole to `@cosyte/deid`, with that library's value-free manifest on stderr; every other format is a
|
|
80
|
+
> typed refusal and it never emits a partial scrub dressed up as de-identified.
|
|
82
81
|
> - **`completion <bash|zsh|fish>`**: print a static shell completion script.
|
|
83
82
|
>
|
|
84
83
|
> **Support is honest per (format, operation)**: not every parser faithfully supports every command, so
|
|
@@ -94,20 +93,22 @@ invoke `dist/bin/cosyte.mjs`), where the FHIR library is supplied locally.
|
|
|
94
93
|
> described above, which is why `0.0.1` and `0.0.2` published green and still cannot be installed: a
|
|
95
94
|
> dry-run builds the tarball but never resolves it from a registry. **That swap has now been made**,
|
|
96
95
|
> and installing the packed tarball from outside the repository is a release step in its own right.
|
|
97
|
-
> `@cosyte/fhir`
|
|
98
|
-
>
|
|
96
|
+
> `@cosyte/fhir` reaches an installed copy as a peer of `@cosyte/transform` (see above). See
|
|
97
|
+
> [RELEASING.md](./RELEASING.md).
|
|
99
98
|
|
|
100
99
|
## Run it
|
|
101
100
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
> packaging defect is fixed in this repository and proven by installing the packed tarball outside it,
|
|
105
|
-
> but a published version is immutable, so the fix reaches you only in the next release. Until then,
|
|
106
|
-
> run it from a source checkout: `pnpm install && pnpm build`, then invoke `dist/bin/cosyte.mjs`.
|
|
101
|
+
Requires Node `>=22.0.0 <26.0.0`. This block runs as-is in an empty directory: it installs the CLI,
|
|
102
|
+
writes a short synthetic HL7 v2 message, and reads it back.
|
|
107
103
|
|
|
108
104
|
```bash
|
|
109
105
|
npm install -g @cosyte/cli # put `cosyte` on your PATH
|
|
110
|
-
|
|
106
|
+
|
|
107
|
+
# A synthetic ADT^A01 admit. HL7 v2 ends every segment with a carriage return (\r).
|
|
108
|
+
printf 'MSH|^~\\&|SENDINGAPP|SENDINGFAC|RECEIVINGAPP|RECEIVINGFAC|20240101120000||ADT^A01|MSG00001|P|2.5\rEVN|A01|20240101120000\rPID|1||MRN-000123^^^HOSP^MR||ZZSENTINELLAST^ZZSENTINELFIRST^M||19800101|M\rPV1|1|I|WARD^101^A\r' > message.hl7
|
|
109
|
+
|
|
110
|
+
cosyte parse message.hl7 # format autodetected → HL7 v2, typed JSON on stdout
|
|
111
|
+
cosyte inspect message.hl7 # a value-free summary: type, version, segment counts
|
|
111
112
|
```
|
|
112
113
|
|
|
113
114
|
Or without installing, using `npx`:
|
|
@@ -146,7 +147,15 @@ astm | ncpdp | ccda | dicom | mllp`.
|
|
|
146
147
|
**MLLP** stream, one record per frame, or any input under **`--ndjson`**, one record per non-empty
|
|
147
148
|
line) streams as **NDJSON**, one `{ record, format, model, warnings }` line each, with per-record
|
|
148
149
|
isolation: a record that fails to parse becomes a value-free `{ record, error }` line and the stream
|
|
149
|
-
continues; the overall exit is a data error (`65`) if any record failed.
|
|
150
|
+
continues; the overall exit is a data error (`65`) if any record failed. Each line is written **as
|
|
151
|
+
its record is parsed**, before the rest of the input has been read, so a batch pipes straight into
|
|
152
|
+
the next process.
|
|
153
|
+
|
|
154
|
+
**Input size.** `parse` reads at most **67108864 bytes (64 MiB)** per invocation, the number
|
|
155
|
+
`cosyte --help` prints. A larger input is a value-free `CLI_INPUT_TOO_LARGE` refusal naming that
|
|
156
|
+
limit, with the data-error exit code (`65`) and never the internal-error code: split the input and
|
|
157
|
+
re-run. Since records are emitted as they are parsed, a refusal can land after some records have
|
|
158
|
+
already reached stdout; the exit code, not the output, says the run did not complete.
|
|
150
159
|
|
|
151
160
|
Support is honest **per (format, operation)**: `x12`/`astm`/`ncpdp` support all of parse/inspect/fmt/
|
|
152
161
|
validate; `ccda` supports inspect/fmt/validate (parse deferred); `dicom` supports inspect/validate
|
|
@@ -230,20 +239,39 @@ valid JSON or not a loadable ConceptMap is a `CLI_MAP_INVALID` data error (`65`)
|
|
|
230
239
|
|
|
231
240
|
## The exit-code contract
|
|
232
241
|
|
|
233
|
-
Every command is safe to branch on in CI. The exit code carries the outcome
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
|
239
|
-
|
|
|
240
|
-
| `
|
|
241
|
-
| `
|
|
242
|
-
| `
|
|
243
|
-
| `
|
|
242
|
+
Every command is safe to branch on in CI. The exit code carries the outcome. `0` is the conventional
|
|
243
|
+
success status and the codes from `65` up are the values the Unix `sysexits.h` header assigns to the
|
|
244
|
+
conditions they name; `1` and `2` are this CLI's own values, because that header defines no constant
|
|
245
|
+
for either:
|
|
246
|
+
|
|
247
|
+
| Code | Meaning |
|
|
248
|
+
| ---- | ------------------------------------------------------------------------------------------------------------------- |
|
|
249
|
+
| `0` | success / **valid** (`validate`) |
|
|
250
|
+
| `1` | **invalid**: `validate` found a parseable-but-bad message, or `redact` could not de-identify every locus |
|
|
251
|
+
| `2` | usage error (unknown flag, missing argument) |
|
|
252
|
+
| `65` | data error (unparseable input, format undetected, or input past the size limit) |
|
|
253
|
+
| `66` | no input (missing/unreadable file) |
|
|
254
|
+
| `69` | unavailable (a capability is not wired for this input, e.g. `redact` on a format `@cosyte/deid` has no adapter for) |
|
|
255
|
+
| `70` | internal error (a bug) |
|
|
256
|
+
| `74` | output error: the output stream closed before the CLI finished writing (a consumer that exited early) |
|
|
244
257
|
|
|
245
258
|
The load-bearing rule: the CLI **never prints a reassuring line and exits `0`** on input it could not
|
|
246
|
-
handle,
|
|
259
|
+
handle, on an invalid message, or on output that never reached its consumer.
|
|
260
|
+
|
|
261
|
+
### A consumer that goes away
|
|
262
|
+
|
|
263
|
+
Piping into a reader that stops early is ordinary shell usage (a pager you quit, a `head` that has
|
|
264
|
+
seen enough), and it is not an error in your input:
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
cosyte parse bulk.ndjson --ndjson | head -3 # three lines, then exit 74, and a value-free note
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
The CLI terminates quietly under `74`: no stack trace, no platform error text, and no byte of the
|
|
271
|
+
input on stderr, just the stable `CLI_OUTPUT_WRITE_FAILED` code. Exit `74` is deliberately not the
|
|
272
|
+
internal-error code: nothing went wrong inside the CLI, the answer simply did not reach you. The
|
|
273
|
+
same holds when the whole result is one write, so a run whose output never arrived is never
|
|
274
|
+
reported as a success.
|
|
247
275
|
|
|
248
276
|
## PHI posture
|
|
249
277
|
|
|
@@ -268,15 +296,47 @@ cosyte parse broken.hl7 --format hl7 --unsafe-show-values # appends a bounded i
|
|
|
268
296
|
|
|
269
297
|
## `cosyte redact` / `cosyte deid`
|
|
270
298
|
|
|
271
|
-
De-identification is the one operation whose _job_ is to strip
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
299
|
+
De-identification is the one operation whose _job_ is to strip identifiers, and the CLI **owns none of
|
|
300
|
+
the policy**. It belongs to [`@cosyte/deid`](https://github.com/cosyte/deid): the CLI locates nothing,
|
|
301
|
+
transforms nothing, and has no fallback scrub, because a built-in "minimal Safe-Harbor" pass over only
|
|
302
|
+
the obvious fields would leave PHI behind and _look_ de-identified while silently under-redacting, the
|
|
303
|
+
exact false-safety hazard `redact` exists to avoid.
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
cosyte redact adt.hl7 > clean.hl7 # stdout: the de-identified message. stderr: what was touched
|
|
307
|
+
echo $? # 0: clean.hl7 is the copy. 1: clean.hl7 is empty, see stderr
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**Covered formats: `ccda`, `fhir`, `hl7`, `x12`** (what the library covers and this CLI can serialize
|
|
311
|
+
onto a text stdout). Anything else emits nothing at all:
|
|
312
|
+
|
|
313
|
+
| Outcome | Diagnostic | Exit |
|
|
314
|
+
| ------------------------------------------------------------------------------------ | ------------------------ | ---- |
|
|
315
|
+
| every locus handled | the manifest | `0` |
|
|
316
|
+
| a locus the library reports it could not handle | `CLI_DEID_INCOMPLETE` | `1` |
|
|
317
|
+
| `astm`, `mllp`, `ncpdp`: no adapter in that library | `CLI_NOT_IMPLEMENTED` | `69` |
|
|
318
|
+
| `dicom`: covered there, but its de-identified form is binary and this stdout is text | `CLI_FORMAT_UNSUPPORTED` | `65` |
|
|
319
|
+
| `@cosyte/deid` not installed (an optional dependency) | `CLI_PARSER_UNAVAILABLE` | `69` |
|
|
320
|
+
|
|
321
|
+
stderr carries the library's **own value-free manifest** (category, transform, the structural path,
|
|
322
|
+
count, disposition and its stable code) and the library's **own published label and version**: the CLI
|
|
323
|
+
asserts no de-identification standard of its own. An absent library is decided **before your input is
|
|
324
|
+
read**.
|
|
325
|
+
|
|
326
|
+
What the library's default policy does decides which of the first two rows you get, and the CLI
|
|
327
|
+
passes it no policy of its own:
|
|
328
|
+
|
|
329
|
+
- **Medical record, account and member numbers are removed**, not replaced by a surrogate: their
|
|
330
|
+
manifest lines read `removed DEID_CATEGORY_REMOVED`.
|
|
331
|
+
- **A visit number or an order number is blocked, so the whole run is refused.** An HL7 visit number
|
|
332
|
+
(`PV1-19`), and a placer or filler order number (`ORC-2`/`ORC-3`, `OBR-2`/`OBR-3`), fall to the
|
|
333
|
+
library's catch-all identifier category, which its default policy blocks rather than removes. Such a
|
|
334
|
+
message exits with `CLI_DEID_INCOMPLETE` (exit `1`) and nothing on stdout, and stderr names each
|
|
335
|
+
blocked locus with the library's `DEID_LOCUS_BLOCKED` code. Many real ADT messages carry `PV1-19`,
|
|
336
|
+
so check the exit code before you use `clean.hl7`.
|
|
337
|
+
|
|
338
|
+
The CLI still keys every run with a **per-invocation ephemeral key** and says so on stderr: any
|
|
339
|
+
identifier surrogate is consistent within one output and deliberately not stable across runs.
|
|
280
340
|
|
|
281
341
|
## `cosyte completion`
|
|
282
342
|
|
|
@@ -315,6 +375,12 @@ and the agent get identical results. The PHI posture is inherited and hardened:
|
|
|
315
375
|
tool _error_ carries only value-free diagnostics (a stable code + position, never an input value). A
|
|
316
376
|
parsed-but-invalid `validate` is a **successful** call reporting the verdict, not a tool error.
|
|
317
377
|
|
|
378
|
+
**Every tool publishes an `outputSchema`**, so a client validates a result against a declared contract
|
|
379
|
+
rather than pattern-matching prose. Each result carries `ok`, a `status` of `success` / `verdict` /
|
|
380
|
+
`failed`, the `exit` code, a stable `code` on a failure, and the tool's own payload under `data`; the
|
|
381
|
+
text content block carries the serialized JSON of that same structured result. See the docs for the
|
|
382
|
+
per-tool payload shapes.
|
|
383
|
+
|
|
318
384
|
The MCP SDK (`@modelcontextprotocol/sdk`) is the CLI's only third-party runtime dependency; it is
|
|
319
385
|
declared **optional** and loaded only on the MCP path, so a `cosyte parse` invocation never pulls it and
|
|
320
386
|
the core works with the SDK absent. The server surface is importable via the `@cosyte/cli/mcp` subpath
|