etymd 0.10.0 → 0.11.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 +66 -0
  2. package/README.md +23 -2
  3. package/dist/{approve-6TMXJLOI.js → approve-OUJ4UPGK.js} +5 -5
  4. package/dist/audit-A75FVXHD.js +12 -0
  5. package/dist/{brief-X64HK325.js → brief-MYUESUMM.js} +7 -7
  6. package/dist/{chunk-SGW7OPHZ.js → chunk-2KVQBL4E.js} +1 -1
  7. package/dist/{chunk-V2SOHPXF.js → chunk-2VLNI3L2.js} +1 -1
  8. package/dist/{chunk-OAFYLBVG.js → chunk-3E2IPCRY.js} +3 -3
  9. package/dist/{chunk-IV3FYVTS.js → chunk-4VPBP6K6.js} +4 -3
  10. package/dist/{chunk-WTD2EIMN.js → chunk-5GQ52DK6.js} +5 -5
  11. package/dist/{chunk-YVGC3E6U.js → chunk-DWL2IKZH.js} +3 -3
  12. package/dist/{chunk-IPOAD67U.js → chunk-F75Q43BC.js} +4 -4
  13. package/dist/{chunk-EF6BPBG6.js → chunk-GWGKEPRX.js} +2 -2
  14. package/dist/{chunk-R6CVJ5D7.js → chunk-HRJJQCMT.js} +9 -13
  15. package/dist/{chunk-K34AVLDP.js → chunk-J7XVOTZL.js} +1 -1
  16. package/dist/{chunk-C7LBUFNU.js → chunk-JHZ2BN4U.js} +3 -3
  17. package/dist/{chunk-KQMQJJZK.js → chunk-JVLWM27I.js} +9 -9
  18. package/dist/{chunk-OIYNP6Y6.js → chunk-LSZGCKIQ.js} +1 -1
  19. package/dist/cli.js +19 -19
  20. package/dist/config-XAH6PA5G.js +4 -0
  21. package/dist/{context-K6DZNWAV.js → context-F63RSIBH.js} +4 -4
  22. package/dist/doctor-OZQTOUFR.js +19 -0
  23. package/dist/{fleet-4PPNUIDJ.js → fleet-Z7W3QBEV.js} +18 -18
  24. package/dist/{gates-Q7FMVUQP.js → gates-47YTMMLZ.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-QLGIYFCX.js} +10 -10
  29. package/dist/ledger-4FOZ5HAB.js +5 -0
  30. package/dist/{scan-VO776GM7.js → scan-VWEXWM6G.js} +5 -5
  31. package/dist/scan-W7RHZVSF.js +5 -0
  32. package/dist/{screen-MOQP6XC7.js → screen-NSWNC7VQ.js} +80 -10
  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
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env node
2
- import { applyFiles } from './chunk-EF6BPBG6.js';
3
- import { planWorkflow } from './chunk-R6CVJ5D7.js';
4
- import './chunk-YVGC3E6U.js';
2
+ import { applyFiles } from './chunk-GWGKEPRX.js';
3
+ import { planWorkflow } from './chunk-HRJJQCMT.js';
4
+ import './chunk-DWL2IKZH.js';
5
5
  import { theme, renderFacts, print, renderPlan, section, glyph } from './chunk-5BVKFJWM.js';
6
- import { scanProject } from './chunk-WTD2EIMN.js';
7
- import { VERSION } from './chunk-K34AVLDP.js';
8
- import { writeCachedFacts, deriveProfile, writeBaseline, CACHE_DIR } from './chunk-C7LBUFNU.js';
9
- import { PACK_VERSION } from './chunk-OIYNP6Y6.js';
10
- import { git, readText } from './chunk-IV3FYVTS.js';
11
- import { promises } from 'node:fs';
12
- import path from 'node:path';
6
+ import { scanProject } from './chunk-5GQ52DK6.js';
7
+ import { VERSION } from './chunk-J7XVOTZL.js';
8
+ import { writeCachedFacts, deriveProfile, writeBaseline, CACHE_DIR } from './chunk-JHZ2BN4U.js';
9
+ import { PACK_VERSION } from './chunk-LSZGCKIQ.js';
10
+ import { git, readText } from './chunk-4VPBP6K6.js';
11
+ import { promises } from 'fs';
12
+ import path from 'path';
13
13
  import { intro, spinner, select, confirm, outro, isCancel, cancel } from '@clack/prompts';
