etymd 0.13.0 → 0.15.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 (38) hide show
  1. package/CHANGELOG.md +108 -0
  2. package/README.md +30 -19
  3. package/dist/{approve-YUT43YLC.js → approve-MA4Z3TBT.js} +5 -5
  4. package/dist/audit-YSALDC2L.js +11 -0
  5. package/dist/{brief-Z5S6OY2M.js → brief-DPZYSAMC.js} +5 -5
  6. package/dist/{chunk-PXRLOEN5.js → chunk-2RNQ6OLV.js} +146 -717
  7. package/dist/{chunk-DSAQ5S5D.js → chunk-CEO3BXQB.js} +3 -2
  8. package/dist/{chunk-D3R74TJ2.js → chunk-DBWDMIYO.js} +1 -1
  9. package/dist/{chunk-5BVKFJWM.js → chunk-HI7NWPRA.js} +79 -4
  10. package/dist/{chunk-2VLNI3L2.js → chunk-HOR4M6EC.js} +1 -1
  11. package/dist/chunk-IWG77WV3.js +758 -0
  12. package/dist/{chunk-DWL2IKZH.js → chunk-P6ATKV2R.js} +65 -3
  13. package/dist/{chunk-HRJJQCMT.js → chunk-UFNETE6P.js} +69 -20
  14. package/dist/{chunk-YXOAPMQH.js → chunk-Y6RZRED3.js} +2 -2
  15. package/dist/{chunk-LSZGCKIQ.js → chunk-YQZDYDAK.js} +1 -1
  16. package/dist/cli.js +42 -21
  17. package/dist/{config-XAH6PA5G.js → config-724Y3IOB.js} +1 -2
  18. package/dist/{context-F63RSIBH.js → context-JGKU4M7Z.js} +2 -4
  19. package/dist/doctor-Y3DWDEBT.js +18 -0
  20. package/dist/{fleet-YQ35KGEP.js → fleet-4FYZ3GBK.js} +11 -12
  21. package/dist/{gates-DU6SDH2M.js → gates-IBQ7HCAN.js} +6 -7
  22. package/dist/generate-KEX75XNG.js +5 -0
  23. package/dist/index.d.ts +173 -2
  24. package/dist/index.js +713 -198
  25. package/dist/{init-XJEYU2HC.js → init-H57H2JBE.js} +14 -13
  26. package/dist/ledger-T54JDHGP.js +6 -0
  27. package/dist/premise-VMC3UUIB.js +333 -0
  28. package/dist/scan-W4US23MU.js +5 -0
  29. package/dist/{scan-B24RZAV2.js → scan-XBOHDXAH.js} +5 -5
  30. package/dist/{screen-CS6PSG7U.js → screen-E4FC7W5N.js} +2 -1
  31. package/package.json +2 -2
  32. package/dist/audit-YRT4SWSQ.js +0 -12
  33. package/dist/chunk-F75Q43BC.js +0 -59
  34. package/dist/chunk-JHZ2BN4U.js +0 -67
  35. package/dist/doctor-7YKDXSKM.js +0 -19
  36. package/dist/generate-PMCP37DC.js +0 -6
  37. package/dist/ledger-4FOZ5HAB.js +0 -5
  38. package/dist/scan-QDNN7ER3.js +0 -5
package/CHANGELOG.md CHANGED
@@ -1,5 +1,113 @@
1
1
  # etymd
2
2
 
