etymd 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/README.md +23 -2
  3. package/dist/{approve-6TMXJLOI.js → approve-PP2QJQ3Y.js} +5 -5
  4. package/dist/audit-BXHJUTMJ.js +12 -0
  5. package/dist/{brief-X64HK325.js → brief-GDLJEG6X.js} +7 -7
  6. package/dist/{chunk-V2SOHPXF.js → chunk-2VLNI3L2.js} +1 -1
  7. package/dist/{chunk-OAFYLBVG.js → chunk-3E2IPCRY.js} +3 -3
  8. package/dist/{chunk-IV3FYVTS.js → chunk-4VPBP6K6.js} +4 -3
  9. package/dist/{chunk-YVGC3E6U.js → chunk-DWL2IKZH.js} +3 -3
  10. package/dist/{chunk-IPOAD67U.js → chunk-F75Q43BC.js} +4 -4
  11. package/dist/{chunk-EF6BPBG6.js → chunk-GWGKEPRX.js} +2 -2
  12. package/dist/{chunk-R6CVJ5D7.js → chunk-HRJJQCMT.js} +9 -13
  13. package/dist/{chunk-C7LBUFNU.js → chunk-JHZ2BN4U.js} +3 -3
  14. package/dist/{chunk-OIYNP6Y6.js → chunk-LSZGCKIQ.js} +1 -1
  15. package/dist/{chunk-WTD2EIMN.js → chunk-MTVEJ33D.js} +5 -5
  16. package/dist/{chunk-KQMQJJZK.js → chunk-O3PHW4OP.js} +9 -9
  17. package/dist/{chunk-SGW7OPHZ.js → chunk-SWA4NQHB.js} +1 -1
  18. package/dist/{chunk-K34AVLDP.js → chunk-YFNRDXUY.js} +1 -1
  19. package/dist/cli.js +25 -21
  20. package/dist/config-XAH6PA5G.js +4 -0
  21. package/dist/{context-K6DZNWAV.js → context-F63RSIBH.js} +4 -4
  22. package/dist/doctor-7SLSUSVK.js +19 -0
  23. package/dist/{fleet-4PPNUIDJ.js → fleet-5NVOUIZD.js} +18 -18
  24. package/dist/{gates-Q7FMVUQP.js → gates-OS5V3P4C.js} +10 -10
  25. package/dist/generate-PMCP37DC.js +6 -0
  26. package/dist/index.d.ts +1 -1
  27. package/dist/index.js +137 -141
  28. package/dist/{init-YYGRFIHQ.js → init-EKQ33WYS.js} +10 -10
  29. package/dist/ledger-4FOZ5HAB.js +5 -0
  30. package/dist/scan-N4BKVL5F.js +5 -0
  31. package/dist/{scan-VO776GM7.js → scan-XS4JPS7J.js} +5 -5
  32. package/dist/{screen-MOQP6XC7.js → screen-UF7VZ26C.js} +154 -20
  33. package/package.json +4 -4
  34. package/dist/audit-FGDX2AYS.js +0 -12
  35. package/dist/config-TPK5LYDM.js +0 -4
  36. package/dist/doctor-W3UZK7KS.js +0 -19
  37. package/dist/generate-NLHGTRZB.js +0 -6
  38. package/dist/ledger-B2XGANTH.js +0 -5
  39. package/dist/scan-PJSZGUG7.js +0 -5
package/CHANGELOG.md CHANGED
@@ -1,5 +1,97 @@
1
1
  # etymd
2
2
 