14
14
 
15
15
  function bail() {
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ export { accept, dismiss, list } from './chunk-2VLNI3L2.js';
3
+ import './chunk-3E2IPCRY.js';
4
+ import './chunk-5BVKFJWM.js';
5
+ import './chunk-4VPBP6K6.js';
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import { print, renderFacts, theme } from './chunk-5BVKFJWM.js';
3
- import { scanProject } from './chunk-WTD2EIMN.js';
4
- import './chunk-K34AVLDP.js';
5
- import { writeCachedFacts } from './chunk-C7LBUFNU.js';
6
- import './chunk-OIYNP6Y6.js';
7
- import './chunk-IV3FYVTS.js';
3
+ import { scanProject } from './chunk-5GQ52DK6.js';
4
+ import './chunk-J7XVOTZL.js';
5
+ import { writeCachedFacts } from './chunk-JHZ2BN4U.js';
6
+ import './chunk-LSZGCKIQ.js';
7
+ import './chunk-4VPBP6K6.js';
8
8
 
9
9
  // src/commands/scan.ts
10
10
  async function run(opts) {
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ export { scanProject } from './chunk-5GQ52DK6.js';
3
+ import './chunk-J7XVOTZL.js';
4
+ import './chunk-LSZGCKIQ.js';
5
+ import './chunk-4VPBP6K6.js';
@@ -1,14 +1,54 @@
1
1
  #!/usr/bin/env node
2
2
  import { print, glyph, theme, section } from './chunk-5BVKFJWM.js';
3
- import { git, readText, pathExists } from './chunk-IV3FYVTS.js';
4
- import { promises } from 'node:fs';
5
- import path from 'node:path';
3
+ import { git, readText, pathExists } from './chunk-4VPBP6K6.js';
4
+ import { promises } from 'fs';
5
+ import path from 'path';
6
6
 
7
7
  var MACHINE_PATH_RE = /\/(?:Users|home)\/[A-Za-z0-9._-]+\//;
8
8
  var ALLOW_MARKER = "allow-published-string";
9
9
  var ALLOW_FILE = ".etymd-screen-allow";
10
10
  var LEGACY_ALLOW_FILE = ".artifact-check-allow";
11
- function compile(raw) {
11
+ var LABELED_LINE = /^(pattern|reason|date|author)[ \t]+(.*)$/;
12
+ function compileAllow(raw) {
13
+ const entries = [];
14
+ let current = null;
15
+ const close = () => {
16
+ if (current) entries.push(current);
17
+ current = null;
18
+ };
19
+ for (const rawLine of raw.split("\n")) {
20
+ const l = rawLine.trim();
21
+ if (!l || l.startsWith("#")) continue;
22
+ const labeled = LABELED_LINE.exec(l);
23
+ if (labeled) {
24
+ const [, label = "", value = ""] = labeled;
25
+ if (label === "pattern") {
26
+ close();
27
+ current = makeAllowEntry(value);
28
+ } else if (current) {
29
+ if (label === "reason") current.reason = value.trim();
30
+ else if (label === "date") current.date = value.trim();
31
+ else current.author = value.trim();
32
+ }
33
+ } else {
34
+ close();
35
+ current = makeAllowEntry(l);
36
+ }
37
+ }
38
+ close();
39
+ return entries;
40
+ }
41
+ function makeAllowEntry(patternStr) {
42
+ try {
43
+ return { pattern: new RegExp(patternStr, "i"), isSelfName: false };
44
+ } catch {
45
+ return {
46
+ pattern: new RegExp(patternStr.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "i"),
47
+ isSelfName: false
48
+ };
49
+ }
50
+ }
51
+ function compilePatterns(raw) {
12
52
  return raw.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#")).map((l) => {
13
53
  try {
14
54
  return new RegExp(l, "i");
@@ -66,7 +106,7 @@ function screenText(text, file, patterns, allow = []) {
66
106
  const lines = text.split("\n");
67
107
  for (const [i, line] of lines.entries()) {
68
108
  if (line.includes(ALLOW_MARKER)) continue;
69
- if (allow.some((re) => re.test(line))) continue;
109
+ if (allow.some((entry) => entry.pattern.test(line))) continue;
70
110
  for (const re of patterns) {
71
111
  if (re.test(line)) {
72
112
  hits.push({ file, line: i + 1, text: line.trim().slice(0, 160), reason: String(re) });
@@ -122,15 +162,42 @@ async function run(opts) {
122
162
  );
123
163
  return;
124
164
  }
125
- const patterns = compile(rawPatterns);
165
+ const patterns = compilePatterns(rawPatterns);
126
166
  if (!patterns.length) {
127
167
  print(` ${glyph.partial} ${theme.dim(`${patternPath} has no active patterns \u2014 skipping.`)}`);
128
168
  return;
129
169
  }
130
- const allowRaw = await readText(path.join(opts.cwd, ALLOW_FILE)) ?? await readText(path.join(opts.cwd, LEGACY_ALLOW_FILE));
131
- const allow = allowRaw ? compile(allowRaw) : [];
170
+ const usingLegacy = !await pathExists(path.join(opts.cwd, ALLOW_FILE)) && await pathExists(path.join(opts.cwd, LEGACY_ALLOW_FILE));
171
+ const allowRaw = usingLegacy ? await readText(path.join(opts.cwd, LEGACY_ALLOW_FILE)) : await readText(path.join(opts.cwd, ALLOW_FILE));
172
+ const allowEntries = allowRaw ? compileAllow(allowRaw) : [];
132
173
  const selves = await selfIdentities(opts.cwd);
174
+ const validatedEntries = allowEntries.filter((entry) => {
175
+ if (entry.isSelfName) return true;
176
+ if (isSelfName(entry.pattern, selves)) {
177
+ entry.isSelfName = true;
178
+ return true;
179
+ }
180
+ if (!entry.reason || !entry.date || !entry.author) {
181
+ print(
182
+ ` ${glyph.partial} ${theme.warn(`Missing provenance for exemption pattern`)} ${theme.dim(String(entry.pattern))}`
183
+ );
184
+ print(
185
+ ` ${theme.dim("Format: a `pattern` line, then `reason`, `date`, `author` lines \u2014 a bare pattern line is a self-name exemption")}`
186
+ );
187
+ return false;
188
+ }
189
+ return true;
190
+ });
191
+ const allow = validatedEntries;
133
192
  const active = selves.length ? patterns.filter((re) => !isSelfName(re, selves)) : patterns;
193
+ if (usingLegacy) {
194
+ print(
195
+ ` ${glyph.partial} ${theme.warn(`Using legacy ${LEGACY_ALLOW_FILE} file \u2014 rename to ${ALLOW_FILE} and add provenance`)}`
196
+ );
197
+ print(
198
+ ` ${theme.dim("New format: a `pattern` line, then `reason`, `date`, `author` lines per entry")}`
199
+ );
200
+ }
134
201
  const hits = [];
135
202
  let scanned = 0;
136
203
  let skippedBinary = 0;
@@ -174,12 +241,15 @@ async function run(opts) {
174
241
  hits.push(...screenText(raw, rel, active, allow));
175
242
  }
176
243
  }
177
- if (!hits.length) return;
178
244
  section(
179
245
  `Content screen ${theme.dim(
180
246
  `\xB7 ${opts.scope} \xB7 ${scanned} file(s)${skippedBinary ? ` \xB7 ${skippedBinary} binary skipped` : ""}`
181
247
  )}`
182
248
  );
249
+ if (!hits.length) {
250
+ print(` ${glyph.ok} ${theme.dim("clean")}`);
251
+ return;
252
+ }
183
253
  for (const h of hits) {
184
254
  print(` ${theme.warn(h.file)}${theme.dim(`:${h.line}`)} ${theme.dim(`(${h.reason})`)}`);
185
255
  print(` ${h.text}`);
@@ -194,4 +264,4 @@ async function run(opts) {
194
264
  if (!opts.advisory) process.exitCode = 1;
195
265
  }
196
266
 
197
- export { isSelfName, patternLiteral, readScreenable, run, screenText, selfIdentities };
267
+ export { compileAllow, isSelfName, patternLiteral, readScreenable, run, screenText, selfIdentities };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "etymd",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Keep your agent instructions true — verify AGENTS.md, CLAUDE.md, rules & skills against the actual repo, with drift caught over time and a regression ledger.",
5
5
  "keywords": [
6
6
  "cli",
@@ -69,12 +69,12 @@
69
69
  "yaml": "2.9.0"
70
70
  },
71
71
  "devDependencies": {
72
- "@changesets/cli": "2.27.11",
72
+ "@changesets/cli": "2.31.1",
73
73
  "@types/node": "22.10.2",
74
74
  "prettier": "3.4.2",
75
- "tsup": "8.3.5",
75
+ "tsup": "8.5.1",
76
76
  "typescript": "5.7.2",
77
- "vitest": "2.1.8"
77
+ "vitest": "4.1.10"
78
78
  },
79
79
  "publishConfig": {
80
80
  "access": "public"
@@ -1,12 +0,0 @@
1
- #!/usr/bin/env node
2
- export { run } from './chunk-SGW7OPHZ.js';
3
- import './chunk-KQMQJJZK.js';
4
- import './chunk-IPOAD67U.js';
5
- import './chunk-OAFYLBVG.js';
6
- import './chunk-YVGC3E6U.js';
7
- import './chunk-5BVKFJWM.js';
8
- import './chunk-WTD2EIMN.js';
9
- import './chunk-K34AVLDP.js';
10
- import './chunk-C7LBUFNU.js';
11
- import './chunk-OIYNP6Y6.js';
12
- import './chunk-IV3FYVTS.js';
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env node
2
- export { CONFIG_FILE, DEFAULT_CONFIG, configPath, readConfig } from './chunk-YVGC3E6U.js';
3
- import './chunk-C7LBUFNU.js';
4
- import './chunk-IV3FYVTS.js';
@@ -1,19 +0,0 @@
1
- #!/usr/bin/env node
2
- import { run } from './chunk-SGW7OPHZ.js';
3
- import './chunk-KQMQJJZK.js';
4
- import './chunk-IPOAD67U.js';
5
- import './chunk-OAFYLBVG.js';
6
- import './chunk-YVGC3E6U.js';
7
- import './chunk-5BVKFJWM.js';
8
- import './chunk-WTD2EIMN.js';
9
- import './chunk-K34AVLDP.js';
10
- import './chunk-C7LBUFNU.js';
11
- import './chunk-OIYNP6Y6.js';
12
- import './chunk-IV3FYVTS.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,6 +0,0 @@
1
- #!/usr/bin/env node
2
- export { deriveFailOn, derivedCommands, planWorkflow, riskReachability } from './chunk-R6CVJ5D7.js';
3
- import './chunk-YVGC3E6U.js';
4
- import './chunk-C7LBUFNU.js';
5
- import './chunk-OIYNP6Y6.js';
6
- import './chunk-IV3FYVTS.js';
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env node
2
- export { accept, dismiss, list } from './chunk-V2SOHPXF.js';
3
- import './chunk-OAFYLBVG.js';
4
- import './chunk-5BVKFJWM.js';
5
- import './chunk-IV3FYVTS.js';
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env node
2
- export { scanProject } from './chunk-WTD2EIMN.js';
3
- import './chunk-K34AVLDP.js';
4
- import './chunk-OIYNP6Y6.js';
5
- import './chunk-IV3FYVTS.js';