@cosyte/script-utils 0.1.2 → 0.1.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 +30 -12
- package/LICENSE +1 -1
- package/README.md +224 -15
- package/agent-notes.d.ts +92 -0
- package/agent-notes.js +512 -0
- package/attw.d.ts +18 -0
- package/attw.js +188 -8
- package/bin/cosyte-agent-notes.js +23 -0
- package/bin/cosyte-attw.js +24 -0
- package/bin/cosyte-catalog.js +23 -0
- package/bin/cosyte-claude-card.js +23 -0
- package/bin/cosyte-internal-refs.js +23 -0
- package/bin/cosyte-no-emdash.js +18 -0
- package/bin/cosyte-phi-scan.js +26 -0
- package/bin/cosyte-readme.js +22 -0
- package/bin/script-utils.js +44 -0
- package/catalog.d.ts +110 -0
- package/catalog.js +251 -0
- package/catalog.json +210 -0
- package/check-no-emdash.sh +69 -22
- package/claude-card.d.ts +64 -0
- package/claude-card.js +296 -0
- package/internal-refs.d.ts +12 -2
- package/internal-refs.js +131 -6
- package/package.json +40 -1
- package/phi-scan.d.ts +22 -0
- package/phi-scan.js +152 -4
- package/readme.d.ts +81 -0
- package/readme.js +489 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,18 +1,36 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versions are managed with Changesets;
|
|
5
|
-
this file is hand-maintained (Changesets' own changelog generation is disabled). The package is on the
|
|
6
|
-
**`0.1.x`** line: its surface is settled, and bump types follow ordinary semver rather than a
|
|
7
|
-
pre-alpha rule. See
|
|
8
|
-
[ADR 0002](../../documentation/decisions/0002-the-0-1-0-version-line.md).
|
|
3
|
+
## 0.1.4
|
|
9
4
|
|
|
10
|
-
|
|
11
|
-
> the pull request that adds the changeset. Nothing does it automatically.
|
|
5
|
+
### Patch Changes
|
|
12
6
|
|
|
13
|
-
|
|
7
|
+
- b9b2a7c: Every gate is now a bin, so a repository with no `package.json` can run it through npx: `cosyte-no-emdash`, `cosyte-attw`, `cosyte-phi-scan`, `cosyte-internal-refs`, `cosyte-readme`, `cosyte-claude-card`, `cosyte-agent-notes` and `cosyte-catalog`, each with `--help`, and `script-utils`, the dispatcher npx runs by the package's name (`npx -y @cosyte/script-utils@0.1 no-emdash`). The dash gate also matches every form the marketing and consulting scanner caught, in any case: the characters, URL encoding, the backslash-u escape (plain, braced and eight-digit), the braced backslash-x escape, the CSS escape, the Unicode name, and the named, decimal and hexadecimal HTML entities with or without the semicolon and with leading zeros. It now reads every tracked file's name as well as its content, and answers `--help`. A tracked file or name carrying one of the newly matched forms is refused where 0.1.3 printed OK.
|
|
14
8
|
|
|
15
|
-
##
|
|
9
|
+
## 0.1.3
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- f15075b: A new entry point, `@cosyte/script-utils/agent-notes`: the checker for a repository's agent notes, which replaces each library's own. What does not fit on the CLAUDE.md card lives in one file, `documentation/agent-notes.md`, and the card points into it in one form, `documentation/agent-notes.md#<anchor>`. The checker reads every tracked file and requires every pointer to name a heading of the notes (its GitHub slug) or an explicit `<a id>` or `<a name>` target; in CLAUDE.md it also refuses a bare backticked `#anchor` and `agent-notes.md#` without its directory. A notes directory, notes the card never points into, a blank notes file, an empty section and a citation of the umbrella's deleted ADR 0023 or its doc-budget hook are findings. Run it with `node node_modules/@cosyte/script-utils/agent-notes.js`; it exits 0 when clean, 1 with each finding's file, line and rule, and 2 when it cannot run.
|
|
14
|
+
- 7a0f98c: The `attw` gate in `@cosyte/script-utils` reads `npm pack --dry-run --json` in both of npm's shapes: the array npm 10 and 11 print, and the object keyed by package name that npm 12 prints. Before this, npm 12's object read as no tarball at all, and the gate refused every package ("npm described 0 tarball(s)"). It still requires exactly one entry whose name is the package's own, and in the object shape the key must match too; any other document is refused as before. The docblock no longer says every repo's `prepare` is the same one-liner: the parser template's `prepare` printed on stdout, inside the JSON this net reads, and twelve sibling repos still carry that line.
|
|
15
|
+
- 9d56322: A new entry point, `@cosyte/script-utils/catalog`: the one list of our libraries. It holds a record for each of the 14 libraries, the 8 standards (HL7 v2, MLLP, FHIR, C-CDA, X12, NCPDP, ASTM and DICOM) and the 6 built on them (terminology, transform, deid, synth, dates and cli), and one for Pathways, our integration engine, in development and not on npm. Each record is generated from the package's own package.json (name, description, release line, engines, repository, docs and npm URLs) and carries its tier. The data ships as `catalog.json` beside the module, and `CATALOG` is that file, frozen. Every library can run `node node_modules/@cosyte/script-utils/catalog.js` to check that its package.json description is the catalog's: it exits 0 when they agree, 1 with both values when they do not, and 2 when the package is not listed or package.json cannot be read.
|
|
16
|
+
- d0a2576: A new entry point, `@cosyte/script-utils/claude-card`: the checker for the CLAUDE.md card every Cosyte repository keeps. A card opens with `# <name>` and a paragraph, then has exactly three level-2 sections in order, Gate, Hazard and Rules (a heading may go on after its word, as in `## Rules that bind here`), none empty. It is at most 60 lines, every line at most 100 characters with code included, and at most 5,120 bytes, and when an AGENTS.md sits beside it the card imports it on a line of its own (`@AGENTS.md`). Run it with `node node_modules/@cosyte/script-utils/claude-card.js`; it exits 0 when the card follows the spec, 1 with each finding's line and rule, and 2 when CLAUDE.md cannot be read. `checkClaudeCard`, `runClaudeCardGate` and the limits it checks against are exported.
|
|
17
|
+
- a71747a: The attw, PHI-scan and internal-reference gates run from the command line, each with one per-repository file, as the dash gate already did. `node node_modules/@cosyte/script-utils/attw.js` runs the attw gate for the package in the working directory, and `scripts/attw.exclude` selects the profile (`node10` alone for `node16`, with `node16-cjs` for `esm-only`). `node node_modules/@cosyte/script-utils/phi-scan.js` runs the PHI engine over the whole repository with exit codes 0, 1 and 2, `--staged` reading everything but Markdown, and the literal tracked paths in `scripts/phi-scan.exclude` left out; it carries the cross-cutting floor only. `node node_modules/@cosyte/script-utils/internal-refs.js` reads the gate's axes from `scripts/internal-refs.json`, with exit codes 0, 1 and 2. The PHI engine's `--staged` route now passes `--ignore-submodules=none` to git, so a staged gitlink is refused even when the user's git config hides submodules from `git diff`. The internal-reference gate's ADR rule also matches an ADR path segment (`docs/adr/0001-scope.md`) and its phase rule the plural (`Phases 1 to 6`), as ten of the eleven per-repository copies did, and an extra rule's pattern may be a `{ source, flags }` object, so a rule read from JSON can be case-insensitive.
|
|
18
|
+
- bcdb7ea: The README's license line names the legal owner: "MIT, copyright Cosyte LLC." The READMEs of `@cosyte/eslint-config`, `@cosyte/process` and `@cosyte/script-utils` also use US spelling where they did not (license, behavior, generalize, recognized, honored). No code, configuration or type changes.
|
|
19
|
+
- e788688: A new entry point, `@cosyte/script-utils/readme`: the README gate for every `@cosyte/*` library. It checks the house skeleton (the shared lockup tile with the alt text assets declares for it, `# <package name>`, a one-line tagline, the badge row for npm version, CI, license and Node derived from `package.json`, the sections Why this exists, Status, Install, Usage, Support, Security, Contributing and License in that order with none empty, a link to the package's page on docs.cosyte.com between Usage and Support, and License last with an absolute link to the repository's LICENSE) and refuses a README over 60,000 characters, because npm keeps only the first 65,536. Run it with `node node_modules/@cosyte/script-utils/readme.js`; it exits 0 when the README follows the skeleton, 1 with each finding's line and rule, and 2 when it cannot read the package. `checkReadme`, `badgeRow`, `runReadmeGate` and the constants it checks against are exported.
|
|
20
|
+
|
|
21
|
+
## Released before this file was generated
|
|
22
|
+
|
|
23
|
+
Every release section above this heading is written by
|
|
24
|
+
[Changesets](https://github.com/changesets/changesets) from the changesets in `.changeset/`, newest
|
|
25
|
+
release first. A release writes its own version heading, so nothing above this line is maintained by
|
|
26
|
+
hand: a change is recorded by adding a changeset rather than by editing this file.
|
|
27
|
+
|
|
28
|
+
The sections below were kept by hand, in the
|
|
29
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format, until 2026-11-07. A version heading
|
|
30
|
+
that still read "Unreleased" after its version reached npm now carries that date; no entry was
|
|
31
|
+
reworded.
|
|
32
|
+
|
|
33
|
+
## [0.1.2] - 2026-11-07
|
|
16
34
|
|
|
17
35
|
### Changed
|
|
18
36
|
|
|
@@ -25,7 +43,7 @@ pre-alpha rule. See
|
|
|
25
43
|
now refuses where 0.1.1 printed OK**: write a range with "to", and rewrite a pause with a period,
|
|
26
44
|
a colon, a comma or parentheses.
|
|
27
45
|
|
|
28
|
-
## [0.1.1] -
|
|
46
|
+
## [0.1.1] - 2026-09-24
|
|
29
47
|
|
|
30
48
|
### Fixed
|
|
31
49
|
|
|
@@ -39,7 +57,7 @@ pre-alpha rule. See
|
|
|
39
57
|
still read from the bytes git carries and a hit in them is printed before the refusal; the
|
|
40
58
|
completeness rule still counts every read, and a root the walk reads is not refused.
|
|
41
59
|
|
|
42
|
-
## [0.1.0] -
|
|
60
|
+
## [0.1.0] - 2026-09-21
|
|
43
61
|
|
|
44
62
|
### Changed
|
|
45
63
|
|
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -49,7 +49,7 @@ that a broken or hostile install cannot decide whether a release gate runs.
|
|
|
49
49
|
|
|
50
50
|
### If your gate runs before `pnpm install`, do not use the bare specifier
|
|
51
51
|
|
|
52
|
-
Read this before adopting the package, because it is the one thing that does not
|
|
52
|
+
Read this before adopting the package, because it is the one thing that does not generalize.
|
|
53
53
|
|
|
54
54
|
A bare `import ... from "@cosyte/script-utils"` resolves through `node_modules`, so it only works
|
|
55
55
|
once the install has happened. `config`'s own gates run before their install and therefore import
|
|
@@ -65,8 +65,9 @@ So check when your gate runs, and pick accordingly:
|
|
|
65
65
|
Installing the package does not, on its own, give a pre-install gate the property described above.
|
|
66
66
|
|
|
67
67
|
Every entry point is published as source with no build step, so the relative-path route works for
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
each: the files are `index.js` and one `<entry>.js` per subpath, each beside its own hand-written
|
|
69
|
+
`.d.ts`. A vendored copy of a gate is that one file: its command-line form loads nothing beside it
|
|
70
|
+
unless node was pointed at a file of the same name.
|
|
70
71
|
|
|
71
72
|
## Usage
|
|
72
73
|
|
|
@@ -142,19 +143,135 @@ import { runAttwGate } from "@cosyte/script-utils/attw";
|
|
|
142
143
|
typeof runAttwGate; // => "function"
|
|
143
144
|
```
|
|
144
145
|
|
|
146
|
+
The README gate is the fifth. It checks a library README against the house skeleton and npm's
|
|
147
|
+
size limit, and it reads everything package-specific from `package.json`:
|
|
148
|
+
|
|
149
|
+
```ts runnable
|
|
150
|
+
import { checkReadme, README_CHARACTER_LIMIT } from "@cosyte/script-utils/readme";
|
|
151
|
+
|
|
152
|
+
const manifest = {
|
|
153
|
+
name: "@cosyte/demo",
|
|
154
|
+
repository: "https://github.com/cosyte/demo",
|
|
155
|
+
engines: { node: ">=22.14" },
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// A README that is only a title: each finding names the rule it breaks and the line.
|
|
159
|
+
const findings = checkReadme("# @cosyte/demo\n", manifest);
|
|
160
|
+
findings.some((finding) => finding.rule === "tile"); // => true
|
|
161
|
+
README_CHARACTER_LIMIT; // => 60000
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The card checker is the sixth. It checks a repository's CLAUDE.md against the card spec: a title,
|
|
165
|
+
a paragraph, then `## Gate`, `## Hazard` and `## Rules`, in at most 60 lines of at most 100
|
|
166
|
+
characters and 5,120 bytes:
|
|
167
|
+
|
|
168
|
+
```ts runnable
|
|
169
|
+
import { checkClaudeCard, CARD_MAX_LINES } from "@cosyte/script-utils/claude-card";
|
|
170
|
+
|
|
171
|
+
const card =
|
|
172
|
+
"# cosyte/demo\n\nOur demo.\n\n## Gate\n\npnpm test\n\n## Hazard\n\nNone.\n\n## Rules\n\n- One.\n";
|
|
173
|
+
checkClaudeCard(card); // => []
|
|
174
|
+
checkClaudeCard(card.replace("## Hazard", "## Notes")).length > 0; // => true
|
|
175
|
+
CARD_MAX_LINES; // => 60
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
The catalog is the seventh: one record per library, generated from its package.json, with its
|
|
179
|
+
tier, and one for Pathways. A site reads the list from it, and a library checks its description
|
|
180
|
+
against it:
|
|
181
|
+
|
|
182
|
+
```ts runnable
|
|
183
|
+
import { CATALOG, catalogEntry } from "@cosyte/script-utils/catalog";
|
|
184
|
+
|
|
185
|
+
CATALOG.libraries.length; // => 14
|
|
186
|
+
CATALOG.libraries.filter((library) => library.tier === "standard").length; // => 8
|
|
187
|
+
catalogEntry("@cosyte/hl7")?.docs; // => "https://docs.cosyte.com/hl7"
|
|
188
|
+
CATALOG.engine.displayName; // => "Pathways"
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
The agent-notes checker is the eighth. It resolves every pointer into a repository's one notes
|
|
192
|
+
file against that file's headings, slugged the way GitHub slugs them:
|
|
193
|
+
|
|
194
|
+
```ts runnable
|
|
195
|
+
import { checkAgentNotes, slugify } from "@cosyte/script-utils/agent-notes";
|
|
196
|
+
|
|
197
|
+
slugify("Why `attw` exits 0"); // => "why-attw-exits-0"
|
|
198
|
+
|
|
199
|
+
const claude = "# demo\n\nSee documentation/agent-notes.md#setup.\n";
|
|
200
|
+
const notes = "# Notes\n\n## Setup\n\nRun it.\n";
|
|
201
|
+
checkAgentNotes({ claude, notes, files: [] }); // => []
|
|
202
|
+
checkAgentNotes({ claude, notes: notes.replace("Setup", "Install"), files: [] })[0]?.rule; // => "dangling"
|
|
203
|
+
```
|
|
204
|
+
|
|
145
205
|
## Entry points
|
|
146
206
|
|
|
147
|
-
| entry point | what it is
|
|
148
|
-
| ------------------------------------ |
|
|
149
|
-
| `@cosyte/script-utils` | `isCliEntrypoint(moduleUrl)`, the entry-point guard
|
|
150
|
-
| `@cosyte/script-utils/phi-scan` | `runPhiScan(config)` and `exemptsMarkdown(relPath)`, the shared PHI gate
|
|
151
|
-
| `@cosyte/script-utils/internal-refs` | `runInternalRefsScan(config)`, the shared internal-reference gate
|
|
152
|
-
| `@cosyte/script-utils/attw` | `runAttwGate(options)`, the shared `attw` publish gate
|
|
207
|
+
| entry point | what it is |
|
|
208
|
+
| ------------------------------------ | -------------------------------------------------------------------------------------------- |
|
|
209
|
+
| `@cosyte/script-utils` | `isCliEntrypoint(moduleUrl)`, the entry-point guard |
|
|
210
|
+
| `@cosyte/script-utils/phi-scan` | `runPhiScan(config)` and `exemptsMarkdown(relPath)`, the shared PHI gate |
|
|
211
|
+
| `@cosyte/script-utils/internal-refs` | `runInternalRefsScan(config)`, the shared internal-reference gate |
|
|
212
|
+
| `@cosyte/script-utils/attw` | `runAttwGate(options)`, the shared `attw` publish gate |
|
|
213
|
+
| `@cosyte/script-utils/readme` | `runReadmeGate(options)` and `checkReadme(text, manifest)`, the README gate |
|
|
214
|
+
| `@cosyte/script-utils/claude-card` | `runClaudeCardGate(options)` and `checkClaudeCard(text)`, the CLAUDE.md card checker |
|
|
215
|
+
| `@cosyte/script-utils/catalog` | `CATALOG`, `catalogEntry(name)` and `runCatalogCheck(options)`, the catalog of our libraries |
|
|
216
|
+
| `@cosyte/script-utils/agent-notes` | `runAgentNotesCheck(options)` and `checkAgentNotes(input)`, the agent-notes checker |
|
|
153
217
|
|
|
154
218
|
They are separate subpaths because they are separately adoptable: a repo can take the entry-point
|
|
155
219
|
guard without taking a position on PHI scanning, a repo can take the internal-reference gate without
|
|
156
220
|
taking either, and importing one never loads another.
|
|
157
221
|
|
|
222
|
+
### The four gates from the command line
|
|
223
|
+
|
|
224
|
+
Each shared gate runs from a repository's package script with no file of its own but one input
|
|
225
|
+
(ST34). The dash gate already did; the other three now do too:
|
|
226
|
+
|
|
227
|
+
| gate | command | the one per-repository file |
|
|
228
|
+
| -------------- | ----------------------------------------------------------- | --------------------------------- |
|
|
229
|
+
| em and en dash | `bash node_modules/@cosyte/script-utils/check-no-emdash.sh` | `scripts/check-no-emdash.exclude` |
|
|
230
|
+
| attw | `node node_modules/@cosyte/script-utils/attw.js` | `scripts/attw.exclude` |
|
|
231
|
+
| PHI scan | `node node_modules/@cosyte/script-utils/phi-scan.js` | `scripts/phi-scan.exclude` |
|
|
232
|
+
| internal refs | `node node_modules/@cosyte/script-utils/internal-refs.js` | `scripts/internal-refs.json` |
|
|
233
|
+
|
|
234
|
+
- **attw** runs for the package in the working directory, as the one-line `scripts/attw.mjs`
|
|
235
|
+
caller does. `scripts/attw.exclude` names the resolutions the package leaves out, one per line:
|
|
236
|
+
`node10` alone selects attw's `node16` profile, and `node10` with `node16-cjs` selects `esm-only`.
|
|
237
|
+
It selects a profile and nothing else; any other entry, a repeat, `node16-cjs` alone, or a
|
|
238
|
+
`--profile` argument beside the file is refused at exit 1.
|
|
239
|
+
- **PHI scan** runs the engine with the house settings: exit codes 0 clean, 1 hits, 2 refuse; the
|
|
240
|
+
whole repository as the scan root; `--staged` reading everything but Markdown; the allow-list at
|
|
241
|
+
`scripts/phi-allow-list.txt` and the override log at `phi-scan-overrides.md`. Each line of
|
|
242
|
+
`scripts/phi-scan.exclude` is one literal tracked path (`#` lines are comments); a directory, a
|
|
243
|
+
pattern, a repeat or a path git does not track is refused at exit 2. It carries the
|
|
244
|
+
cross-cutting floor only, so a repository whose standard needs field-level detectors keeps a
|
|
245
|
+
caller passing `detect` until the per-standard detectors ship here.
|
|
246
|
+
- **Internal refs** reads its axes from `scripts/internal-refs.json` (keys starting with `$` are
|
|
247
|
+
notes), with exit codes 0 clean, 1 hits, 2 the gate could not run. The file may not set
|
|
248
|
+
`exitCodes`, `repoRoot` or `write`, which the command-line form owns.
|
|
249
|
+
|
|
250
|
+
### The bins, for a repository with no package.json
|
|
251
|
+
|
|
252
|
+
Every gate is also a bin (D56), so a repository with no `package.json`, or none that depends on this
|
|
253
|
+
package, runs it through npx. `script-utils` is named after the package, so npx runs it by the
|
|
254
|
+
package's name and it dispatches to the gate named first:
|
|
255
|
+
|
|
256
|
+
```sh
|
|
257
|
+
npx -y @cosyte/script-utils@0.1 no-emdash # the dispatcher: script-utils <command>
|
|
258
|
+
npx -y -p @cosyte/script-utils@0.1 cosyte-readme # or one gate's own bin
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
| bin | `script-utils` command | the gate |
|
|
262
|
+
| ---------------------- | ---------------------- | --------------------------------------------- |
|
|
263
|
+
| `cosyte-no-emdash` | `no-emdash` | the em and en dash gate, over files and names |
|
|
264
|
+
| `cosyte-attw` | `attw` | the attw publish gate, for the package here |
|
|
265
|
+
| `cosyte-phi-scan` | `phi-scan` | the PHI commit-gate |
|
|
266
|
+
| `cosyte-internal-refs` | `internal-refs` | the internal-reference gate |
|
|
267
|
+
| `cosyte-readme` | `readme` | the README gate |
|
|
268
|
+
| `cosyte-claude-card` | `claude-card` | the CLAUDE.md card checker |
|
|
269
|
+
| `cosyte-agent-notes` | `agent-notes` | the agent-notes checker |
|
|
270
|
+
| `cosyte-catalog` | `catalog` | the catalog check |
|
|
271
|
+
|
|
272
|
+
Each runs over the working directory, takes the arguments its gate takes, exits with the gate's own
|
|
273
|
+
code, and prints what it does with `--help`. `script-utils` with no command prints the list and exits 2.
|
|
274
|
+
|
|
158
275
|
### The em-dash gate, which is a file rather than a subpath
|
|
159
276
|
|
|
160
277
|
This package also ships `check-no-emdash.sh`, the one implementation of the em-dash gate for every
|
|
@@ -172,7 +289,7 @@ bash node_modules/@cosyte/script-utils/check-no-emdash.sh --self-id
|
|
|
172
289
|
|
|
173
290
|
Exit 0 means the mode completed and found nothing banned. Exit 1 means anything else: a banned form
|
|
174
291
|
was found, an input could not be read, an input was not scanned, a declaration was unusable, or an
|
|
175
|
-
argument was not
|
|
292
|
+
argument was not recognized. There is no third code. Hits and diagnostics go to stderr in every mode.
|
|
176
293
|
|
|
177
294
|
`--self-id` prints the sha256 of the copy that is executing, so a repository can prove it is running
|
|
178
295
|
these bytes rather than a fork of them. `--list-scanned` prints the NUL-separated, repo-root-relative
|
|
@@ -183,9 +300,101 @@ A repository narrows WHAT IS SCANNED, and only that, through a tracked file at i
|
|
|
183
300
|
`scripts/check-no-emdash.exclude`: one entry per line, `#` comments and blank lines ignored, an entry
|
|
184
301
|
ending in `/` covering every tracked path beneath it, and every entry anchored at the repository
|
|
185
302
|
root. An entry that matches no tracked path is refused rather than ignored, because an exclusion that
|
|
186
|
-
has outlived its subject is a hole nobody is looking at
|
|
187
|
-
banned forms are fixed in the gate. They are the em
|
|
188
|
-
the
|
|
303
|
+
has outlived its subject is a hole nobody is looking at; an excluded path's name is left out with its
|
|
304
|
+
content. Nothing narrows WHAT IS MATCHED: the banned forms are fixed in the gate. They are the em
|
|
305
|
+
dash (U+2014) and the en dash (U+2013), in any case, each as the literal character, its URL encoding,
|
|
306
|
+
its backslash-u escape (plain, braced and eight-digit), its braced backslash-x escape, its CSS escape
|
|
307
|
+
(plain and zero-padded), its Unicode name escape (a backslash, `N` and the character's name in braces), and its named, decimal and hexadecimal
|
|
308
|
+
HTML entities, with or without the semicolon and with leading zeros. The default scan also reads
|
|
309
|
+
every tracked file's NAME, because a name is copy too.
|
|
310
|
+
|
|
311
|
+
### The README gate
|
|
312
|
+
|
|
313
|
+
`@cosyte/script-utils/readme` checks a library's README against the house skeleton, and against a
|
|
314
|
+
size limit under npm's: the registry keeps only the first 65,536 characters of a README, and the
|
|
315
|
+
gate refuses one over 60,000. A library runs it from its package script, with no file of its own:
|
|
316
|
+
|
|
317
|
+
```sh
|
|
318
|
+
# "readme:check": "node node_modules/@cosyte/script-utils/readme.js"
|
|
319
|
+
node node_modules/@cosyte/script-utils/readme.js # the package in this directory
|
|
320
|
+
node node_modules/@cosyte/script-utils/readme.js --dir <path> # another package directory
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
The skeleton, in order: the shared lockup tile in a `<picture>` element with the alt text assets
|
|
324
|
+
declares for it; `# <package name>`; a one-line `>` tagline of at most 120 characters; the badge row
|
|
325
|
+
(npm version, CI, license and Node, one per line, derived from `package.json`); then the sections
|
|
326
|
+
`Why this exists`, `Status`, `Install`, `Usage`, `Support`, `Security`, `Contributing` and
|
|
327
|
+
`License`, in that order, none empty, with `License` last and linking the repository's `LICENSE` by
|
|
328
|
+
its absolute URL. A link to the package's page on docs.cosyte.com sits after `## Usage` begins and
|
|
329
|
+
before `## Support`. Other sections may sit between the required ones.
|
|
330
|
+
|
|
331
|
+
Exit 0 means the README follows the skeleton, 1 that it does not (each finding names its line and
|
|
332
|
+
its rule, from `README_RULES`), and 2 that the gate could not read the package: no README, no
|
|
333
|
+
`package.json`, or a manifest without the `@cosyte/*` name, the github.com/cosyte repository URL or
|
|
334
|
+
the `engines.node` the skeleton is derived from. Nothing is configurable, so no setting switches a
|
|
335
|
+
rule off.
|
|
336
|
+
|
|
337
|
+
### The CLAUDE.md card checker
|
|
338
|
+
|
|
339
|
+
`@cosyte/script-utils/claude-card` checks the CLAUDE.md card every Cosyte repository keeps: what
|
|
340
|
+
must pass before a push, what a change can break that a gate would not show, and the rules that bind
|
|
341
|
+
there. The spec is `documentation/claude-card.md` in cosyte/config. A repository runs it with no file
|
|
342
|
+
of its own:
|
|
343
|
+
|
|
344
|
+
```sh
|
|
345
|
+
node node_modules/@cosyte/script-utils/claude-card.js # CLAUDE.md in this directory
|
|
346
|
+
node node_modules/@cosyte/script-utils/claude-card.js --dir <path> # another repository
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
The card opens with `# <name>` and a paragraph, then has exactly three level-2 sections in order,
|
|
350
|
+
`## Gate`, `## Hazard` and `## Rules` (a heading may go on after its word, as in
|
|
351
|
+
`## Rules that bind here`), none empty. It is at most 60 lines, every line at most 100 characters
|
|
352
|
+
with code included, and at most 5,120 bytes. When an AGENTS.md sits beside it, the card imports it on
|
|
353
|
+
a line of its own, `@AGENTS.md`. Exit 0 means the card follows the spec, 1 that it does not (each
|
|
354
|
+
finding names its line and rule, from `CARD_RULES`), and 2 that CLAUDE.md could not be read.
|
|
355
|
+
|
|
356
|
+
### The catalog
|
|
357
|
+
|
|
358
|
+
`@cosyte/script-utils/catalog` is the one list of our libraries (ST13): the 8 standards (HL7 v2,
|
|
359
|
+
MLLP, FHIR, C-CDA, X12, NCPDP, ASTM and DICOM), the 6 built on them (terminology, transform, deid,
|
|
360
|
+
synth, dates and cli), and Pathways, our integration engine, in development and not on npm. Each
|
|
361
|
+
record is generated from the package's own `package.json` (name, description, release line,
|
|
362
|
+
engines, repository, docs and npm URLs) and carries its tier; the data ships as `catalog.json`
|
|
363
|
+
beside the module, and `CATALOG` is that file, frozen.
|
|
364
|
+
|
|
365
|
+
Each package.json description is that library's one canonical line (ST14), so every library runs
|
|
366
|
+
the check that its description is the catalog's, with no file of its own:
|
|
367
|
+
|
|
368
|
+
```sh
|
|
369
|
+
node node_modules/@cosyte/script-utils/catalog.js # the package in this directory
|
|
370
|
+
node node_modules/@cosyte/script-utils/catalog.js --dir <path> # another package directory
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
Exit 0 means the description is the catalog's, 1 that it is not (both values are printed), and 2
|
|
374
|
+
that the check could not run (no package.json, or a package the catalog does not list). A changed
|
|
375
|
+
description therefore goes through the catalog: regenerate it in cosyte/config
|
|
376
|
+
(`node scripts/catalog.mjs write`), release this package, then move the library to that release.
|
|
377
|
+
|
|
378
|
+
### The agent-notes checker
|
|
379
|
+
|
|
380
|
+
`@cosyte/script-utils/agent-notes` checks a repository's agent notes (RD4): what does not fit on the
|
|
381
|
+
CLAUDE.md card lives in one file, `documentation/agent-notes.md`, and the card points into it in one
|
|
382
|
+
form, `documentation/agent-notes.md#<anchor>`. A repository runs it with no file of its own:
|
|
383
|
+
|
|
384
|
+
```sh
|
|
385
|
+
node node_modules/@cosyte/script-utils/agent-notes.js # this repository
|
|
386
|
+
node node_modules/@cosyte/script-utils/agent-notes.js --dir <path> # another repository
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
It reads every file `git ls-files` lists, skipping and counting a binary file or anything that is not
|
|
390
|
+
a regular file. Every pointer in any of them must name a heading of the notes (its GitHub slug) or an
|
|
391
|
+
explicit `<a id>` or `<a name>` target. In CLAUDE.md the pointer must take the one form, not a bare
|
|
392
|
+
backticked `#anchor` or `agent-notes.md#` without its directory. A `documentation/agent-notes/`
|
|
393
|
+
directory is a finding, and so is a notes file CLAUDE.md never points into, a blank one, an empty
|
|
394
|
+
section (a heading followed by a deeper one is a container, not empty), and a citation of the
|
|
395
|
+
umbrella's deleted ADR 0023 or its doc-budget hook. A repository with no notes and no pointers
|
|
396
|
+
passes. Exit 0 means clean, 1 a finding (file, line and rule from `AGENT_NOTES_RULES`), and 2 that
|
|
397
|
+
the check could not run.
|
|
189
398
|
|
|
190
399
|
## Overrides
|
|
191
400
|
|
|
@@ -207,7 +416,7 @@ four required, six defaulted, and every per-repository difference supplied by th
|
|
|
207
416
|
will not accept is a configuration that SUBTRACTS. The canonical rule set, the self-test floor and
|
|
208
417
|
every completeness refusal are not caller inputs, and an option that reaches for one of them is
|
|
209
418
|
refused by name rather than ignored. So is an option the gate has never heard of: an ignored setting
|
|
210
|
-
reads, from the caller's side, exactly like an
|
|
419
|
+
reads, from the caller's side, exactly like an honored one.
|
|
211
420
|
|
|
212
421
|
`runAttwGate` takes the narrowest bargain of the four, and deliberately. A caller supplies where it
|
|
213
422
|
lives (`callerUrl`, required, no default) and may supply the arguments to forward; everything else
|
|
@@ -491,4 +700,4 @@ something. Never open an issue containing a real PHI value; describe the shape i
|
|
|
491
700
|
|
|
492
701
|
## License
|
|
493
702
|
|
|
494
|
-
MIT, copyright Cosyte. See [LICENSE](https://github.com/cosyte/config/blob/main/LICENSE).
|
|
703
|
+
MIT, copyright Cosyte LLC. See [LICENSE](https://github.com/cosyte/config/blob/main/LICENSE).
|
package/agent-notes.d.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for `@cosyte/script-utils/agent-notes`: the checker for a repository's agent notes, one
|
|
3
|
+
* file at `documentation/agent-notes.md` that CLAUDE.md points into as
|
|
4
|
+
* `documentation/agent-notes.md#<anchor>` (RD4).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** The one place the notes live. */
|
|
8
|
+
export declare const NOTES_PATH: "documentation/agent-notes.md";
|
|
9
|
+
|
|
10
|
+
/** A rule id a finding can carry. */
|
|
11
|
+
export type AgentNotesRule =
|
|
12
|
+
| "layout"
|
|
13
|
+
| "pointer-form"
|
|
14
|
+
| "dangling"
|
|
15
|
+
| "notes-missing"
|
|
16
|
+
| "no-pointer"
|
|
17
|
+
| "blank"
|
|
18
|
+
| "empty-section"
|
|
19
|
+
| "stale-citation";
|
|
20
|
+
|
|
21
|
+
/** Every rule id, with what it requires. */
|
|
22
|
+
export declare const AGENT_NOTES_RULES: Readonly<Record<AgentNotesRule, string>>;
|
|
23
|
+
|
|
24
|
+
/** Raised when the check cannot run; the CLI turns it into exit 2. */
|
|
25
|
+
export declare class AgentNotesRefusal extends Error {}
|
|
26
|
+
|
|
27
|
+
/** GitHub's heading slug, as github-slugger writes it. */
|
|
28
|
+
export declare function slugify(text: string): string;
|
|
29
|
+
|
|
30
|
+
/** A slugger that suffixes repeats as GitHub does: the second `Setup` is `setup-1`. */
|
|
31
|
+
export declare function makeSlugger(): (text: string) => string;
|
|
32
|
+
|
|
33
|
+
/** One heading of the notes. */
|
|
34
|
+
export interface NotesHeading {
|
|
35
|
+
level: number;
|
|
36
|
+
text: string;
|
|
37
|
+
/** 0-based line. */
|
|
38
|
+
line: number;
|
|
39
|
+
slug: string;
|
|
40
|
+
/** Nothing under it, and not a container followed by a deeper heading. */
|
|
41
|
+
empty: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The anchors a notes file offers (heading slugs and explicit `<a id>` or `<a name>` targets) and
|
|
46
|
+
* its headings.
|
|
47
|
+
*
|
|
48
|
+
* @throws {AgentNotesRefusal} On an HTML comment that never closes.
|
|
49
|
+
*/
|
|
50
|
+
export declare function readNotes(text: string): { targets: Set<string>; headings: NotesHeading[] };
|
|
51
|
+
|
|
52
|
+
/** One place the notes or a pointer depart from RD4. */
|
|
53
|
+
export interface AgentNotesFinding {
|
|
54
|
+
rule: AgentNotesRule;
|
|
55
|
+
file: string;
|
|
56
|
+
/** 1-based line, or 0 for the whole file. */
|
|
57
|
+
line: number;
|
|
58
|
+
message: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface AgentNotesInput {
|
|
62
|
+
/** CLAUDE.md's contents, or `null` when the repository has none. */
|
|
63
|
+
claude: string | null;
|
|
64
|
+
/** The notes' contents, or `null` when the repository has none. */
|
|
65
|
+
notes: string | null;
|
|
66
|
+
/** Every other tracked text file, scanned for pointers. */
|
|
67
|
+
files: { path: string; text: string }[];
|
|
68
|
+
/** Whether a `documentation/agent-notes/` directory is tracked. */
|
|
69
|
+
notesDirectory?: boolean;
|
|
70
|
+
/** Whether the repository has its own `documentation/decisions/0023-*`. */
|
|
71
|
+
localDecision0023?: boolean;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Check the notes and every pointer into them.
|
|
76
|
+
*
|
|
77
|
+
* @throws {AgentNotesRefusal} When the notes cannot be read to the end.
|
|
78
|
+
*/
|
|
79
|
+
export declare function checkAgentNotes(input: AgentNotesInput): AgentNotesFinding[];
|
|
80
|
+
|
|
81
|
+
export interface AgentNotesCheckOptions {
|
|
82
|
+
/** The repository root. Default: the working directory. */
|
|
83
|
+
dir?: string;
|
|
84
|
+
/** CLI arguments; only `--dir <path>` is accepted. */
|
|
85
|
+
argv?: string[];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Run the checker over one repository's tracked files and return the exit code: 0 clean, 1 at
|
|
90
|
+
* least one finding, 2 the check could not run. It never exits the process.
|
|
91
|
+
*/
|
|
92
|
+
export declare function runAgentNotesCheck(options?: AgentNotesCheckOptions): 0 | 1 | 2;
|