@cosyte/cli 0.0.3 → 0.0.5

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
@@ -7,10 +7,197 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
  Versions and publishing are managed with [Changesets](https://github.com/changesets/changesets);
8
8
  this file is maintained by hand (Changesets handles the version bump and publish only).
9
9
 
10
+ The released sections below were reconstructed on 2026-08-04. Until then every entry sat under
11
+ `Unreleased`, including entries describing releases that had already shipped, so each published
12
+ tarball carried a changelog calling its own contents unreleased. Those tarballs are immutable and
13
+ still do. Each entry was assigned to the release whose tag first contains it, read off `v0.0.1`,
14
+ `v0.0.2` and `v0.0.3`; no entry text was rewritten to fit a section.
15
+
10
16
  ## [Unreleased]
11
17
 
12
18
  ### Fixed
13
19
 
20
+ - **A red pre-publish gate showed a red X and merged anyway, because `ci / prepublish` was a
21
+ required check nowhere (CI-REQUIRED-CHECKS).** The shared pipeline this repo calls grew a
22
+ `prepublish` job on 2026-08-05 (`cosyte/.github#35`, `6142ac4`; its second layer defaulted on in
23
+ `#36`, `90936ea`), so `ci.yml` began emitting a `ci / prepublish` context on every pull request
24
+ here **with no commit landing in this repo**. Repository ruleset `19907924` did not name it, so
25
+ the job could fail and the merge still landed on `main`, which is the branch that publishes.
26
+ `ci / prepublish` is now a required context, `integration_id`-pinned like the other six.
27
+ - **What it gates is this package's own worst shipped defect.** The job is an offline manifest
28
+ lint that refuses a dependency specifier no registry can resolve, plus a probe that packs this
29
+ tree and installs the tarball into a clean directory. `@cosyte/cli@0.0.1` and `0.0.2` reached
30
+ the registry carrying `file:vendor/*.tgz` specifiers and are permanently uninstallable; the
31
+ manifest lint would have refused both. A gate that catches that and then cannot block the merge
32
+ reintroducing it is documentation.
33
+ - **The order was load-bearing and is recorded because it is easy to get backwards.** The context
34
+ name was read off a real `pull_request` check run before the ruleset was written, never off the
35
+ workflow's `name:` field. Requiring a context nothing emits does not fail a pull request, it
36
+ leaves it pending and unmergeable forever. A census of the eight most recent head shas here
37
+ (`#27` through `#34`) finds `ci / prepublish` **zero** times, because the newest of them merged
38
+ before the upstream job existed, so it could not have been required any earlier.
39
+ - **`ci.yml`'s banner now covers the hazard that actually bit.** Every previous wording of it was
40
+ scoped to splitting a step out of `verify` locally. The `uses:` reference is unpinned, so a job
41
+ added upstream emits a new `ci / <job>` context here with no commit in this repo, and it always
42
+ arrives unrequired.
43
+ - **Deliberately NOT in this change: `release.yml`'s version-PR trap note.** It carries a stale
44
+ required-context count and a claim about the "Version Packages" PR arriving with zero check runs
45
+ whose truth depends on whether `RELEASE_PR_TOKEN` is authoring that PR. Two attempts to correct
46
+ it inside this change each produced a fresh false claim: the first a false operational premise,
47
+ the second a false claim about the note's own history. So it is cut out to its own change rather
48
+ than rewritten a third time. Nothing about it is made worse here; it is left exactly as it was.
49
+
50
+ - **The shipped documentation sidebar was off the canonical IA spine, and it was holding up the
51
+ docs site's deploy (CLI-SIDEBAR-IA-NONCANONICAL).** `docs-content/sidebars.json` declared two
52
+ top-level categories that are not on the spine, **"MCP server"** and **"Reference"**. The docs
53
+ site lints the sidebar it receives from each package's released `docs-content.tar.gz`, and in
54
+ strict mode a non-canonical top-level label grades as an error, so this package failed that gate
55
+ and the site stopped deploying. Pre-existing since the pages were authored; it surfaced only once
56
+ an unrelated build failure stopped masking it.
57
+ - Both categories are removed and their pages folded into categories this package already had, so
58
+ **no page left the navigation and none was orphaned** (verified: the nine documents in
59
+ `docs-content/` and the nine referenced by the sidebar are the same nine). **`mcp`** and
60
+ **`reference-commands`** join **Guides**, next to `guides-overview`, both being task-oriented:
61
+ what to run and what comes back. **`limitations`** joins **Troubleshooting**, next to
62
+ `troubleshooting`, which is where the documentation standard puts known limitations.
63
+ - The categories this package ships are now `Installation`, `Quickstart`, `Core Concepts`,
64
+ `Guides` and `Troubleshooting`, in that order, under the `intro` document.
65
+ - **"Reference" was deliberately NOT renamed to "API Reference".** That category is injected by
66
+ the docs site, and a hand-authored one is refused outright rather than warned about, so the
67
+ rename would have traded a failing check for a differently failing one. Whether and where the
68
+ site adds it is the site's decision, not this package's, and this package neither authors nor
69
+ positions it.
70
+ - Verified against the site's own linter rather than by inspection, with the sidebar shipped in
71
+ the previous release as a **negative control**: that one produces two errors and this one
72
+ produces no findings. **Only a new release can clear the gate**, because it reads the sidebar
73
+ out of the released artifact and published releases are immutable, so the previous release
74
+ keeps its non-canonical sidebar permanently. That is reported without gating once a release is
75
+ no longer current.
76
+ - Documentation-artifact change only: no command, flag, exit code, diagnostic code or export
77
+ moves, and no page content was rewritten.
78
+
79
+ - **The pre-commit PHI gate never saw a `git mv` into a scan root
80
+ (PHI-SCAN-RENAME-BLIND-AT-PRECOMMIT).** `scripts/phi-scan.ts --staged` listed the index with
81
+ `git diff --cached --name-only --diff-filter=AM`. Rename detection is on by default, so
82
+ `git mv <path> test/__fixtures__/<name>` stages as a **two-path `R100` record**, and `R` and `C`
83
+ are in neither `AM` nor `AMT`: the status filter deleted the record outright and the destination
84
+ was never enumerated. Measured on this repo, both shapes walking through the
85
+ `pnpm phi-scan --staged` pre-commit hook at **exit 0**: a regular file carrying a value this
86
+ scanner's own floor catches (`:100644 100644 <sha> <sha> R100`), and a symbolic link
87
+ (`:120000 120000 <sha> <sha> R100`, index mode `120000` under the scan root). `git mv` is an
88
+ ordinary developer action, not crafted input, and the pre-commit hook is the gate it walked
89
+ through.
90
+ - **`--no-renames` is the remedy, and it costs the record stride nothing.** The destination
91
+ arrives as a single-path `A` and the source as a `D` the filter drops, so the enumeration is a
92
+ strict **superset** of the previous one. Verified under `diff.renames` set to `true`, `copies`,
93
+ `false` and `1`, and under `diff.renameLimit=1`: no `R` or `C` record survives in any of them,
94
+ which makes the two-field record stride structural rather than conditional. `copies` is not
95
+ hypothetical; it produces a live `C100` here.
96
+ - **The destination mode was never read at all.** The route enumerated with `--name-only` and read
97
+ content with `git show :<path>`, and git stores a symbolic link as its **target path** under
98
+ mode `120000`, so the scan was handed the path text and never the target's bytes. It now lists
99
+ with `--raw -z` and **refuses** (exit `2`) any in-scope entry whose destination mode is not a
100
+ regular blob. A refusal names the entry's own repo-relative path and an engine-owned token for
101
+ its kind, and **never the link target**, which is working-tree text that can itself carry PHI.
102
+ Every offender is named, not just the first. That guarantee is about a **refusal** and does not
103
+ extend to a hit; see the linked-scan-root residual below.
104
+ - **`T` (typechange) is now in the filter**, because replacing a _tracked_ regular fixture with a
105
+ link is neither an add nor a modify (`:100644 120000 <sha> <sha> T`), so `--diff-filter=AM`
106
+ deleted the record before any mode could be read. The reverse direction, a link replaced by a
107
+ real file, is now scanned as the file it became.
108
+ - **Each scan root's own path is in scope**, not just its contents. Git records no index entry for
109
+ a directory, so an entry at exactly `test/__fixtures__` or `src` is that root replaced by a blob
110
+ or a link, and a prefix test requiring the trailing slash let it through while the whole corpus
111
+ went unscanned.
112
+ - **The all-mode walk gets the same refusal.** A scanner whose pre-commit half refuses a link
113
+ while its CI half silently drops one is not one a developer can reason about. The walk
114
+ enumerates `Dirent.isFile()`, an lstat answer, so a link (and a linked _directory_, which
115
+ `isDirectory()` also answers false for) fell out of the loop silently. The `.md` exemption
116
+ deliberately does not reach a link: it is a judgement about a file whose bytes the walk could
117
+ have read, and a link's name is no evidence about what is on the other side of it. A gitignored
118
+ entry stays out of scope, by the same rule that already excludes a gitignored fixture.
119
+ - **Two pre-existing exit-code defects fixed with it.** A missing or unreadable allow-list, and an
120
+ unreadable scan root, both threw past every handler and exited **1** with a raw stack trace. `1`
121
+ is this contract's code for _hits found_, so a caller branching on the exit code read a broken
122
+ invocation as a PHI finding and a caller branching on "not 0" read it as the gate working.
123
+ Neither was true. Both are now exit `2` with a diagnostic.
124
+ - **Stated rather than left to be inferred, both pre-existing and neither closed here.** The
125
+ staged route still does not enumerate `D` (a deletion has no staged blob to scan) or `U` (an
126
+ unmerged path has no single one). The `U` half costs nothing that can reach a commit, and that
127
+ was measured rather than assumed: `git commit` refuses an unmerged index outright. Under `src/`
128
+ the staged route still covers only `.ts` files while the all-mode walk covers every non-`.md`
129
+ file, so the CI sweep is what covers the difference; widening the staged half is a scope
130
+ decision and was not taken here.
131
+ - **The refusal rule is scoped to an _enumerated_ entry, and the unqualified version of it is
132
+ false.** It covers an entry the walk reached beneath a root it had already opened, and a staged
133
+ record in scope per the boundary rule, which under `src/` is `.ts` files only, so a staged link
134
+ at `src/notes.json` is under a scan root and `--staged` still exits 0 over it while the all-mode
135
+ sweep refuses it. Three shapes escape the rule, all pre-existing, all measured, none
136
+ closed here: **(1)** a scan root that is itself a **live** link is followed by the all-mode walk,
137
+ because `existsSync` and `readdirSync` both resolve, so the walk reads files no commit contains
138
+ and reports their values under a **fabricated in-repo path** that holds no such file (the
139
+ **dangling** direction is the mirror image: it reports clean over a corpus it never opened);
140
+ **(2)** an **ancestor** of a scan root is in neither route's scope, so staging `test` as a link
141
+ leaves `--staged` at exit 0 and the walk then follows it; **(3)** paths mode follows an
142
+ explicitly named link, because `statSync` resolves. The `--staged` half of shape (1) **is**
143
+ closed here. Closing the rest needs a refuse-a-scan-that-observed-nothing rule plus a decision
144
+ about how far above a scan root to look, which is its own change.
145
+ - `test/scripts/phi-scan.test.ts` builds throwaway git repositories for all of it, because these
146
+ are properties of what `git diff --cached` reports and cannot be reproduced by scanning a path.
147
+ **16 of its 34 tests run red against the scanner on `a7a92f8`**; the 18 that stay green are the
148
+ pre-existing floor tests, the deliberate controls (an ordinary staged hit, a clean pass, a
149
+ staged link outside both roots, an ignored link, and a check that the payload under test is
150
+ something this scanner would otherwise catch), and the four that **pin the disclosed residuals
151
+ above**. Those four are green on both trees by design: they pin behaviour this change does not
152
+ alter, so that the scoped wording of the refusal rule cannot quietly revert to the absolute one.
153
+ Synthetic values only.
154
+ - **No change to the CLI's runtime surface**: no command, flag, exit code, diagnostic code or
155
+ export moves. This is repository tooling.
156
+
157
+ ## [0.0.3] - 2026-08-03
158
+
159
+ ### Changed
160
+
161
+ - **FHIR support is unavailable in an npm-installed copy, and now says so instead of crashing.**
162
+ `@cosyte/fhir` is not on the npm registry, so it cannot be declared as a dependency at all;
163
+ measured, declaring it alongside `@cosyte/transform` (which requires it) fails the whole install
164
+ with `ERESOLVE`. `@cosyte/transform` is therefore skipped by npm as an unresolvable optional
165
+ dependency. Both were previously loaded with a bare `await import()`, which in an installed copy
166
+ would have surfaced a raw resolver error and a stack frame, so FHIR `parse`/`inspect`/`fmt`/`validate`
167
+ and `convert` now degrade to a value-free `CLI_PARSER_UNAVAILABLE` (exit `69`) with a diagnostic that
168
+ says the package is not on the registry rather than "install it". **Neither diagnostic says "install
169
+ it", and that is deliberate**: `npm install @cosyte/transform` fails `E404` on its own
170
+ `@cosyte/fhir` peer, so `loadOptional()`'s stock wording ("install it to use this format, it is an
171
+ optional dependency") would point a user at a command that cannot succeed. New
172
+ `loadOptionalPackage(detail, load)` under `loadOptional`, exported on the `.` subpath.
173
+ `@cosyte/fhir` is retained as a `devDependency` on the vendored tarball so this repo's own FHIR and
174
+ `convert` tests still run; note that `devDependencies` **are** published, so that one
175
+ `file:vendor/*.tgz` specifier does remain in the manifest, harmlessly, because a consumer never
176
+ installs a dependency's `devDependencies` (verified: the install exits `0`). HL7 v2, `map-codes` and
177
+ the six breadth formats are unaffected and work from a plain install.
178
+
179
+ - **Documented a pre-existing defect that this release makes reachable for the first time:
180
+ `--omit=optional` produces an install in which the `cosyte` command does not run at all.** The
181
+ install exits `0`, then every invocation, `--version` included, fails with `ERR_MODULE_NOT_FOUND` on
182
+ `@modelcontextprotocol/sdk` and a raw stack trace, because the built `dist/bin/cosyte.mjs` imports
183
+ the SDK statically at the top level rather than only on the `mcp` path. Verified identical on the
184
+ base commit, so it is not introduced here; it simply could not be hit before, because the package
185
+ could not be installed at all. `docs-content/` now says not to use that flag instead of implying it
186
+ is a supported way to slim the install. **The code defect is not fixed here** and needs its own
187
+ change: it also falsifies the "a plain `cosyte parse` never pulls it" claim in `src/bin/cosyte.ts`.
188
+
189
+ - **The docs no longer tell you to run `npx @cosyte/cli …`, which never worked.** Separate from the
190
+ packaging defect and not fixed by it: `npx` runs the executable whose name matches the package
191
+ name's last segment, which would be `cli`, and this package ships `cosyte` and `cosyte-mcp`, so the
192
+ short form fails with `could not determine executable to run`. Reproduced on the published `0.0.2`
193
+ and on the fixed tarball, whose `bin` block is byte-identical. `README.md`, `docs-content/installation.md`
194
+ and both MCP registration snippets now use `npx --package @cosyte/cli cosyte …` /
195
+ `npx -y --package @cosyte/cli cosyte-mcp`, each measured working. A `cli` bin alias would fix the
196
+ short form and is deliberately not added, because `npm install -g` would then claim a command named
197
+ `cli` on the user's `PATH`.
198
+
199
+ ### Fixed
200
+
14
201
  - **`@cosyte/cli` can be installed from npm again (CLI-UNINSTALLABLE-MANIFEST).** `0.0.1` and `0.0.2`
15
202
  both published with all ten `@cosyte/*` sibling packages declared as `file:vendor/*.tgz` local
16
203
  paths. `vendor/` is not in `files` and there is no `bundledDependencies`, so the tarball shipped
@@ -81,29 +268,6 @@ node_modules/@cosyte/cli/vendor/cosyte-fhir-0.0.0.tgz`. The siblings are now rea
81
268
  with attw's own status, and that the profile flag survives the wrapper in both directions.
82
269
  - `scripts/verify.sh` in the meta-repo is unchanged; its propagation was never at fault.
83
270
 
84
- - **The public surface now states that `0.0.1` is published and uninstallable (ASSETS-P8).** `0.0.1`
85
- published on 2026-07-29 with all ten `file:vendor/*.tgz` dependency specifiers intact. `vendor/` is
86
- not in `files` and there is no `bundledDependencies`, so every install route (`npm i`, `npm i -g`,
87
- `npx`) fails with `ENOENT` on `node_modules/@cosyte/cli/vendor/cosyte-fhir-0.0.0.tgz`. Reproduced
88
- in a clean directory. A published version is immutable (ADR 0001), so `0.0.1` stays broken and the
89
- fix must ship as a later version.
90
- - `README.md` gains a **"Known issue"** section stating what fails, the exact error, why, and that
91
- a source checkout is the only workaround. `docs-content/installation.md` gains the same under
92
- **"Installing fails today"**. Both copies of the broken `npx`-based MCP registration snippet are
93
- annotated (`README.md` and `docs-content/mcp.md`).
94
- - **Four false claims corrected.** (1) `README.md` said "not yet published to npm"; it is
95
- published. (2) It described swapping the vendored sibling deps for real `@cosyte/*` npm ranges as
96
- a step still to come "at that flip"; the flip already happened without the swap, which is the
97
- defect. (3) The same "not yet published" claim appeared in **three** `docs-content/` pages. (4)
98
- The `redact`/`deid` terminal diagnostic, the `--help` text, three JSDoc blocks that compile into
99
- `dist/*.d.ts`, and **five** docs pages said `@cosyte/deid` was unpublished, unshipped, or unbuilt;
100
- it is published at `0.0.2`, and the accurate statement is that the CLI does not wire it yet. Every
101
- count here was re-derived by census of the base tree, not estimated.
102
- - **The "all eight formats" claim was checked and is correct**: `CosyteFormat` and `OP_SUPPORT` both
103
- enumerate exactly eight.
104
- - `RELEASING.md` records that the documented dependency-swap step was skipped, that a green
105
- `npm publish --dry-run` cannot catch this (it packs a tarball but never resolves its deps from a
106
- registry), and adds a checklist step to install the published version from outside the repo.
107
271
  - **The route to an installable release, recorded in `RELEASING.md` and verified against the
108
272
  registry.** `@cosyte/hl7` (`0.0.3`), `@cosyte/terminology` (`0.0.4`) and all six breadth parsers
109
273
  would swap to real ranges today. `@cosyte/fhir` is unpublished (`FHIR-NPM-NAME`, an npm E403
@@ -114,53 +278,15 @@ node_modules/@cosyte/cli/vendor/cosyte-fhir-0.0.0.tgz`. The siblings are now rea
114
278
  routed through a guarded loader to degrade to `CLI_PARSER_UNAVAILABLE` (exit `69`) rather than
115
279
  crash. `loadOptional()` cannot be reused unchanged: it takes a `CosyteFormat`, and `"transform"` is
116
280
  not one, and its diagnostic hardcodes the word "parser". Not undertaken here.
117
- - **Superseded within this same unreleased set**, by the two entries at the top of this section:
118
- the swap and the loader change were both carried out. Two claims that entry made did not survive
281
+ - **Superseded by the two `0.0.3` entries above**: the swap and the loader change were both
282
+ carried out. Two claims that entry made did not survive
119
283
  contact: the "name similarity" reading of the `@cosyte/fhir` `E403` was **retracted across the
120
284
  ecosystem on 2026-08-03** (the cause is unexplained; do not assert one), and "npm tolerates an
121
285
  `optionalDependency` that fails to resolve" is true only in isolation. Declaring **both**
122
286
  `@cosyte/fhir` and `@cosyte/transform` optional fails the install outright with `ERESOLVE`, which
123
287
  is why `@cosyte/fhir` ended up not declared at all rather than declared optional.
124
288
 
125
- ### Changed
126
-
127
- - **FHIR support is unavailable in an npm-installed copy, and now says so instead of crashing.**
128
- `@cosyte/fhir` is not on the npm registry, so it cannot be declared as a dependency at all;
129
- measured, declaring it alongside `@cosyte/transform` (which requires it) fails the whole install
130
- with `ERESOLVE`. `@cosyte/transform` is therefore skipped by npm as an unresolvable optional
131
- dependency. Both were previously loaded with a bare `await import()`, which in an installed copy
132
- would have surfaced a raw resolver error and a stack frame, so FHIR `parse`/`inspect`/`fmt`/`validate`
133
- and `convert` now degrade to a value-free `CLI_PARSER_UNAVAILABLE` (exit `69`) with a diagnostic that
134
- says the package is not on the registry rather than "install it". **Neither diagnostic says "install
135
- it", and that is deliberate**: `npm install @cosyte/transform` fails `E404` on its own
136
- `@cosyte/fhir` peer, so `loadOptional()`'s stock wording ("install it to use this format, it is an
137
- optional dependency") would point a user at a command that cannot succeed. New
138
- `loadOptionalPackage(detail, load)` under `loadOptional`, exported on the `.` subpath.
139
- `@cosyte/fhir` is retained as a `devDependency` on the vendored tarball so this repo's own FHIR and
140
- `convert` tests still run; note that `devDependencies` **are** published, so that one
141
- `file:vendor/*.tgz` specifier does remain in the manifest, harmlessly, because a consumer never
142
- installs a dependency's `devDependencies` (verified: the install exits `0`). HL7 v2, `map-codes` and
143
- the six breadth formats are unaffected and work from a plain install.
144
-
145
- - **Documented a pre-existing defect that this release makes reachable for the first time:
146
- `--omit=optional` produces an install in which the `cosyte` command does not run at all.** The
147
- install exits `0`, then every invocation, `--version` included, fails with `ERR_MODULE_NOT_FOUND` on
148
- `@modelcontextprotocol/sdk` and a raw stack trace, because the built `dist/bin/cosyte.mjs` imports
149
- the SDK statically at the top level rather than only on the `mcp` path. Verified identical on the
150
- base commit, so it is not introduced here; it simply could not be hit before, because the package
151
- could not be installed at all. `docs-content/` now says not to use that flag instead of implying it
152
- is a supported way to slim the install. **The code defect is not fixed here** and needs its own
153
- change: it also falsifies the "a plain `cosyte parse` never pulls it" claim in `src/bin/cosyte.ts`.
154
-
155
- - **The docs no longer tell you to run `npx @cosyte/cli …`, which never worked.** Separate from the
156
- packaging defect and not fixed by it: `npx` runs the executable whose name matches the package
157
- name's last segment, which would be `cli`, and this package ships `cosyte` and `cosyte-mcp`, so the
158
- short form fails with `could not determine executable to run`. Reproduced on the published `0.0.2`
159
- and on the fixed tarball, whose `bin` block is byte-identical. `README.md`, `docs-content/installation.md`
160
- and both MCP registration snippets now use `npx --package @cosyte/cli cosyte …` /
161
- `npx -y --package @cosyte/cli cosyte-mcp`, each measured working. A `cli` bin alias would fix the
162
- short form and is deliberately not added, because `npm install -g` would then claim a command named
163
- `cli` on the user's `PATH`.
289
+ ## [0.0.2] - 2026-07-31
164
290
 
165
291
  ### Added
166
292
 
@@ -201,6 +327,36 @@ node_modules/@cosyte/cli/vendor/cosyte-fhir-0.0.0.tgz`. The siblings are now rea
201
327
  would be a wasted line. The wording is the one eight sibling packages already carry, confirmed
202
328
  against both rendered PNGs here rather than copied on trust.
203
329
 
330
+ ### Fixed
331
+
332
+ - **The public surface now states that `0.0.1` is published and uninstallable (ASSETS-P8).** `0.0.1`
333
+ published on 2026-07-29 with all ten `file:vendor/*.tgz` dependency specifiers intact. `vendor/` is
334
+ not in `files` and there is no `bundledDependencies`, so every install route (`npm i`, `npm i -g`,
335
+ `npx`) fails with `ENOENT` on `node_modules/@cosyte/cli/vendor/cosyte-fhir-0.0.0.tgz`. Reproduced
336
+ in a clean directory. A published version is immutable (ADR 0001), so `0.0.1` stays broken and the
337
+ fix must ship as a later version.
338
+ - `README.md` gains a **"Known issue"** section stating what fails, the exact error, why, and that
339
+ a source checkout is the only workaround. `docs-content/installation.md` gains the same under
340
+ **"Installing fails today"**. Both copies of the broken `npx`-based MCP registration snippet are
341
+ annotated (`README.md` and `docs-content/mcp.md`).
342
+ - **Four false claims corrected.** (1) `README.md` said "not yet published to npm"; it is
343
+ published. (2) It described swapping the vendored sibling deps for real `@cosyte/*` npm ranges as
344
+ a step still to come "at that flip"; the flip already happened without the swap, which is the
345
+ defect. (3) The same "not yet published" claim appeared in **three** `docs-content/` pages. (4)
346
+ The `redact`/`deid` terminal diagnostic, the `--help` text, three JSDoc blocks that compile into
347
+ `dist/*.d.ts`, and **five** docs pages said `@cosyte/deid` was unpublished, unshipped, or unbuilt;
348
+ it is published at `0.0.2`, and the accurate statement is that the CLI does not wire it yet. Every
349
+ count here was re-derived by census of the base tree, not estimated.
350
+ - **The "all eight formats" claim was checked and is correct**: `CosyteFormat` and `OP_SUPPORT` both
351
+ enumerate exactly eight.
352
+ - `RELEASING.md` records that the documented dependency-swap step was skipped, that a green
353
+ `npm publish --dry-run` cannot catch this (it packs a tarball but never resolves its deps from a
354
+ registry), and adds a checklist step to install the published version from outside the repo.
355
+
356
+ ## [0.0.1] - 2026-07-29
357
+
358
+ ### Added
359
+
204
360
  - **Phase 7: release hardening (the final roadmap phase; the CLI is feature-complete).** No new
205
361
  runtime command surface: this phase is publish-readiness.
206
362
  - **Fuzz gate over the two input boundaries.** `test/fuzz.property.test.ts` fuzzes the terminal
@@ -221,6 +377,7 @@ node_modules/@cosyte/cli/vendor/cosyte-fhir-0.0.0.tgz`. The siblings are now rea
221
377
  honest per-(format, operation) support matrix, the PHI-default posture), a man-page-style
222
378
  `docs-content/reference-commands.md`, and `RELEASING.md` (the one-package-two-bins publish,
223
379
  provenance/OIDC, the vendored-`file:`→npm dep swap, and the two standing founder stops).
380
+
224
381
  - **Phase 6: six more formats + streaming + shell completion (ADR 0025).** The `cosyte` CLI now wraps
225
382
  **all eight cosyte formats**, routed through a single lazy **per-format adapter registry**
226
383
  (`src/core/parsers.ts`) that replaces the old per-command `hl7 ? : fhir` branches and makes support
@@ -279,6 +436,7 @@ parse` invocation never loads it; the core works with the SDK absent (`--omit=op
279
436
  (`createMcpServer`, `startStdioServer`, `dispatchTool`, `TOOL_DEFS`, and the MCP result types) on the
280
437
  `./mcp` subpath. `redact`/`deid` (gated on `@cosyte/deid`) and `map-codes` are deliberately not
281
438
  exposed as tools yet.
439
+
282
440
  - **Phase 4: `convert` / `map-codes` (the consumer-of-consumers commands).** Two commands that wrap
283
441
  the higher-layer libraries; the CLI adds **no** mapping or terminology logic of its own.
284
442
  - **`convert <file|-> --to fhir [--json] [--quiet]`**: **HL7 v2 → FHIR R4** via
@@ -309,6 +467,7 @@ parse` invocation never loads it; the core works with the SDK absent (`--omit=op
309
467
  lazy-loaded per command, so the `parse` fast path never loads them).
310
468
  - **ADR `0023`**: wire `@cosyte/transform` + `@cosyte/terminology`; the deliberate 2 → 4 cap raise
311
469
  (amends ADR 0021).
470
+
312
471
  - **Phase 3: `validate` / `inspect` / `fmt`.** Three commands over the two wired parsers
313
472
  (HL7 v2 + FHIR R4), each a thin wrapper that re-implements no library logic.
314
473
  - **`validate <file|-> [--profile] [--json] [--quiet]`**: parse + run the wrapped parser's own
@@ -335,6 +494,7 @@ parse` invocation never loads it; the core works with the SDK absent (`--omit=op
335
494
  helpers (behavior-preserving). New programmatic exports: `validateCommand`, `inspectCommand`,
336
495
  `fmtCommand`, `resolveInput`, `parseFailureResult`, `formatHl7Position`, `errorResult`. No new
337
496
  runtime dependencies: stays within the cap of 2.
497
+
338
498
  - **Phase 2: PHI posture hardened + `redact`/`deid` + `--unsafe-show-values`.**
339
499
  - **`--unsafe-show-values`**: a global, opt-in, PHI-exposing flag, resolved once and order-
340
500
  independently and funnelled through a **single chokepoint** (`core/phi.ts`), so the "a value
@@ -355,28 +515,35 @@ parse` invocation never loads it; the core works with the SDK absent (`--omit=op
355
515
  - New `CLI_NOT_IMPLEMENTED` diagnostic code and `EXIT.UNAVAILABLE` (`69`); new programmatic exports
356
516
  (`PhiPosture`, `VALUE_FREE`/`SHOW_VALUES`, `extractPhiPosture`, `unsafeInputSuffix`, `deidStatus`,
357
517
  `redactCommand`).
518
+
358
519
  - **Phase 1: the `cosyte parse` foundation.** Reshaped the scaffold from a library skeleton into a
359
520
  **`bin` package**: `package.json#bin` maps `cosyte` → `dist/bin/cosyte.mjs` (a shebang entry over a
360
521
  testable `core`), argument-parsed with Node's built-in `util.parseArgs` + a hand-rolled subcommand
361
522
  dispatcher (**no third-party CLI framework**).
523
+
362
524
  - **`cosyte parse <file|->`**: reads a file argument or stdin (`-`); **autodetects the format by
363
525
  content** (HL7 v2 `MSH` framing, FHIR JSON `resourceType`): conservative and fail-safe (a confident
364
526
  single match parses; ambiguity/no-match is a data error asking for `--format`, never a guess); routes
365
527
  to the wrapped parser (**lazy-loaded** per format); emits the parsed model as **typed JSON on
366
528
  stdout**. Flags: `--format`, `--json`, `--quiet`, `--no-color`.
529
+
367
530
  - **The exit-code contract** (`sysexits.h`-grounded, documented, tested): `0` success · `2` usage ·
368
531
  `65` data/parse error (`EX_DATAERR`) · `66` no input (`EX_NOINPUT`) · `70` internal (`EX_SOFTWARE`).
369
532
  The CLI never exits `0` on input it could not handle.
533
+
370
534
  - **Value-free diagnostic channel** with stable `CLI_*` codes (`CLI_FORMAT_UNDETECTED`,
371
535
  `CLI_FORMAT_AMBIGUOUS`, `CLI_FORMAT_UNSUPPORTED`, `CLI_NO_INPUT`, `CLI_EMPTY_INPUT`,
372
536
  `CLI_PARSE_FAILED`, `CLI_USAGE`, `CLI_INTERNAL`). **stdout is the data channel; every stderr line is
373
537
  value-free**: code + position only, never a field value. No temp files, no file logging.
538
+
374
539
  - **Programmatic `core` API** (the `.` subpath): `detectFormat` / `classifyCandidates` /
375
540
  `detectionError`, `EXIT`, `CLI_CODES` / `CliError`, `run`, `parseCommand`, `VERSION`.
541
+
376
542
  - **Runtime dependencies (ADR 0021):** `@cosyte/hl7` (`46d50eb`, v0.0.1) and `@cosyte/fhir` (`7a099b2`,
377
543
  v0.0.0) as **hard, first-party** deps (an `npx` bin cannot peer-depend) vendored as `pnpm pack`
378
544
  tarballs under `vendor/` until PUB-FLIP (`pnpm vendor:refresh`; umbrella ADR 0008). Capped at **2**
379
545
  by the umbrella `verify-policy.json`; third-party CLI-core runtime deps stay **zero**.
546
+
380
547
  - **ADRs:** `0021` (developer-tooling tier is a `bin` that hard-depends on first-party siblings;
381
548
  third-party runtime deps minimized) and `0022` (one repo, two bins: the CLI and the future
382
549
  `cosyte-mcp` MCP server over one core; the web playground is out of scope).
@@ -439,6 +606,7 @@ parse` invocation never loads it; the core works with the SDK absent (`--omit=op
439
606
  surrounding guarantees (value-free stderr, the never-a-fake `CLI_FORMAT_UNSUPPORTED`, the gated
440
607
  `redact`, the exit-code contract) are worded exactly as strongly as before. Internal traceability
441
608
  stays where the convention puts it: this file, the changesets, the commits and the roadmap.
609
+
442
610
  - **A dependency-budget figure left `src/core/deid.ts` too.** The module said wiring `@cosyte/deid`
443
611
  "would breach the CLI's runtime-dep cap (2)". Only the number was stale: the cap has been 4 since
444
612
  `convert`/`map-codes` landed, and the constraint itself still holds, because the package declares
@@ -447,10 +615,12 @@ parse` invocation never loads it; the core works with the SDK absent (`--omit=op
447
615
  constraint lapsed. The reasons that actually ground the refusal to ship a built-in redactor are
448
616
  untouched: `@cosyte/deid` is unpublished, the wrapped parsers expose no de-identification API, and
449
617
  a partial scrub would present a false-safety impression.
618
+
450
619
  - **`CosyteFormat`'s documentation no longer understates autodetection.** It read as though content
451
620
  detection recognised only HL7 v2 and FHIR, with the other six accepted by `--format` but "not yet
452
621
  wired", which has not been true since all eight formats gained signatures. The stale sentence is
453
622
  removed rather than restated.
623
+
454
624
  - **A gate now enforces the public-surface rule, which is why the class stops regrowing.**
455
625
  `scripts/check-no-internal-refs.sh` (`pnpm check:no-internal-refs`, on the `verify.sh cli` ladder)
456
626
  plus `.github/workflows/no-internal-refs.yml` port the shape of `hl7`'s gate
@@ -469,6 +639,7 @@ parse` invocation never loads it; the core works with the SDK absent (`--omit=op
469
639
  purpose, as it is in `hl7` and `ncpdp`: it ships inside the npm tarball, yet the convention names it
470
640
  as one of the places identifiers belong. That contradiction is ecosystem-wide, and it is recorded
471
641
  here rather than settled by one repo.
642
+
472
643
  - **`redact`/`deid` no longer names an internal tracking identifier on any consumer surface.** The
473
644
  `CLI_NOT_IMPLEMENTED` text printed when de-identification is unavailable carried an internal work
474
645
  item that means nothing to anyone running the command, and the same identifier reached the
@@ -477,25 +648,24 @@ parse` invocation never loads it; the core works with the SDK absent (`--omit=op
477
648
  `@cosyte/deid`, which is unpublished, and the CLI ships no built-in redactor because a partial
478
649
  scrub would present a false-safety impression. The stable `CLI_NOT_IMPLEMENTED` code and the exit
479
650
  `69` are unchanged.
651
+
480
652
  - **`CLI_PARSER_UNAVAILABLE`'s message no longer cites an internal decision record.** The error
481
653
  raised when an optional per-format parser is not installed pointed at an ADR number, which is
482
654
  meaningless to a caller; it now just names the package to install. The stable
483
655
  `CLI_PARSER_UNAVAILABLE` code and the exit `69` are unchanged. The same sweep removed the
484
656
  remaining roadmap-phase language from `README.md` and `docs-content/troubleshooting.md`.
657
+
485
658
  - **The CI checks are now binding on `main`.** `ci / verify (22, ubuntu-latest)`,
486
659
  `ci / verify (24, ubuntu-latest)`, `ci / actionlint` and `codeql / analyze (javascript-typescript)`
487
660
  are required status checks, each pinned to the `github-actions` app, alongside branch deletion and
488
661
  force-push protection. They were advisory before: a red check could not stop a merge. Dependabot
489
662
  now watches the npm and GitHub Actions dependency surfaces weekly, which nothing did previously.
663
+
490
664
  - **Reshaped the package from the parser-library scaffold to a `bin` package.** Removed the archetype
491
665
  stubs (`parseCli`, `WARNING_CODES`, `FATAL_CODES`); replaced the library `src/index.ts` and the
492
666
  round-trip property test with the command tree, the programmatic `core` API, and command-contract /
493
667
  autodetection / PHI-leak / equivalence tests. Rewrote `docs-content/` and `README.md` for the CLI.
494
668
 
495
- ### Deprecated
496
-
497
- ### Removed
498
-
499
669
  ### Fixed
500
670
 
501
671
  - **README + guides now describe the shipped Phase-3 command surface.** The `README.md` and
@@ -504,10 +674,12 @@ parse` invocation never loads it; the core works with the SDK absent (`--omit=op
504
674
  and the gated `redact`/`deid`) over the two wired parsers (HL7 v2 + FHIR R4). The pre-alpha,
505
675
  not-yet-published-to-npm status is unchanged (accurate), and the `npx`/`npm install -g` examples now
506
676
  carry a "not on npm yet" caveat (docs-only; README-ORG-SWEEP).
677
+
507
678
  - **`phi-scan` now scans the real fixture directory.** The scanner's fixture root pointed at a
508
679
  nonexistent `test/fixtures/`; it now walks `test/__fixtures__/` (and the same path in the staged
509
680
  filter), so the PHI commit-gate actually covers the CLI's synthetic fixtures.
510
681
 
511
- ### Security
512
-
513
- [Unreleased]: https://github.com/cosyte/cli/commits/main
682
+ [Unreleased]: https://github.com/cosyte/cli/compare/v0.0.3...HEAD
683
+ [0.0.3]: https://github.com/cosyte/cli/compare/v0.0.2...v0.0.3
684
+ [0.0.2]: https://github.com/cosyte/cli/compare/v0.0.1...v0.0.2
685
+ [0.0.1]: https://github.com/cosyte/cli/releases/tag/v0.0.1
package/README.md CHANGED
@@ -1,7 +1,9 @@
1
- <picture>
2
- <source media="(prefers-color-scheme: dark)" srcset="https://cosyte.com/tile/cosyte-lockup-tile-on-dark-1200x300.png">
3
- <img alt="Cosyte: a plus mark set in two overlapping rounded squares, one solid and one outlined, beside the Cosyte wordmark" src="https://cosyte.com/tile/cosyte-lockup-tile-on-light-1200x300.png">
4
- </picture>
1
+ <a href="https://cosyte.com">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://cosyte.com/tile/cosyte-lockup-tile-on-dark-1200x300.png">
4
+ <img alt="Cosyte: a plus mark set in two overlapping rounded squares, one solid and one outlined, beside the Cosyte wordmark" src="https://cosyte.com/tile/cosyte-lockup-tile-on-light-1200x300.png">
5
+ </picture>
6
+ </a>
5
7
 
6
8
  # @cosyte/cli
7
9
 
@@ -7,7 +7,7 @@ var types_js = require('@modelcontextprotocol/sdk/types.js');
7
7
  var util = require('util');
8
8
 
9
9
  // src/core/version.ts
10
- var VERSION = "0.0.3";
10
+ var VERSION = "0.0.5";
11
11
 
12
12
  // src/core/exit-codes.ts
13
13
  var EXIT = {