3
+ ## 0.15.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 6f40a7d: `etymd premise "<task>"` — the task you hand an agent is an instruction too. Every path, script,
8
+ well-known doc and decision id the task names is verified against the repo (a missing thing the
9
+ task is _about_ ranks as risk), and a brief hands the agent the premises only it can verify.
10
+ `--file <path>` (`-` reads stdin), `--json` (schema `premise/1`), `--no-brief`, `--fail-on <tier>`.
11
+ Zero trace in a repo that never opted in; no ledger. Prose is read with stricter rules than a code
12
+ span (a script needs the `run` form, a directory claim needs a first segment that exists, a host
13
+ name is a URL) and every class left as prose is disclosed. The command/path/doc-reference/
14
+ decision-reference truth checks are now one shared implementation used by `instruction-truth` and
15
+ `premise` alike — ids, tiers and disclosures of existing findings are unchanged.
16
+
17
+ ## 0.14.0
18
+
19
+ Knowledge pack **v8 → v12**: every generated hook and script is regenerated by `etymd gates`.
20
+ Versions 9, 10 and 11 were claimed by work that was reworked before release and stay retired,
21
+ so a pack number cited in a baseline always means exactly one pack.
22
+
23
+ ### Minor Changes
24
+
25
+ - 3056213: Three fixes to the generated gates and the onboarding flow:
26
+
27
+ - **zsh is out of the shellcheck scan.** The generated pre-push discovered shell
28
+ scripts by a shebang pattern that included zsh, but shellcheck cannot parse zsh — SC1071 is a
29
+ parser-level error no inline directive silences — so a repo whose executable surface is zsh
30
+ could never push. zsh shebangs are now excluded from the checked set and the hook prints the
31
+ exclusion (count + reason) at run time instead of going quiet about coverage.
32
+ - **`~/` home paths are no longer repo file references.** Prose like "global rules in
33
+ `~/.claude/CLAUDE.md` apply on top" made the audit demand a repo-root CLAUDE.md that was
34
+ never meant to exist — the sentence points at the reader's machine. Home-path mentions of
35
+ well-known docs are now skipped and disclosed, like absolute tokens; one ordinary mention
36
+ still makes the doc a live claim.
37
+ - **`init` no longer scaffolds AGENTS.md unasked.** `init -y` in a repo without a contract used
38
+ to write template prose nobody reviewed (and baseline it, making later deletion read as
39
+ drift). The scaffold is now opt-in via `--with-agents`; interactive runs still ask first.
40
+
41
+ - aab88c5: A content gate that cannot run is now caught, and says why.
42
+
43
+ The screen doors resolve their checker at run time, from outside the repo — so whether the gate
44
+ will actually run is the one thing reading the hook cannot tell you. When the resolved checker
45
+ turns out not to be a screener, the commit door failed closed on that program's own bare error
46
+ and the push door, advisory by design, skipped its whole-tree pass in silence. A repo could read
47
+ as screened for months while nothing screened it.
48
+
49
+ Two changes, one class:
50
+
51
+ - **The hooks explain themselves.** After a failed screen — and only then, so a clean run pays
52
+ nothing — the hook asks the checker whether it understands `screen` at all. If it does not, it
53
+ prints a line naming the version floor (`screen` needs etymd 0.11+) and the override, instead of
54
+ leaving the checker's unexplained "unknown command" as the last word. A screener reporting a
55
+ real finding is left to speak for itself.
56
+ - **`etymd audit` and `etymd doctor` check reachability.** Gate integrity now resolves the screen
57
+ runner exactly as the hook would and asks it the same question, reporting a risk-tier finding
58
+ when a checker resolves but cannot screen. No checker installed stays the designed no-op —
59
+ disclosed, never a finding — and a probe that could not be carried out claims nothing.
60
+
61
+ - 6536081: Generated hooks no longer guess at the content screener by path.
62
+
63
+ The emitted content-screen resolution used to include a bare `[ -x ./dist/cli.js ]` check ahead
64
+ of the `etymd` on PATH. That path is simply where a great many CLI projects build, so any repo
65
+ that builds its own binary there had the hook invoke THAT binary as the screener: it does not
66
+ know `screen`, so the commit door failed closed on every commit, while the push door — which
67
+ ignores the screen's exit status by design — skipped the whole-tree pass in silence. The trap
68
+ armed itself on a plain dependency install, since that runs the repo's build.
69
+
70
+ Resolution is now `CONTENT_GATE`, then whatever `etymd` is on PATH. The dev-build arm remains
71
+ for the repo that develops the screener itself, where gating on an unreleased build is the point,
72
+ but it is decided at generation time from the manifest name and emitted nowhere else.
73
+
74
+ Regenerate with `etymd gates` to pick this up; a repo needing a different runner for one
75
+ invocation still has `CONTENT_GATE`.
76
+
77
+ - 0c0bcc6: gates: generated pre-push steps run scrubbed of git's exported GIT\_\* environment
78
+
79
+ Git exports `GIT_DIR` / `GIT_WORK_TREE` / `GIT_INDEX_FILE` / … to every hook it
80
+ runs, and a child `git` that inherits them ignores its cwd. A test suite that
81
+ builds fixture repositories by shelling out to `git` therefore operates on the
82
+ REAL repository — committing into it, moving its refs — while the same suite
83
+ outside a hook is harmless, which is exactly why the defect hides: nothing run
84
+ from CI ever reproduces it. This changes the generated pre-push (`etymd gates`):
85
+
86
+ - **Every gate step runs through a `run_gate()` helper** that strips every
87
+ exported `GIT_*` name before the command runs — each name found in the
88
+ environment, not a fixed list, because git adds variables over time. A step
89
+ that genuinely means the repository finds it again from its working
90
+ directory, which for a hook is the repo root.
91
+ - **The audit and shellcheck steps stay unscrubbed**, deliberately: audit
92
+ operates on the repo it is invoked in and never descends into fixtures, and
93
+ shellcheck's `git ls-files` must see the real repo.
94
+ - **The `.local` companion note documents the wrap**, so a hand-written guard
95
+ that runs tests can scrub the same way — the companion is where repo-owned
96
+ suites live.
97
+
98
+ Existing hooks pick this up on the next `etymd gates` run.
99
+
100
+ ### Patch Changes
101
+
102
+ - 1cae71b: Context economy counts a file once when two instruction names are the same file.
103
+
104
+ `AGENTS.md` symlinked to `CLAUDE.md` is the ordinary way to serve harnesses that read different
105
+ names. Both names were measured separately, which doubled the reported always-loaded footprint —
106
+ enough to manufacture an over-budget finding out of nothing — and fired the heavy-file finding
107
+ twice for one file. Candidates resolving to the same inode (symlink or hardlink) are now counted
108
+ once and reported under every name they answer to, in `etymd audit` and `etymd context` alike,
109
+ with the merge stated in the lens disclosures.
110
+
3
111
  ## 0.13.0