3
+ ## 0.12.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 060c50b: screen: forks can exempt upstream-owned files from vocabulary-class patterns
8
+
9
+ A fork that syncs from upstream stages hundreds of upstream files; a pattern that
10
+ matches ordinary wording (a "vocabulary" pattern, e.g. words a leaky _description_
11
+ would use) then fires on upstream's own already-public docs and blocks the sync
12
+ commit. This adds:
13
+
14
+ - **Pattern classes.** A `# class: vocabulary` directive in the pattern file marks
15
+ the patterns beneath it as vocabulary; everything else stays `secret`. Files with
16
+ no directive are unchanged — every pattern absolute.
17
+ - **Upstream ownership by blob identity.** With `--upstream <remote>` or
18
+ `git config etymd.upstream <remote>`, a staged/tree file whose content matches any
19
+ blob at the tips of `refs/remotes/<remote>/*` is upstream-owned, and its
20
+ vocabulary-class patterns are skipped. Secret-class patterns and the machine-path
21
+ check stay absolute everywhere. Matching is by blob sha across all upstream refs,
22
+ so a file copied verbatim to a different path (an adapter lifted from another
23
+ upstream branch) is still recognised, and a file the fork _modifies_ is screened
24
+ in full.
25
+ - **Fails closed and loud.** If the upstream ref cannot be read (a rebuild dropped
26
+ the remote), nothing is exempted and a one-line notice says so — the config signal
27
+ persists so the fork still knows it is a fork.
28
+
29
+ ## 0.11.0
30
+
31
+ ### Minor Changes
32
+
33
+ - 1193d71: Content screen: allow-file entries carry provenance, and the env bypasses are gone
34
+
35
+ Every exemption is a hole in the gate, and a hole with no name on it lives forever — nobody can
36
+ ask "is this still needed?" about an entry nobody signed. Repo-level exceptions now live in
37
+ `.etymd-screen-allow` (the previous `.artifact-check-allow` is still honoured) as records of
38
+ labeled lines:
39
+
40
+ ```
41
+ pattern ^/Users/someone
42
+ reason test fixture for machine-path detector
43
+ date 2026-08-15
44
+ author owner
45
+ ```
46
+
47
+ The pattern is the rest of its line, verbatim — it may contain any character, `|` included,
48
+ without escaping. Delimiting a free-form field in-band would be an ambiguity in the format
49
+ itself, and every parser-side guard against it only makes the misparses you imagined loud while
50
+ leaving the rest silent; the line break is the one boundary the field cannot contain.
51
+
52
+ An entry naming the repo itself needs no provenance — a bare `^widget$` line is a complete
53
+ record, the exemption being exactly as wide as the name. Anything else missing a field is
54
+ reported and does not apply, so an unprovenanced file reads as noise to fix, not as silence to
55
+ trust.
56
+
57
+ The two environment bypasses the generated hooks carried — `CONTENT_GATE_PREPUSH` and
58
+ `ARTIFACT_CHECK_SKIP` — are removed. They were off-switches invisible in the tree: nothing in
59
+ the repo records that a gate was skipped, or why. The allow file is the one bypass path left,
60
+ and every entry in it says who exempted what, when, and for what reason.
61
+
62
+ Generated hooks now resolve their screener in a defined order: an explicit `CONTENT_GATE`, then
63
+ the repo's own `./dist/cli.js` when it builds one, then the `etymd` on PATH. The middle step is
64
+ the dogfood case — a repo developing the screener must gate on its own unreleased build, or its
65
+ hooks enforce the last published behaviour against a tree that has moved past it. Repos without
66
+ a `dist/` resolve exactly as before. Pack v8 — run `etymd gates` to pick it up.
67
+
68
+ ### Patch Changes
69
+
70
+ - 652a353: Dependency advisories, 2026-08 batch: vitest 2.1.8 → 4.1.10, @changesets/cli 2.27.11 → 2.31.1,
71
+ tsup 8.3.5 → 8.5.1, plus in-range transitive fixes (js-yaml, nanoid, postcss, tmp)
72
+
73
+ Clears the whole advisory list reachable in range, then the vitest 2 → 4 major the rest of it
74
+ needed — the deliberate migration, not an audit-chased one: all 260 tests pass on 4.1.10
75
+ unchanged, config needed nothing, and the esbuild/vite/vitest development-server exposure class
76
+ (file read and execution via a listening dev server) is closed rather than reasoned around.
77
+
78
+ What remains is one low: esbuild 0.27.3–0.28.0, arbitrary file read when running a development
79
+ server on Windows, reached only through tsup (which pins ^0.27.0). Forcing an override past
80
+ tsup's declared range is audit-chasing a code path this repo never enters — nothing in it
81
+ starts a listening dev server — so it waits for a tsup release that carries esbuild 0.28.
82
+
83
+ - 9521732: Content screen: a clean run reports itself, with the file count
84
+
85
+ A clean `etymd screen` printed nothing at all — the summary header, file count and binary-skip
86
+ count only appeared when there were findings. From inside a hook, where the exit code is the
87
+ only other signal, "silent" and "never looked" were indistinguishable, which is the exact
88
+ failure the binary-skip disclosure exists to prevent (0.9.1 claimed the count is always
89
+ reported; on a clean run it never was).
90
+
91
+ Every run now prints its summary line — scope, files scanned, binary skipped — and a clean run
92
+ says so. Hooks gain one line per successful commit; a silent screen remains possible only
93
+ where the screener is absent, which the tool already reports as inert rather than clean.
94
+
3
95
  ## 0.10.0
4
96
 
5
97
  ### Minor Changes
package/README.md CHANGED
@@ -338,8 +338,29 @@ packaged into a published release while every git-scoped check passes forever.
338
338
 
339
339
  Every generated hook resolves the screener at run time and **no-ops when it is absent**, so the
340
340
  same hook file is safe to commit to a public repo: it carries no patterns and imposes no policy
