etymd 0.16.0 → 0.19.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 +83 -0
- package/README.md +28 -5
- package/dist/{approve-K5FFTPA4.js → approve-Y36ZO6IL.js} +3 -3
- package/dist/audit-RONSEYFS.js +11 -0
- package/dist/{brief-DOQ2DQEG.js → brief-ILB6RMSQ.js} +3 -3
- package/dist/{chunk-FKDT4RBP.js → chunk-4IESOWHQ.js} +2 -2
- package/dist/{chunk-EJM47PIF.js → chunk-DLHC7QON.js} +83 -10
- package/dist/{chunk-Y4E6ERCM.js → chunk-EYUW3UJU.js} +59 -11
- package/dist/chunk-EZRK4MV3.js +109 -0
- package/dist/{chunk-OKJ3RGJB.js → chunk-HSRHOVII.js} +113 -117
- package/dist/{chunk-UV3YIBDW.js → chunk-KIPD3N77.js} +11 -6
- package/dist/{chunk-UYCGP5BS.js → chunk-L4KIIKXI.js} +1 -1
- package/dist/{chunk-YQZDYDAK.js → chunk-U7BCBJIH.js} +1 -1
- package/dist/{chunk-ANXGT7V3.js → chunk-ZCOIZVSM.js} +37 -5
- package/dist/cli.js +17 -17
- package/dist/{doctor-X6XAGKV7.js → doctor-EHRADIUZ.js} +6 -6
- package/dist/{fleet-UEFLKIRI.js → fleet-KFF3N2O7.js} +22 -6
- package/dist/{gates-NVWWKMT2.js → gates-UJ23THID.js} +9 -5
- package/dist/{generate-YEARCSHW.js → generate-6IPTCLYG.js} +3 -2
- package/dist/index.d.ts +29 -3
- package/dist/index.js +313 -52
- package/dist/{init-Z5O2WVRJ.js → init-7HWVHZMF.js} +5 -4
- package/dist/{premise-4QRU7LRI.js → premise-U6JIB2QG.js} +9 -5
- package/dist/{propose-IKE4CUIM.js → propose-NZMEPZIL.js} +6 -6
- package/dist/{scan-H3NF5IV5.js → scan-DLKYG5BB.js} +3 -3
- package/dist/scan-V53PGAQ6.js +5 -0
- package/dist/{screen-E4FC7W5N.js → screen-S736DXQ5.js} +56 -24
- package/package.json +2 -2
- package/dist/audit-HBNXNGD6.js +0 -11
- package/dist/scan-64Z6SNYF.js +0 -5
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { applyFiles } from './chunk-GWGKEPRX.js';
|
|
3
|
-
import { planWorkflow } from './chunk-
|
|
3
|
+
import { planWorkflow } from './chunk-EZRK4MV3.js';
|
|
4
|
+
import './chunk-HSRHOVII.js';
|
|
4
5
|
import { theme, renderFacts, print, renderPlan, section, glyph } from './chunk-HI7NWPRA.js';
|
|
5
|
-
import { scanProject } from './chunk-
|
|
6
|
-
import { VERSION } from './chunk-
|
|
6
|
+
import { scanProject } from './chunk-DLHC7QON.js';
|
|
7
|
+
import { VERSION } from './chunk-L4KIIKXI.js';
|
|
7
8
|
import { writeCachedFacts, deriveProfile, writeBaseline, CACHE_DIR } from './chunk-P6ATKV2R.js';
|
|
8
|
-
import { PACK_VERSION } from './chunk-
|
|
9
|
+
import { PACK_VERSION } from './chunk-U7BCBJIH.js';
|
|
9
10
|
import { git, readText } from './chunk-4VPBP6K6.js';
|
|
10
11
|
import { promises } from 'fs';
|
|
11
12
|
import path from 'path';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { parseFailOnTier, meetsFailOn, buildTruthEnv, emptyCounters, checkTextClaims, checkDocRefs, loadDecisionLedger, checkDecisionRefs, rankFindings, PATH_TOKEN_RE, KNOWN_EXTENSIONS, NAMESPACE_IDENT, NAMESPACE_STOP } from './chunk-
|
|
2
|
+
import { parseFailOnTier, meetsFailOn, buildTruthEnv, emptyCounters, checkTextClaims, checkDocRefs, loadDecisionLedger, checkDecisionRefs, rankFindings, PATH_TOKEN_RE, HOSTNAME_RE, KNOWN_EXTENSIONS, NAMESPACE_IDENT, NAMESPACE_STOP } from './chunk-EYUW3UJU.js';
|
|
3
3
|
import { print, section, theme, renderFindings } from './chunk-HI7NWPRA.js';
|
|
4
|
-
import { scanProject } from './chunk-
|
|
5
|
-
import './chunk-
|
|
4
|
+
import { scanProject } from './chunk-DLHC7QON.js';
|
|
5
|
+
import './chunk-L4KIIKXI.js';
|
|
6
6
|
import { ETYMD_DIR } from './chunk-P6ATKV2R.js';
|
|
7
|
-
import './chunk-
|
|
7
|
+
import './chunk-U7BCBJIH.js';
|
|
8
8
|
import { readText, pathExists } from './chunk-4VPBP6K6.js';
|
|
9
9
|
import path from 'path';
|
|
10
10
|
import { promises } from 'fs';
|
|
@@ -21,7 +21,6 @@ var STOP_WORDS = new Set(
|
|
|
21
21
|
);
|
|
22
22
|
var WRAP_RE = /^([([{"']*)(.*?)([.,;:!?)\]}"']*)$/;
|
|
23
23
|
var TRAIL_RE = /[.,;:!?)\]}"']*$/;
|
|
24
|
-
var HOSTNAME_RE = /^[a-z0-9-]+(?:\.[a-z0-9-]+)*\.([a-z]{2,})$/i;
|
|
25
24
|
function promoteBareTokens(text, ctx) {
|
|
26
25
|
const skips = {
|
|
27
26
|
bareInvocations: 0,
|
|
@@ -209,6 +208,11 @@ async function runPremise(opts) {
|
|
|
209
208
|
`${counters.prospectiveSkipped} path(s) sit in create-this prose (the task says to create them) \u2014 forward-looking, not missing; skipped.`
|
|
210
209
|
);
|
|
211
210
|
}
|
|
211
|
+
if (counters.fetchedSkipped) {
|
|
212
|
+
disclosures.push(
|
|
213
|
+
`${counters.fetchedSkipped} path(s) are named beside the URL they are fetched from \u2014 another tree, not this repo; skipped, not flagged.`
|
|
214
|
+
);
|
|
215
|
+
}
|
|
212
216
|
if (counters.placeholderSkipped) {
|
|
213
217
|
disclosures.push(
|
|
214
218
|
`${counters.placeholderSkipped} path(s) are naming stand-ins (e.g. \`my-feature\`) rather than real references; skipped.`
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { sweepFleet, loadFleetManifest, FLEET_JSON_SCHEMA } from './chunk-
|
|
3
|
-
import './chunk-
|
|
4
|
-
import './chunk-
|
|
2
|
+
import { sweepFleet, loadFleetManifest, FLEET_JSON_SCHEMA } from './chunk-ZCOIZVSM.js';
|
|
3
|
+
import './chunk-KIPD3N77.js';
|
|
4
|
+
import './chunk-EYUW3UJU.js';
|
|
5
5
|
import './chunk-3E2IPCRY.js';
|
|
6
6
|
import { print, section, theme, renderFleetNotes } from './chunk-HI7NWPRA.js';
|
|
7
|
-
import './chunk-
|
|
8
|
-
import './chunk-
|
|
7
|
+
import './chunk-DLHC7QON.js';
|
|
8
|
+
import './chunk-L4KIIKXI.js';
|
|
9
9
|
import './chunk-P6ATKV2R.js';
|
|
10
|
-
import './chunk-
|
|
10
|
+
import './chunk-U7BCBJIH.js';
|
|
11
11
|
import { readText } from './chunk-4VPBP6K6.js';
|
|
12
12
|
import path from 'path';
|
|
13
13
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { print, renderFacts, theme } from './chunk-HI7NWPRA.js';
|
|
3
|
-
import { scanProject } from './chunk-
|
|
4
|
-
import './chunk-
|
|
3
|
+
import { scanProject } from './chunk-DLHC7QON.js';
|
|
4
|
+
import './chunk-L4KIIKXI.js';
|
|
5
5
|
import { writeCachedFacts } from './chunk-P6ATKV2R.js';
|
|
6
|
-
import './chunk-
|
|
6
|
+
import './chunk-U7BCBJIH.js';
|
|
7
7
|
import './chunk-4VPBP6K6.js';
|
|
8
8
|
|
|
9
9
|
// src/commands/scan.ts
|
|
@@ -6,17 +6,28 @@ import { promises } from 'fs';
|
|
|
6
6
|
import path from 'path';
|
|
7
7
|
|
|
8
8
|
var CLASS_DIRECTIVE = /^#[ \t]*class:[ \t]*(secret|vocabulary)\b/i;
|
|
9
|
-
var MACHINE_PATH_RE =
|
|
9
|
+
var MACHINE_PATH_RE = /(?:^|[\s"'=(\[:])\/(?:Users|home)\/[A-Za-z0-9._-]+\//;
|
|
10
10
|
var ALLOW_MARKER = "allow-published-string";
|
|
11
11
|
var ALLOW_FILE = ".etymd-screen-allow";
|
|
12
12
|
var LEGACY_ALLOW_FILE = ".artifact-check-allow";
|
|
13
|
-
var LABELED_LINE = /^(pattern|reason|date|author)[ \t]+(.*)$/;
|
|
13
|
+
var LABELED_LINE = /^(pattern|generated|reason|date|author)[ \t]+(.*)$/;
|
|
14
|
+
function compileLooseRegex(source) {
|
|
15
|
+
try {
|
|
16
|
+
return new RegExp(source, "i");
|
|
17
|
+
} catch {
|
|
18
|
+
return new RegExp(source.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "i");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
14
21
|
function compileAllow(raw) {
|
|
15
|
-
const
|
|
22
|
+
const lines = [];
|
|
23
|
+
const generated = [];
|
|
16
24
|
let current = null;
|
|
25
|
+
let currentGen = null;
|
|
17
26
|
const close = () => {
|
|
18
|
-
if (current)
|
|
27
|
+
if (current) lines.push(current);
|
|
28
|
+
if (currentGen) generated.push(currentGen);
|
|
19
29
|
current = null;
|
|
30
|
+
currentGen = null;
|
|
20
31
|
};
|
|
21
32
|
for (const rawLine of raw.split("\n")) {
|
|
22
33
|
const l = rawLine.trim();
|
|
@@ -26,29 +37,26 @@ function compileAllow(raw) {
|
|
|
26
37
|
const [, label = "", value = ""] = labeled;
|
|
27
38
|
if (label === "pattern") {
|
|
28
39
|
close();
|
|
29
|
-
current =
|
|
40
|
+
current = { pattern: compileLooseRegex(value), isSelfName: false };
|
|
41
|
+
} else if (label === "generated") {
|
|
42
|
+
close();
|
|
43
|
+
currentGen = { path: compileLooseRegex(value) };
|
|
30
44
|
} else if (current) {
|
|
31
45
|
if (label === "reason") current.reason = value.trim();
|
|
32
46
|
else if (label === "date") current.date = value.trim();
|
|
33
47
|
else current.author = value.trim();
|
|
48
|
+
} else if (currentGen) {
|
|
49
|
+
if (label === "reason") currentGen.reason = value.trim();
|
|
50
|
+
else if (label === "date") currentGen.date = value.trim();
|
|
51
|
+
else currentGen.author = value.trim();
|
|
34
52
|
}
|
|
35
53
|
} else {
|
|
36
54
|
close();
|
|
37
|
-
current =
|
|
55
|
+
current = { pattern: compileLooseRegex(l), isSelfName: false };
|
|
38
56
|
}
|
|
39
57
|
}
|
|
40
58
|
close();
|
|
41
|
-
return
|
|
42
|
-
}
|
|
43
|
-
function makeAllowEntry(patternStr) {
|
|
44
|
-
try {
|
|
45
|
-
return { pattern: new RegExp(patternStr, "i"), isSelfName: false };
|
|
46
|
-
} catch {
|
|
47
|
-
return {
|
|
48
|
-
pattern: new RegExp(patternStr.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "i"),
|
|
49
|
-
isSelfName: false
|
|
50
|
-
};
|
|
51
|
-
}
|
|
59
|
+
return { lines, generated };
|
|
52
60
|
}
|
|
53
61
|
function compileOnePattern(l) {
|
|
54
62
|
try {
|
|
@@ -117,11 +125,11 @@ async function selfIdentities(cwd) {
|
|
|
117
125
|
names.delete("");
|
|
118
126
|
return [...names];
|
|
119
127
|
}
|
|
120
|
-
function screenText(text, file, patterns, allow = [], upstreamOwned = false) {
|
|
128
|
+
function screenText(text, file, patterns, allow = [], upstreamOwned = false, generatedData = false) {
|
|
121
129
|
const classed = patterns.map(
|
|
122
130
|
(p) => p instanceof RegExp ? { re: p, cls: "secret" } : p
|
|
123
131
|
);
|
|
124
|
-
const active = upstreamOwned ? classed.filter((p) => p.cls === "secret") : classed;
|
|
132
|
+
const active = upstreamOwned || generatedData ? classed.filter((p) => p.cls === "secret") : classed;
|
|
125
133
|
const hits = [];
|
|
126
134
|
const lines = text.split("\n");
|
|
127
135
|
for (const [i, line] of lines.entries()) {
|
|
@@ -213,9 +221,9 @@ async function run(opts) {
|
|
|
213
221
|
}
|
|
214
222
|
const usingLegacy = !await pathExists(path.join(opts.cwd, ALLOW_FILE)) && await pathExists(path.join(opts.cwd, LEGACY_ALLOW_FILE));
|
|
215
223
|
const allowRaw = usingLegacy ? await readText(path.join(opts.cwd, LEGACY_ALLOW_FILE)) : await readText(path.join(opts.cwd, ALLOW_FILE));
|
|
216
|
-
const
|
|
224
|
+
const allowFile = allowRaw ? compileAllow(allowRaw) : { lines: [], generated: [] };
|
|
217
225
|
const selves = await selfIdentities(opts.cwd);
|
|
218
|
-
const validatedEntries =
|
|
226
|
+
const validatedEntries = allowFile.lines.filter((entry) => {
|
|
219
227
|
if (entry.isSelfName) return true;
|
|
220
228
|
if (isSelfName(entry.pattern, selves)) {
|
|
221
229
|
entry.isSelfName = true;
|
|
@@ -233,6 +241,17 @@ async function run(opts) {
|
|
|
233
241
|
return true;
|
|
234
242
|
});
|
|
235
243
|
const allow = validatedEntries;
|
|
244
|
+
const generatedPaths = allowFile.generated.filter((entry) => {
|
|
245
|
+
if (entry.reason && entry.date && entry.author) return true;
|
|
246
|
+
print(
|
|
247
|
+
` ${glyph.partial} ${theme.warn(`Missing provenance for generated-path exemption`)} ${theme.dim(String(entry.path))}`
|
|
248
|
+
);
|
|
249
|
+
print(
|
|
250
|
+
` ${theme.dim("Format: a `generated` line, then `reason`, `date`, `author` lines \u2014 all four required")}`
|
|
251
|
+
);
|
|
252
|
+
return false;
|
|
253
|
+
});
|
|
254
|
+
const isGenerated = (rel) => generatedPaths.some((e) => e.path.test(rel));
|
|
236
255
|
const active = selves.length ? patterns.filter((p) => !isSelfName(p.re, selves)) : patterns;
|
|
237
256
|
const hasVocab = active.some((p) => p.cls === "vocabulary");
|
|
238
257
|
const upstreamRemote = hasVocab && (opts.scope === "staged" || opts.scope === "tree") ? opts.upstream ?? await git(opts.cwd, ["config", "--get", "etymd.upstream"]) ?? void 0 : void 0;
|
|
@@ -263,6 +282,7 @@ async function run(opts) {
|
|
|
263
282
|
const hits = [];
|
|
264
283
|
let scanned = 0;
|
|
265
284
|
let skippedBinary = 0;
|
|
285
|
+
const generatedExempted = [];
|
|
266
286
|
if (opts.scope === "message") {
|
|
267
287
|
const file = opts.target;
|
|
268
288
|
if (!file) throw new Error("--message needs the message file path (the commit-msg hook's $1)");
|
|
@@ -284,7 +304,10 @@ async function run(opts) {
|
|
|
284
304
|
continue;
|
|
285
305
|
}
|
|
286
306
|
scanned++;
|
|
287
|
-
|
|
307
|
+
const rel = path.relative(dir, f);
|
|
308
|
+
const gen = isGenerated(rel);
|
|
309
|
+
if (gen) generatedExempted.push(rel);
|
|
310
|
+
hits.push(...screenText(raw, rel, active, allow, false, gen));
|
|
288
311
|
}
|
|
289
312
|
} else {
|
|
290
313
|
const listing = opts.scope === "tree" ? await git(opts.cwd, ["ls-files"]) : await git(opts.cwd, ["diff", "--cached", "--name-only", "--diff-filter=ACM"]);
|
|
@@ -300,7 +323,9 @@ async function run(opts) {
|
|
|
300
323
|
continue;
|
|
301
324
|
}
|
|
302
325
|
scanned++;
|
|
303
|
-
|
|
326
|
+
const gen = isGenerated(rel);
|
|
327
|
+
if (gen) generatedExempted.push(rel);
|
|
328
|
+
hits.push(...screenText(raw, rel, active, allow, isUpstreamOwned(rel), gen));
|
|
304
329
|
}
|
|
305
330
|
}
|
|
306
331
|
if (upstreamNote) {
|
|
@@ -308,9 +333,16 @@ async function run(opts) {
|
|
|
308
333
|
}
|
|
309
334
|
section(
|
|
310
335
|
`Content screen ${theme.dim(
|
|
311
|
-
`\xB7 ${opts.scope} \xB7 ${scanned} file(s)${skippedBinary ? ` \xB7 ${skippedBinary} binary skipped` : ""}`
|
|
336
|
+
`\xB7 ${opts.scope} \xB7 ${scanned} file(s)${skippedBinary ? ` \xB7 ${skippedBinary} binary skipped` : ""}${generatedExempted.length ? ` \xB7 ${generatedExempted.length} generated exempt` : ""}`
|
|
312
337
|
)}`
|
|
313
338
|
);
|
|
339
|
+
if (generatedExempted.length) {
|
|
340
|
+
print(
|
|
341
|
+
` ${glyph.partial} ${theme.dim(
|
|
342
|
+
`generated data, vocabulary-class dropped (secret-class and machine paths still screened): ${generatedExempted.join(", ")}`
|
|
343
|
+
)}`
|
|
344
|
+
);
|
|
345
|
+
}
|
|
314
346
|
if (!hits.length) {
|
|
315
347
|
print(` ${glyph.ok} ${theme.dim("clean")}`);
|
|
316
348
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "etymd",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "Keep your agent instructions true — verify AGENTS.md, CLAUDE.md, rules, skills, and the task you hand an agent against the actual repo, with drift caught over time and a regression ledger.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"prettier": "3.4.2",
|
|
75
75
|
"tsup": "8.5.1",
|
|
76
76
|
"typescript": "5.7.2",
|
|
77
|
-
"vitest": "4.1.
|
|
77
|
+
"vitest": "4.1.11"
|
|
78
78
|
},
|
|
79
79
|
"publishConfig": {
|
|
80
80
|
"access": "public"
|
package/dist/audit-HBNXNGD6.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
export { run } from './chunk-FKDT4RBP.js';
|
|
3
|
-
import './chunk-UV3YIBDW.js';
|
|
4
|
-
import './chunk-Y4E6ERCM.js';
|
|
5
|
-
import './chunk-3E2IPCRY.js';
|
|
6
|
-
import './chunk-HI7NWPRA.js';
|
|
7
|
-
import './chunk-EJM47PIF.js';
|
|
8
|
-
import './chunk-UYCGP5BS.js';
|
|
9
|
-
import './chunk-P6ATKV2R.js';
|
|
10
|
-
import './chunk-YQZDYDAK.js';
|
|
11
|
-
import './chunk-4VPBP6K6.js';
|