4
112
 
5
113
  ### Minor Changes
package/README.md CHANGED
@@ -15,7 +15,8 @@ You wrote rules for your AI months ago. Since then a script got renamed, a folde
15
15
  changed — and the AI still trusts every word. The file never complains when it goes stale; it just
16
16
  keeps instructing, confidently, and you live with the results.
17
17
 
18
- Etymd reads those instruction files and checks every claim in them against your actual project.
18
+ Etymd reads those instruction files — and, when you ask, the task you are about to hand an agent —
19
+ and checks every claim against your actual project.
19
20
 
20
21
  One command, run in your project's folder (needs Node ≥ 18.17, nothing else): `npx etymd audit`.
21
22
  Here it is on a small demo project whose AGENTS.md still tells the AI to run `npm run start` and
@@ -110,6 +111,7 @@ cd your-project
110
111
  npx etymd audit # verify every instruction claim against the repo
111
112
  npx etymd init # opt in to drift: approve the baseline (+ scaffold AGENTS.md only if you have none)
112
113
  npx etymd audit --fail-on risk # the CI gate
114
+ npx etymd premise "fix the flaky test in src/legacy/foo.test.ts" # is this the right task?
113
115
  ```
114
116
 
115
117
  `audit` needs no setup — without `init` you get the full findings report and lose only drift
@@ -132,6 +134,14 @@ gate into a pipeline, see [In CI](#in-ci).
132
134
  - **Drift vs baseline** — documented commands/artifacts/layout that existed at approval and are
133
135
  now gone.
134
136
 
137
+ **`premise`** (via `etymd premise`) — the task itself is an instruction. Before an agent acts on
138
+ it, every path, script, well-known doc and decision id the task names is checked with the same
139
+ rules instruction files get. A path the task is _about_ and that does not exist ranks as **risk**:
140
+ the task would solve the wrong problem precisely. What cannot be read from files — that the named
141
+ things are the ones meant, that the mechanism the task assumes actually runs, that the state it
142
+ assumes holds — is handed to the agent in a brief, never guessed at. Nothing is remembered between
143
+ runs.
144
+
135
145
  **`gate-integrity`** — a CI config is a claim too: checks enforced only in CI (failures surface a
136
146
  slow pipeline after the agent finished — `etymd gates` generates the local mirror), checks only in
137
147
  skippable local hooks, latent gaps (coverage collected but nothing gates on it; commitlint
@@ -161,24 +171,25 @@ personal and employer repos. See [the fleet manifest](#the-fleet-manifest-experi
161
171
 
162
172
  ## Commands
163
173
 
164
- | Command | What it does |
165
- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
166
- | `etymd audit` | Verify every claim; ranked findings (risk → gap → polish) + ledger diff. `--lens`, `--truth`, `--json`, `--no-ledger`, `--fail-on <tier>`. |
167
- | `etymd init` | Onboard: approve the committed baseline; scaffold a minimal AGENTS.md **only if missing**. Never overwrites. |
168
- | `etymd doctor` | Alias for `audit --truth`. |
169
- | `etymd context` | The economy view: per-file always-loaded footprint + extraction candidates. |
170
- | `etymd gates` | Install local git-hook gates (pre-commit / commit-msg / pre-push, plus a publish screen where something ships) built from your own check scripts — and from the repo's shell surface, where it has one. |
171
- | `etymd screen` | Content screen: find text that must never be published. Four scopes — `--staged`, `--message`, `--tree`, `--dir`. Bring your own patterns; etymd ships none. |
172
- | `etymd scan` | The deterministic reckoning behind everything. `--json`. |
173
- | `etymd brief` | A grounded briefing your in-repo agent completes to author the semantic layer. |
174
- | `etymd approve` | Refresh the committed baseline non-interactively after intentional structural changes. |
175
- | `etymd ledger` | The findings memory: every tracked finding with status and history. |
176
- | `etymd dismiss` | `dismiss <id> --reason <text>` — a dismissed finding never resurfaces without regressing. |
177
- | `etymd accept` | `accept <id>` — record a finding as accepted reality; visible in the ledger, out of the report. |
178
- | `etymd fleet` | Sweep every project in a fleet manifest: read-only per-repo audits + manifest/wall checks. `--manifest`, `--only`, `--profile`, `--truth`, `--persist-ledgers`, `--json`, `--fail-on`. |
179
- | `etymd fleet check` | Validate the manifest pair alone (no lenses): dangling mappings, duplicate names, privacy leaks, undeclared trust, machine paths. Non-zero exit on any finding. |
180
- | `etymd fleet add` | `add <dir>` — register a project: scans it, asks for what no scan can derive, and refuses to write an entry missing a mandatory field. `--name`, `--kind`, `--profile`, `--trust`, `-y`. |
181
- | `etymd fleet dismiss` / `accept` | `<name> <id>` — resolve a project's finding from any cwd; corp findings persist beside the manifest, never in the corp worktree. |
174
+ | Command | What it does |
175
+ | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
176
+ | `etymd audit` | Verify every claim; ranked findings (risk → gap → polish) + ledger diff. `--lens`, `--truth`, `--json`, `--no-ledger`, `--fail-on <tier>`. |
177
+ | `etymd init` | Onboard: approve the committed baseline; scaffold a minimal AGENTS.md **only if missing**. Never overwrites. |
178
+ | `etymd doctor` | Alias for `audit --truth`. |
179
+ | `etymd context` | The economy view: per-file always-loaded footprint + extraction candidates. |
180
+ | `etymd gates` | Install local git-hook gates (pre-commit / commit-msg / pre-push, plus a publish screen where something ships) built from your own check scripts — and from the repo's shell surface, where it has one. |
181
+ | `etymd screen` | Content screen: find text that must never be published. Four scopes — `--staged`, `--message`, `--tree`, `--dir`. Bring your own patterns; etymd ships none. |
182
+ | `etymd scan` | The deterministic reckoning behind everything. `--json`. |
183
+ | `etymd brief` | A grounded briefing your in-repo agent completes to author the semantic layer. |
184
+ | `etymd premise` | `premise "<task>"` — is this the right task? What it names, verified against the repo; a brief for what only the agent can verify. `--file` (`-` = stdin), `--json`, `--no-brief`, `--fail-on <tier>`. No ledger. |
185
+ | `etymd approve` | Refresh the committed baseline non-interactively after intentional structural changes. |
186
+ | `etymd ledger` | The findings memory: every tracked finding with status and history. |
187
+ | `etymd dismiss` | `dismiss <id> --reason <text>` — a dismissed finding never resurfaces without regressing. |
188
+ | `etymd accept` | `accept <id>` — record a finding as accepted reality; visible in the ledger, out of the report. |
189
+ | `etymd fleet` | Sweep every project in a fleet manifest: read-only per-repo audits + manifest/wall checks. `--manifest`, `--only`, `--profile`, `--truth`, `--persist-ledgers`, `--json`, `--fail-on`. |
190
+ | `etymd fleet check` | Validate the manifest pair alone (no lenses): dangling mappings, duplicate names, privacy leaks, undeclared trust, machine paths. Non-zero exit on any finding. |
191
+ | `etymd fleet add` | `add <dir>` — register a project: scans it, asks for what no scan can derive, and refuses to write an entry missing a mandatory field. `--name`, `--kind`, `--profile`, `--trust`, `-y`. |
192
+ | `etymd fleet dismiss` / `accept` | `<name> <id>` — resolve a project's finding from any cwd; corp findings persist beside the manifest, never in the corp worktree. |
182
193
 
183
194
  `--cwd <dir>` targets another directory. Read-only probing of any repo leaves **zero trace**
184
195
  (`audit --no-ledger` writes nothing).
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { section, theme, print, renderBaselineDrift, glyph } from './chunk-5BVKFJWM.js';
3
- import { scanProject } from './chunk-YXOAPMQH.js';
4
- import { VERSION } from './chunk-D3R74TJ2.js';
5
- import { readBaseline, summarizeBaselineDrift, isDriftEmpty, writeBaseline, deriveProfile } from './chunk-JHZ2BN4U.js';
6
- import { PACK_VERSION } from './chunk-LSZGCKIQ.js';
2
+ import { section, theme, print, renderBaselineDrift, glyph } from './chunk-HI7NWPRA.js';
3
+ import { scanProject } from './chunk-Y6RZRED3.js';
4
+ import { VERSION } from './chunk-DBWDMIYO.js';
5
+ import { readBaseline, summarizeBaselineDrift, isDriftEmpty, writeBaseline, deriveProfile } from './chunk-P6ATKV2R.js';
6
+ import { PACK_VERSION } from './chunk-YQZDYDAK.js';
7
7
  import './chunk-4VPBP6K6.js';
8
8
 
9
9
  // src/commands/approve.ts
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ export { run } from './chunk-CEO3BXQB.js';
3
+ import './chunk-2RNQ6OLV.js';
4
+ import './chunk-IWG77WV3.js';
5
+ import './chunk-3E2IPCRY.js';
6
+ import './chunk-HI7NWPRA.js';
7
+ import './chunk-Y6RZRED3.js';
8
+ import './chunk-DBWDMIYO.js';
9
+ import './chunk-P6ATKV2R.js';
10
+ import './chunk-YQZDYDAK.js';
11
+ import './chunk-4VPBP6K6.js';
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { print, theme } from './chunk-5BVKFJWM.js';
3
- import { scanProject } from './chunk-YXOAPMQH.js';
4
- import './chunk-D3R74TJ2.js';
5
- import { ETYMD_DIR } from './chunk-JHZ2BN4U.js';
6
- import './chunk-LSZGCKIQ.js';
2
+ import { print, theme } from './chunk-HI7NWPRA.js';
3
+ import { scanProject } from './chunk-Y6RZRED3.js';
4
+ import './chunk-DBWDMIYO.js';
5
+ import { ETYMD_DIR } from './chunk-P6ATKV2R.js';
6
+ import './chunk-YQZDYDAK.js';
7
7
  import './chunk-4VPBP6K6.js';
8
8
  import { promises } from 'fs';
9
9
  import path from 'path';