341
- on anyone who clones it. A deliberate exception is marked inline with `allow-published-string`,
342
- visible in the diff rather than hidden in an allowlist.
341
+ on anyone who clones it. A deliberate exception on a line you can edit is marked inline with
342
+ `allow-published-string`, visible in the diff.
343
+
344
+ Some exemptions cannot live on the line itself: a scanner's own source contains the strings it
345
+ screens for, its tests contain fixtures that must match, and a bundler strips comments so an
346
+ inline marker would not survive into the artifact. Those live in `.etymd-screen-allow` at the
347
+ repo root — one labeled line per field, so the pattern is never delimited:
348
+
349
+ ```
350
+ pattern ^AcmeCorp|BetaCorp$
351
+ reason fixture proving the detector fires on either name
352
+ date 2026-08-15
353
+ author someone
354
+ ```
355
+
356
+ A pattern may contain any character, including the `|` shown above, without escaping: a
357
+ free-form field delimited in-band is an ambiguity in the format itself, and no amount of
358
+ parser-side guarding fixes that class — labels move the boundary to the line break, which the
359
+ field cannot contain. An entry naming the repo itself needs no provenance — a bare `^widget$`
360
+ line is a complete record, the exemption being exactly as wide as the name. Anything else
361
+ missing a field is reported and does not apply: an exemption is a hole in the gate, and a hole
362
+ nobody signed cannot be audited later. The file is read from the repo being screened, never a
363
+ shared location, and it screens itself out (it necessarily contains every string it exempts).
343
364
 
344
365
  ### The commit subject, if you ask for it
345
366
 
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import { section, theme, print, renderBaselineDrift, glyph } from './chunk-5BVKFJWM.js';
3
- import { scanProject } from './chunk-WTD2EIMN.js';
4
- import { VERSION } from './chunk-K34AVLDP.js';
5
- import { readBaseline, summarizeBaselineDrift, isDriftEmpty, writeBaseline, deriveProfile } from './chunk-C7LBUFNU.js';
6
- import { PACK_VERSION } from './chunk-OIYNP6Y6.js';
7
- import './chunk-IV3FYVTS.js';
3
+ import { scanProject } from './chunk-MTVEJ33D.js';
4
+ import { VERSION } from './chunk-YFNRDXUY.js';
5
+ import { readBaseline, summarizeBaselineDrift, isDriftEmpty, writeBaseline, deriveProfile } from './chunk-JHZ2BN4U.js';
6
+ import { PACK_VERSION } from './chunk-LSZGCKIQ.js';
7
+ import './chunk-4VPBP6K6.js';
8
8
 
9
9
  // src/commands/approve.ts
