etymd 0.9.1 → 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.
- package/CHANGELOG.md +120 -14
- package/README.md +50 -2
- package/dist/{approve-HED3NCTE.js → approve-OUJ4UPGK.js} +5 -5
- package/dist/audit-A75FVXHD.js +12 -0
- package/dist/{brief-2CXAUDNN.js → brief-MYUESUMM.js} +7 -7
- package/dist/{chunk-ULM25GWG.js → chunk-2KVQBL4E.js} +1 -1
- package/dist/{chunk-V2SOHPXF.js → chunk-2VLNI3L2.js} +1 -1
- package/dist/{chunk-OAFYLBVG.js → chunk-3E2IPCRY.js} +3 -3
- package/dist/{chunk-IV3FYVTS.js → chunk-4VPBP6K6.js} +4 -3
- package/dist/{chunk-UN7IAYM6.js → chunk-5GQ52DK6.js} +5 -5
- package/dist/{chunk-D2RI3CCT.js → chunk-DWL2IKZH.js} +12 -3
- package/dist/{chunk-JSUYV26K.js → chunk-F75Q43BC.js} +4 -4
- package/dist/{chunk-EF6BPBG6.js → chunk-GWGKEPRX.js} +2 -2
- package/dist/{chunk-WENIJMVV.js → chunk-HRJJQCMT.js} +54 -18
- package/dist/{chunk-AQM4GYGN.js → chunk-J7XVOTZL.js} +1 -1
- package/dist/{chunk-C7LBUFNU.js → chunk-JHZ2BN4U.js} +3 -3
- package/dist/{chunk-KGVRZ6WC.js → chunk-JVLWM27I.js} +9 -9
- package/dist/{chunk-6DUDIVIC.js → chunk-LSZGCKIQ.js} +1 -1
- package/dist/cli.js +19 -19
- package/dist/config-XAH6PA5G.js +4 -0
- package/dist/{context-5ANOP2IJ.js → context-F63RSIBH.js} +4 -4
- package/dist/doctor-OZQTOUFR.js +19 -0
- package/dist/{fleet-DPJSZDEY.js → fleet-Z7W3QBEV.js} +18 -18
- package/dist/{gates-RR3V4PII.js → gates-47YTMMLZ.js} +10 -10
- package/dist/generate-PMCP37DC.js +6 -0
- package/dist/index.d.ts +9 -1
- package/dist/index.js +192 -147
- package/dist/{init-RC35RS5J.js → init-QLGIYFCX.js} +10 -10
- package/dist/ledger-4FOZ5HAB.js +5 -0
- package/dist/{scan-MBXSD5RO.js → scan-VWEXWM6G.js} +5 -5
- package/dist/scan-W7RHZVSF.js +5 -0
- package/dist/{screen-EHNK6ANK.js → screen-NSWNC7VQ.js} +125 -16
- package/package.json +4 -4
- package/dist/audit-Y35XVD6Z.js +0 -12
- package/dist/config-7WCVZCM6.js +0 -4
- package/dist/doctor-DXXQJ2L3.js +0 -19
- package/dist/generate-IPY5QIR5.js +0 -6
- package/dist/ledger-B2XGANTH.js +0 -5
- package/dist/scan-KX522VKV.js +0 -5
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { applyFiles } from './chunk-
|
|
3
|
-
import { planWorkflow } from './chunk-
|
|
4
|
-
import './chunk-
|
|
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-
|
|
7
|
-
import { VERSION } from './chunk-
|
|
8
|
-
import { writeCachedFacts, deriveProfile, writeBaseline, CACHE_DIR } from './chunk-
|
|
9
|
-
import { PACK_VERSION } from './chunk-
|
|
10
|
-
import { git, readText } from './chunk-
|
|
11
|
-
import { promises } from '
|
|
12
|
-
import path from '
|
|
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() {
|
|
@@ -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-
|
|
4
|
-
import './chunk-
|
|
5
|
-
import { writeCachedFacts } from './chunk-
|
|
6
|
-
import './chunk-
|
|
7
|
-
import './chunk-
|
|
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) {
|
|
@@ -1,14 +1,54 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { print, glyph, theme, section } from './chunk-5BVKFJWM.js';
|
|
3
|
-
import {
|
|
4
|
-
import { promises } from '
|
|
5
|
-
import path from '
|
|
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
|
-
|
|
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");
|
|
@@ -17,15 +57,56 @@ function compile(raw) {
|
|
|
17
57
|
}
|
|
18
58
|
});
|
|
19
59
|
}
|
|
20
|
-
|
|
21
|
-
|
|
60
|
+
var META = ".[]*^$+?(){}|";
|
|
61
|
+
function patternLiteral(source) {
|
|
62
|
+
let out = "";
|
|
63
|
+
let i = source.startsWith("\\b") ? 2 : 0;
|
|
64
|
+
for (; i < source.length; i++) {
|
|
65
|
+
const c = source.charAt(i);
|
|
66
|
+
if (c === "\\") {
|
|
67
|
+
const next = source[i + 1];
|
|
68
|
+
if (next === void 0) return null;
|
|
69
|
+
if (/[A-Za-z0-9]/.test(next)) return next === "b" && i + 2 === source.length ? out : null;
|
|
70
|
+
out += next;
|
|
71
|
+
i++;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (META.includes(c)) return null;
|
|
75
|
+
out += c;
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
function isSelfName(pattern, selves) {
|
|
80
|
+
const literal = patternLiteral(pattern.source);
|
|
81
|
+
if (literal === null || literal === "") return false;
|
|
82
|
+
return selves.some((s) => s.toLowerCase() === literal.toLowerCase());
|
|
83
|
+
}
|
|
84
|
+
function bareName(raw) {
|
|
85
|
+
return raw.replace(/^@[^/]+\//, "").replace(/\.git$/, "");
|
|
86
|
+
}
|
|
87
|
+
async function selfIdentities(cwd) {
|
|
88
|
+
const names = /* @__PURE__ */ new Set();
|
|
89
|
+
const top = await git(cwd, ["rev-parse", "--show-toplevel"]);
|
|
90
|
+
names.add(path.basename(top || path.resolve(cwd)));
|
|
91
|
+
const pkg = await readText(path.join(top || cwd, "package.json"));
|
|
92
|
+
if (pkg) {
|
|
93
|
+
try {
|
|
94
|
+
const name = JSON.parse(pkg).name;
|
|
95
|
+
if (typeof name === "string" && name) names.add(bareName(name));
|
|
96
|
+
} catch {
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const remote = await git(cwd, ["remote", "get-url", "origin"]);
|
|
100
|
+
if (remote) names.add(bareName(path.basename(remote.trim())));
|
|
101
|
+
names.delete("");
|
|
102
|
+
return [...names];
|
|
22
103
|
}
|
|
23
104
|
function screenText(text, file, patterns, allow = []) {
|
|
24
105
|
const hits = [];
|
|
25
106
|
const lines = text.split("\n");
|
|
26
107
|
for (const [i, line] of lines.entries()) {
|
|
27
108
|
if (line.includes(ALLOW_MARKER)) continue;
|
|
28
|
-
if (allow.some((
|
|
109
|
+
if (allow.some((entry) => entry.pattern.test(line))) continue;
|
|
29
110
|
for (const re of patterns) {
|
|
30
111
|
if (re.test(line)) {
|
|
31
112
|
hits.push({ file, line: i + 1, text: line.trim().slice(0, 160), reason: String(re) });
|
|
@@ -81,17 +162,42 @@ async function run(opts) {
|
|
|
81
162
|
);
|
|
82
163
|
return;
|
|
83
164
|
}
|
|
84
|
-
const patterns =
|
|
165
|
+
const patterns = compilePatterns(rawPatterns);
|
|
85
166
|
if (!patterns.length) {
|
|
86
167
|
print(` ${glyph.partial} ${theme.dim(`${patternPath} has no active patterns \u2014 skipping.`)}`);
|
|
87
168
|
return;
|
|
88
169
|
}
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
)
|
|
94
|
-
|
|
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) : [];
|
|
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;
|
|
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
|
+
}
|
|
95
201
|
const hits = [];
|
|
96
202
|
let scanned = 0;
|
|
97
203
|
let skippedBinary = 0;
|
|
@@ -135,12 +241,15 @@ async function run(opts) {
|
|
|
135
241
|
hits.push(...screenText(raw, rel, active, allow));
|
|
136
242
|
}
|
|
137
243
|
}
|
|
138
|
-
if (!hits.length) return;
|
|
139
244
|
section(
|
|
140
245
|
`Content screen ${theme.dim(
|
|
141
246
|
`\xB7 ${opts.scope} \xB7 ${scanned} file(s)${skippedBinary ? ` \xB7 ${skippedBinary} binary skipped` : ""}`
|
|
142
247
|
)}`
|
|
143
248
|
);
|
|
249
|
+
if (!hits.length) {
|
|
250
|
+
print(` ${glyph.ok} ${theme.dim("clean")}`);
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
144
253
|
for (const h of hits) {
|
|
145
254
|
print(` ${theme.warn(h.file)}${theme.dim(`:${h.line}`)} ${theme.dim(`(${h.reason})`)}`);
|
|
146
255
|
print(` ${h.text}`);
|
|
@@ -155,4 +264,4 @@ async function run(opts) {
|
|
|
155
264
|
if (!opts.advisory) process.exitCode = 1;
|
|
156
265
|
}
|
|
157
266
|
|
|
158
|
-
export { isSelfName, readScreenable, run, screenText };
|
|
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.
|
|
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.
|
|
72
|
+
"@changesets/cli": "2.31.1",
|
|
73
73
|
"@types/node": "22.10.2",
|
|
74
74
|
"prettier": "3.4.2",
|
|
75
|
-
"tsup": "8.
|
|
75
|
+
"tsup": "8.5.1",
|
|
76
76
|
"typescript": "5.7.2",
|
|
77
|
-
"vitest": "
|
|
77
|
+
"vitest": "4.1.10"
|
|
78
78
|
},
|
|
79
79
|
"publishConfig": {
|
|
80
80
|
"access": "public"
|
package/dist/audit-Y35XVD6Z.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
export { run } from './chunk-ULM25GWG.js';
|
|
3
|
-
import './chunk-KGVRZ6WC.js';
|
|
4
|
-
import './chunk-JSUYV26K.js';
|
|
5
|
-
import './chunk-OAFYLBVG.js';
|
|
6
|
-
import './chunk-D2RI3CCT.js';
|
|
7
|
-
import './chunk-5BVKFJWM.js';
|
|
8
|
-
import './chunk-UN7IAYM6.js';
|
|
9
|
-
import './chunk-AQM4GYGN.js';
|
|
10
|
-
import './chunk-C7LBUFNU.js';
|
|
11
|
-
import './chunk-6DUDIVIC.js';
|
|
12
|
-
import './chunk-IV3FYVTS.js';
|
package/dist/config-7WCVZCM6.js
DELETED
package/dist/doctor-DXXQJ2L3.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { run } from './chunk-ULM25GWG.js';
|
|
3
|
-
import './chunk-KGVRZ6WC.js';
|
|
4
|
-
import './chunk-JSUYV26K.js';
|
|
5
|
-
import './chunk-OAFYLBVG.js';
|
|
6
|
-
import './chunk-D2RI3CCT.js';
|
|
7
|
-
import './chunk-5BVKFJWM.js';
|
|
8
|
-
import './chunk-UN7IAYM6.js';
|
|
9
|
-
import './chunk-AQM4GYGN.js';
|
|
10
|
-
import './chunk-C7LBUFNU.js';
|
|
11
|
-
import './chunk-6DUDIVIC.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 };
|
package/dist/ledger-B2XGANTH.js
DELETED