10
10
  async function run(opts) {
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ export { run } from './chunk-SWA4NQHB.js';
3
+ import './chunk-O3PHW4OP.js';
4
+ import './chunk-F75Q43BC.js';
5
+ import './chunk-3E2IPCRY.js';
6
+ import './chunk-DWL2IKZH.js';
7
+ import './chunk-5BVKFJWM.js';
8
+ import './chunk-MTVEJ33D.js';
9
+ import './chunk-YFNRDXUY.js';
10
+ import './chunk-JHZ2BN4U.js';
11
+ import './chunk-LSZGCKIQ.js';
12
+ import './chunk-4VPBP6K6.js';
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import { print, theme } from './chunk-5BVKFJWM.js';
3
- import { scanProject } from './chunk-WTD2EIMN.js';
4
- import './chunk-K34AVLDP.js';
5
- import { ETYMD_DIR } from './chunk-C7LBUFNU.js';
6
- import './chunk-OIYNP6Y6.js';
7
- import './chunk-IV3FYVTS.js';
8
- import { promises } from 'node:fs';
9
- import path from 'node:path';
3
+ import { scanProject } from './chunk-MTVEJ33D.js';
4
+ import './chunk-YFNRDXUY.js';
5
+ import { ETYMD_DIR } from './chunk-JHZ2BN4U.js';
6
+ import './chunk-LSZGCKIQ.js';
7
+ import './chunk-4VPBP6K6.js';
8
+ import { promises } from 'fs';
9
+ import path from 'path';
10
10
 
11
11
  async function run(opts) {
12
12
  const facts = await scanProject(opts.cwd);
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { readLedger, resolveEntry, writeLedger } from './chunk-OAFYLBVG.js';
2
+ import { readLedger, resolveEntry, writeLedger } from './chunk-3E2IPCRY.js';
3
3
  import { print, renderLedger, glyph, theme } from './chunk-5BVKFJWM.js';
4
4
 
5
5
  // src/commands/ledger.ts
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { readJson } from './chunk-IV3FYVTS.js';
3
- import { promises } from 'node:fs';
4
- import path from 'node:path';
2
+ import { readJson } from './chunk-4VPBP6K6.js';
3
+ import { promises } from 'fs';
4
+ import path from 'path';
5
5
 
6
6
  function ledgerPath(root) {
7
7
  return path.join(root, ".etymd", "ledger.json");
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { execFile } from 'node:child_process';
3
- import { promises } from 'node:fs';
4
- import { promisify } from 'node:util';
2
+ import { execFile } from 'child_process';
3
+ import { promises } from 'fs';
4
+ import 'path';
5
+ import { promisify } from 'util';
5
6
 
6
7
  var pExecFile = promisify(execFile);
7
8
  async function pathExists(p) {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { ETYMD_DIR } from './chunk-C7LBUFNU.js';
3
- import { pathExists, readText } from './chunk-IV3FYVTS.js';
4
- import path from 'node:path';
2
+ import { ETYMD_DIR } from './chunk-JHZ2BN4U.js';
3
+ import { pathExists, readText } from './chunk-4VPBP6K6.js';
4
+ import path from 'path';
5
5
 
6
6
  var CONFIG_FILE = path.join(ETYMD_DIR, "config.json");
7
7
  var DEFAULT_CONFIG = {
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { DEFAULT_CONFIG } from './chunk-YVGC3E6U.js';
3
- import { readText, wordCount, approxTokens, pathExists } from './chunk-IV3FYVTS.js';
4
- import { promises } from 'node:fs';
5
- import path from 'node:path';
2
+ import { DEFAULT_CONFIG } from './chunk-DWL2IKZH.js';
3
+ import { readText, wordCount, approxTokens, pathExists } from './chunk-4VPBP6K6.js';
4
+ import { promises } from 'fs';
5
+ import path from 'path';
6
6
 
7
7
  var ALWAYS_LOADED = [
8
8
  { path: "AGENTS.md", role: "operating contract" },
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { promises } from 'node:fs';
3
- import path from 'node:path';
2
+ import { promises } from 'fs';
3
+ import path from 'path';
4
4
 
5
5
  async function applyFiles(root, files, overwrite = /* @__PURE__ */ new Set()) {
6
6
  const written = [];
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { DEFAULT_CONFIG } from './chunk-YVGC3E6U.js';
3
- import { PACK_VERSION } from './chunk-OIYNP6Y6.js';
4
- import { readText, pathExists } from './chunk-IV3FYVTS.js';
5
- import path from 'node:path';
6
- import { createHash } from 'node:crypto';
2
+ import { DEFAULT_CONFIG } from './chunk-DWL2IKZH.js';
3
+ import { PACK_VERSION } from './chunk-LSZGCKIQ.js';
4
+ import { readText, pathExists } from './chunk-4VPBP6K6.js';
5
+ import path from 'path';
6
+ import { createHash } from 'crypto';
7
7
 
8
8
  var GENERATION_MARKER_RE = /^(?:# |<!-- )etymd:generated pack-v\S+ ([0-9a-f]{16})(?: -->)?$/;
9
9
  function digestOf(body) {
@@ -132,7 +132,7 @@ ${[
132
132
  "md"
133
133
  );
134
134
  }
135
- var CONTENT_GATE_RESOLUTION = `GATE="\${CONTENT_GATE:-$(command -v etymd || true)}"`;
135
+ var CONTENT_GATE_RESOLUTION = `GATE="\${CONTENT_GATE:-$(if [ -x ./dist/cli.js ]; then echo ./dist/cli.js; else command -v etymd || true; fi)}"`;
136
136
  function localHookCall(hook) {
137
137
  return `# Repo-owned checks. This file is generated and will be overwritten; \`.githooks/${hook}.local\`
138
138
  # is yours \u2014 etymd never reads, writes, or regenerates it. Put project-specific guards there.
@@ -280,7 +280,7 @@ ${auditStep}
280
280
  # with --no-verify and anything a rebase or merge brought in from elsewhere. Advisory here (it
281
281
  # never blocks the push): the blocking decision belongs at commit time, where the fix is cheap.
282
282
  ${CONTENT_GATE_RESOLUTION}
283
- if [ -x "$GATE" ] && [ "\${CONTENT_GATE_PREPUSH:-1}" = "1" ]; then
283
+ if [ -x "$GATE" ]; then
284
284
  "$GATE" screen --tree --advisory || true
285
285
  fi
286
286
 
@@ -294,14 +294,10 @@ function generateArtifactCheckScript() {
294
294
  # Wire it into the irreversible moment:
295
295
  # package.json \u2192 "prepublishOnly": "./scripts/artifact-check.sh"
296
296
  #
297
- # No-op where no checker is installed. Bypass is deliberate and loud: ARTIFACT_CHECK_SKIP=1.
297
+ # The artifact gate is the one check that sees what actually SHIPS \u2014 bypass with
298
+ # .etymd-screen-allow entries (with provenance) if you must exempt a string.
298
299
  set -eu
299
300
 
300
- if [ "\${ARTIFACT_CHECK_SKIP:-0}" = "1" ]; then
301
- echo "\u203A artifact-check: SKIPPED by ARTIFACT_CHECK_SKIP=1"
302
- exit 0
303
- fi
304
-
305
301
  ${CONTENT_GATE_RESOLUTION}
306
302
  [ -x "$GATE" ] || { echo "\u203A artifact-check: no checker installed \u2014 skipping."; exit 0; }
307
303
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { readJson } from './chunk-IV3FYVTS.js';
3
- import { promises } from 'node:fs';
4
- import path from 'node:path';
2
+ import { readJson } from './chunk-4VPBP6K6.js';
3
+ import { promises } from 'fs';
4
+ import path from 'path';
5
5
 
6
6
  var ETYMD_DIR = ".etymd";
7
7
  var CACHE_DIR = path.join(ETYMD_DIR, "cache");
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  // src/pack/version.ts
3
- var PACK_VERSION = "7";
3
+ var PACK_VERSION = "8";
4
4
 
5
5
  export { PACK_VERSION };
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { VERSION } from './chunk-K34AVLDP.js';
3
- import { PACK_VERSION } from './chunk-OIYNP6Y6.js';
4
- import { normalizeRelPath, isDirectory, readJson, git, matchesAnyGlob, pathExists, readText } from './chunk-IV3FYVTS.js';
5
- import path from 'node:path';
6
- import { promises } from 'node:fs';
2
+ import { VERSION } from './chunk-YFNRDXUY.js';
3
+ import { PACK_VERSION } from './chunk-LSZGCKIQ.js';
4
+ import { normalizeRelPath, isDirectory, readJson, git, matchesAnyGlob, pathExists, readText } from './chunk-4VPBP6K6.js';
5
+ import path from 'path';
6
+ import { promises } from 'fs';
7
7
 
8
8
  var IGNORED_DIRS = /* @__PURE__ */ new Set([
9
9
  "node_modules",
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import { measureContext } from './chunk-IPOAD67U.js';
3
- import { readLedger, reconcileLedger, writeLedger, visibleFindings } from './chunk-OAFYLBVG.js';
4
- import { DEFAULT_CONFIG, readConfig, CONFIG_FILE } from './chunk-YVGC3E6U.js';
5
- import { scanProject, expandFileGlobs } from './chunk-WTD2EIMN.js';
6
- import { ETYMD_DIR, writeCachedFacts, readBaseline, deriveProfile, baselineCarriesMachinePath, BASELINE_FILE } from './chunk-C7LBUFNU.js';
7
- import { PACK_VERSION } from './chunk-OIYNP6Y6.js';
8
- import { pathExists, readJson, readText, isDirectory, matchesAnyGlob, git, normalizeRelPath, isCiEnvironment, isExecutable } from './chunk-IV3FYVTS.js';
9
- import path from 'node:path';
2
+ import { measureContext } from './chunk-F75Q43BC.js';
3
+ import { readLedger, reconcileLedger, writeLedger, visibleFindings } from './chunk-3E2IPCRY.js';
4
+ import { DEFAULT_CONFIG, readConfig, CONFIG_FILE } from './chunk-DWL2IKZH.js';
5
+ import { scanProject, expandFileGlobs } from './chunk-MTVEJ33D.js';
6
+ import { ETYMD_DIR, writeCachedFacts, readBaseline, deriveProfile, baselineCarriesMachinePath, BASELINE_FILE } from './chunk-JHZ2BN4U.js';
7
+ import { PACK_VERSION } from './chunk-LSZGCKIQ.js';
8
+ import { pathExists, readJson, readText, isDirectory, matchesAnyGlob, git, normalizeRelPath, isCiEnvironment, isExecutable } from './chunk-4VPBP6K6.js';
9
+ import path from 'path';
10
10
  import YAML from 'yaml';
11
- import { promises } from 'node:fs';
11
+ import { promises } from 'fs';
12
12
 
13
13
  // src/engine/finding.ts
14
14
  var TIER_ORDER = { risk: 0, gap: 1, polish: 2 };
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { parseFailOnTier, runAudit, meetsFailOn } from './chunk-KQMQJJZK.js';
2
+ import { parseFailOnTier, runAudit, meetsFailOn } from './chunk-O3PHW4OP.js';
3
3
  import { print, section, theme, renderLensCoverage, renderFindings, renderLedgerDiff } from './chunk-5BVKFJWM.js';
4
4
 
5
5
  // src/commands/audit.ts
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  // package.json
3
3
  var package_default = {
4
- version: "0.10.0"};
4
+ version: "0.12.0"};
5
5
 
6
6
  // src/version.ts
7
7
  var VERSION = package_default.version;
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { VERSION } from './chunk-K34AVLDP.js';
3
- import path from 'node:path';
2
+ import { VERSION } from './chunk-YFNRDXUY.js';
3
+ import path from 'path';
4
4
  import { Command } from 'commander';
5
5
  import pc from 'picocolors';
6
6
 
@@ -31,7 +31,7 @@ program.command("audit").description("Verify every instruction claim against the
31
31
  "exit non-zero when findings at/above this tier exist (risk|gap|polish)"
32
32
  ).action(
33
33
  (opts, cmd) => action(async () => {
34
- const { run } = await import('./audit-FGDX2AYS.js');
34
+ const { run } = await import('./audit-BXHJUTMJ.js');
35
35
  await run({
36
36
  cwd: resolveCwd(cmd),
37
37
  json: opts.json,
@@ -44,7 +44,7 @@ program.command("audit").description("Verify every instruction claim against the
44
44
  );
45
45
  program.command("init").description("Onboard the truth guard: approve the baseline; scaffold AGENTS.md only if missing").option("-y, --yes", "accept defaults without prompting (never overwrites)").action(
46
46
  (opts, cmd) => action(async () => {
47
- const { run } = await import('./init-YYGRFIHQ.js');
47
+ const { run } = await import('./init-EKQ33WYS.js');
48
48
  await run({ cwd: resolveCwd(cmd), yes: opts.yes });
49
49
  })
50
50
  );
@@ -52,49 +52,49 @@ program.command("approve").description(
52
52
  "Re-approve the committed baseline after intentional structural changes (non-interactive)"
53
53
  ).action(
54
54
  (_opts, cmd) => action(async () => {
55
- const { run } = await import('./approve-6TMXJLOI.js');
55
+ const { run } = await import('./approve-PP2QJQ3Y.js');
56
56
  await run({ cwd: resolveCwd(cmd) });
57
57
  })
58
58
  );
59
59
  program.command("scan").description("Deterministically reckon the project into a facts index").option("--json", "print the raw facts as JSON").option("--no-save", "do not write the .etymd cache").action(
60
60
  (opts, cmd) => action(async () => {
61
- const { run } = await import('./scan-VO776GM7.js');
61
+ const { run } = await import('./scan-XS4JPS7J.js');
62
62
  await run({ cwd: resolveCwd(cmd), json: opts.json, save: opts.save });
63
63
  })
64
64
  );
65
65
  program.command("doctor").description('Alias for `audit --truth` \u2014 "are the recorded instructions still true?"').option("--json", "print findings as JSON").action(
66
66
  (opts, cmd) => action(async () => {
67
- const { run } = await import('./doctor-W3UZK7KS.js');
67
+ const { run } = await import('./doctor-7SLSUSVK.js');
68
68
  await run({ cwd: resolveCwd(cmd), json: opts.json });
69
69
  })
70
70
  );
71
71
  program.command("context").description("Measure the always-loaded context footprint and flag extraction candidates").option("--json", "print the budget as JSON").action(
72
72
  (opts, cmd) => action(async () => {
73
- const { run } = await import('./context-K6DZNWAV.js');
73
+ const { run } = await import('./context-F63RSIBH.js');
74
74
  await run({ cwd: resolveCwd(cmd), json: opts.json });
75
75
  })
76
76
  );
77
77
  program.command("brief").description("Emit a grounded briefing for the in-repo agent to complete the semantic layer").option("--human", "write a human onboarding brief instead of the agent briefing").action(
78
78
  (opts, cmd) => action(async () => {
79
- const { run } = await import('./brief-X64HK325.js');
79
+ const { run } = await import('./brief-GDLJEG6X.js');
80
80
  await run({ cwd: resolveCwd(cmd), human: opts.human });
81
81
  })
82
82
  );
83
83
  program.command("ledger").description("List every tracked finding grouped by status (open \xB7 accepted \xB7 dismissed \xB7 \u2026)").option("--json", "print the raw ledger as JSON").action(
84
84
  (opts, cmd) => action(async () => {
85
- const { list } = await import('./ledger-B2XGANTH.js');
85
+ const { list } = await import('./ledger-4FOZ5HAB.js');
86
86
  await list({ cwd: resolveCwd(cmd), json: opts.json });
87
87
  })
88
88
  );
89
89
  program.command("dismiss").argument("<finding-id>", "the finding id (from `etymd audit`) to dismiss").description("Dismiss a finding as a false positive / not applicable (hidden from future audits)").requiredOption("--reason <text>", "why it is dismissed \u2014 recorded so the decision survives").action(
90
90
  (id, opts, cmd) => action(async () => {
91
- const { dismiss } = await import('./ledger-B2XGANTH.js');
91
+ const { dismiss } = await import('./ledger-4FOZ5HAB.js');
92
92
  await dismiss({ cwd: resolveCwd(cmd), id, reason: opts.reason });
93
93
  })
94
94
  );
95
95
  program.command("accept").argument("<finding-id>", "the finding id (from `etymd audit`) to accept").description("Accept a real finding as a known trade-off (hidden from future audits)").option("--reason <text>", "optional note on why the trade-off is accepted").action(
96
96
  (id, opts, cmd) => action(async () => {
97
- const { accept } = await import('./ledger-B2XGANTH.js');
97
+ const { accept } = await import('./ledger-4FOZ5HAB.js');
98
98
  await accept({ cwd: resolveCwd(cmd), id, reason: opts.reason });
99
99
  })
100
100
  );
@@ -111,7 +111,7 @@ var fleet = program.command("fleet").description(
111
111
  "exit non-zero when findings at/above this tier exist (risk|gap|polish)"
112
112
  ).action(
113
113
  (opts, cmd) => action(async () => {
114
- const { sweep } = await import('./fleet-4PPNUIDJ.js');
114
+ const { sweep } = await import('./fleet-5NVOUIZD.js');
115
115
  await sweep({
116
116
  cwd: resolveCwd(cmd),
117
117
  manifest: opts.manifest,
@@ -126,7 +126,7 @@ var fleet = program.command("fleet").description(
126
126
  );
127
127
  fleet.command("check").description("Validate the manifest pair only \u2014 no lenses: dangling mappings, duplicates, leaks").option("--manifest <file>", "the fleet manifest \u2014 required unless the cwd holds registry.json").option("--json", "print the findings as JSON (EXPERIMENTAL through 0.2.x)").action(
128
128
  (_opts, cmd) => action(async () => {
129
- const { check } = await import('./fleet-4PPNUIDJ.js');
129
+ const { check } = await import('./fleet-5NVOUIZD.js');
130
130
  const opts = cmd.optsWithGlobals();
131
131
  await check({ cwd: resolveCwd(cmd), manifest: opts.manifest, json: opts.json });
132
132
  })
@@ -136,7 +136,7 @@ fleet.command("add").argument("<dir>", "directory of the project to register").d
136
136
  "public-repo | public-bound | private \u2014 mandatory for personal entries"
137
137
  ).option("-y, --yes", "skip prompts; every mandatory value must be passed as a flag").option("--manifest <file>", "the fleet manifest \u2014 required unless the cwd holds registry.json").action(
138
138
  (dir, opts, cmd) => action(async () => {
139
- const { add } = await import('./fleet-4PPNUIDJ.js');
139
+ const { add } = await import('./fleet-5NVOUIZD.js');
140
140
  const shared = cmd.optsWithGlobals();
141
141
  await add({
142
142
  cwd: resolveCwd(cmd),
@@ -159,7 +159,7 @@ fleet.command("dismiss").argument("<name>", "the registered project name").argum
159
159
  "Dismiss a project's finding from any cwd \u2014 corp ledgers persist beside the manifest"
160
160
  ).requiredOption("--reason <text>", "why it is dismissed \u2014 recorded so the decision survives").option("--manifest <file>", "the fleet manifest \u2014 required unless the cwd holds registry.json").action(
161
161
  (name, id, _opts, cmd) => action(async () => {
162
- const { dismiss } = await import('./fleet-4PPNUIDJ.js');
162
+ const { dismiss } = await import('./fleet-5NVOUIZD.js');
163
163
  const opts = cmd.optsWithGlobals();
164
164
  await dismiss({
165
165
  cwd: resolveCwd(cmd),
@@ -174,29 +174,33 @@ fleet.command("accept").argument("<name>", "the registered project name").argume
174
174
  "Accept a project's finding as a known trade-off \u2014 corp ledgers persist beside the manifest"
175
175
  ).option("--reason <text>", "optional note on why the trade-off is accepted").option("--manifest <file>", "the fleet manifest \u2014 required unless the cwd holds registry.json").action(
176
176
  (name, id, _opts, cmd) => action(async () => {
177
- const { accept } = await import('./fleet-4PPNUIDJ.js');
177
+ const { accept } = await import('./fleet-5NVOUIZD.js');
178
178
  const opts = cmd.optsWithGlobals();
179
179
  await accept({ cwd: resolveCwd(cmd), manifest: opts.manifest, name, id, reason: opts.reason });
180
180
  })
181
181
  );
182
182
  program.command("screen").description(
183
183
  "Content screen: check for text that must never be published. Bring your own patterns \u2014 etymd ships none."
184
- ).option("--staged", "screen what a commit is about to add (default)").option("--tree", "screen every tracked file \u2014 what is about to leave the machine").option("--message <file>", "screen a commit message (the commit-msg hook's $1)").option("--dir <dir>", "screen an unpacked build artifact \u2014 what actually ships").option("--patterns <file>", "pattern file (default: ~/.config/etymd/screen-patterns)").option("--advisory", "report without failing").action(
184
+ ).option("--staged", "screen what a commit is about to add (default)").option("--tree", "screen every tracked file \u2014 what is about to leave the machine").option("--message <file>", "screen a commit message (the commit-msg hook's $1)").option("--dir <dir>", "screen an unpacked build artifact \u2014 what actually ships").option("--patterns <file>", "pattern file (default: ~/.config/etymd/screen-patterns)").option("--advisory", "report without failing").option(
185
+ "--upstream <remote>",
186
+ "fork's upstream remote: files byte-identical to its refs skip vocabulary-class patterns (secret patterns stay absolute)"
187
+ ).action(
185
188
  (opts, cmd) => action(async () => {
186
- const { run } = await import('./screen-MOQP6XC7.js');
189
+ const { run } = await import('./screen-UF7VZ26C.js');
187
190
  const scope = opts.message ? "message" : opts.dir ? "dir" : opts.tree ? "tree" : "staged";
188
191
  await run({
189
192
  cwd: resolveCwd(cmd),
190
193
  scope,
191
194
  target: opts.message ?? opts.dir,
192
195
  patterns: opts.patterns,
193
- advisory: opts.advisory
196
+ advisory: opts.advisory,
197
+ upstream: opts.upstream
194
198
  });
195
199
  })
196
200
  );
197
201
  program.command("gates").description("Install the local git-hook gates (process \u2192 pre-commit, correctness \u2192 pre-push)").option("--ci", "note about the CI review gate (ships later; local gates install now)").option("-y, --yes", "skip prompts; never overwrites a hand-edited hook").action(
198
202
  (opts, cmd) => action(async () => {
199
- const { run } = await import('./gates-Q7FMVUQP.js');
203
+ const { run } = await import('./gates-OS5V3P4C.js');
200
204
  await run({ cwd: resolveCwd(cmd), ci: opts.ci, yes: opts.yes });
201
205
  })
202
206
  );
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ export { CONFIG_FILE, DEFAULT_CONFIG, configPath, readConfig } from './chunk-DWL2IKZH.js';
3
+ import './chunk-JHZ2BN4U.js';
4
+ import './chunk-4VPBP6K6.js';
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { measureContext } from './chunk-IPOAD67U.js';
3
- import { readConfig } from './chunk-YVGC3E6U.js';
2
+ import { measureContext } from './chunk-F75Q43BC.js';
3
+ import { readConfig } from './chunk-DWL2IKZH.js';
4
4
  import { print, renderContext } from './chunk-5BVKFJWM.js';
5
- import './chunk-C7LBUFNU.js';
6
- import './chunk-IV3FYVTS.js';
5
+ import './chunk-JHZ2BN4U.js';
6
+ import './chunk-4VPBP6K6.js';
7
7
 
8
8
  // src/commands/context.ts
9
9
  async function run(opts) {
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ import { run } from './chunk-SWA4NQHB.js';
3
+ import './chunk-O3PHW4OP.js';
4
+ import './chunk-F75Q43BC.js';
5
+ import './chunk-3E2IPCRY.js';
6
+ import './chunk-DWL2IKZH.js';
7
+ import './chunk-5BVKFJWM.js';
8
+ import './chunk-MTVEJ33D.js';
9
+ import './chunk-YFNRDXUY.js';
10
+ import './chunk-JHZ2BN4U.js';
11
+ import './chunk-LSZGCKIQ.js';
12
+ import './chunk-4VPBP6K6.js';
13
+
14
+ // src/commands/doctor.ts
15
+ async function run2(opts) {
16
+ await run({ cwd: opts.cwd, json: opts.json, truth: true });
17
+ }
18
+
19
+ export { run2 as run };
@@ -1,21 +1,21 @@
1
1
  #!/usr/bin/env node
2
- import { dismiss, accept } from './chunk-V2SOHPXF.js';
3
- import { parseFailOnTier, meetsFailOn, runAudit } from './chunk-KQMQJJZK.js';
4
- import './chunk-IPOAD67U.js';
5
- import { readLedger } from './chunk-OAFYLBVG.js';
6
- import { DEFAULT_CONFIG } from './chunk-YVGC3E6U.js';
2
+ import { dismiss, accept } from './chunk-2VLNI3L2.js';
3
+ import { parseFailOnTier, meetsFailOn, runAudit } from './chunk-O3PHW4OP.js';
4
+ import './chunk-F75Q43BC.js';
5
+ import { readLedger } from './chunk-3E2IPCRY.js';
6
+ import { DEFAULT_CONFIG } from './chunk-DWL2IKZH.js';
7
7
  import { print, theme, section, renderFleetRows, renderFleetNotes, renderFindings, TIER_BADGE, glyph } from './chunk-5BVKFJWM.js';
8
- import { scanProject } from './chunk-WTD2EIMN.js';
9
- import './chunk-K34AVLDP.js';
10
- import { ETYMD_DIR } from './chunk-C7LBUFNU.js';
11
- import './chunk-OIYNP6Y6.js';
12
- import { readText, pathExists, git, isDirectory } from './chunk-IV3FYVTS.js';
13
- import { promises } from 'node:fs';
14
- import os from 'node:os';
15
- import path from 'node:path';
8
+ import { scanProject } from './chunk-MTVEJ33D.js';
9
+ import './chunk-YFNRDXUY.js';
10
+ import { ETYMD_DIR } from './chunk-JHZ2BN4U.js';
11
+ import './chunk-LSZGCKIQ.js';
12
+ import { readText, pathExists, git, isDirectory } from './chunk-4VPBP6K6.js';
13
+ import { promises } from 'fs';
14
+ import os from 'os';
15
+ import path from 'path';
16
16
  import { select, isCancel, cancel, text, confirm } from '@clack/prompts';
17
- import { execFile } from 'node:child_process';
18
- import { promisify } from 'node:util';
17
+ import { execFile } from 'child_process';
18
+ import { promisify } from 'util';
19
19
 
20
20
  var FLEET_TRUST_VALUES = ["public-repo", "public-bound", "private"];
21
21
  function isFleetTrust(value) {
@@ -687,9 +687,9 @@ async function checkCorpEmails(manifest, findings, disclosures) {
687
687
  }
688
688
  }
689
689
  async function checkGateDrift(manifest, findings, disclosures) {
690
- const { planWorkflow } = await import('./generate-NLHGTRZB.js');
691
- const { scanProject: scanProject2 } = await import('./scan-PJSZGUG7.js');
692
- const { readConfig } = await import('./config-TPK5LYDM.js');
690
+ const { planWorkflow } = await import('./generate-PMCP37DC.js');
691
+ const { scanProject: scanProject2 } = await import('./scan-N4BKVL5F.js');
692
+ const { readConfig } = await import('./config-XAH6PA5G.js');
693
693
  for (const entry of manifest.entries) {
694
694
  const root = entry.resolvedRoot;
695
695
  if (!root || !await isDirectory(root)) continue;