etymd 0.16.0 → 0.17.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 +26 -0
- package/README.md +18 -0
- package/dist/{approve-K5FFTPA4.js → approve-VN4EDBR5.js} +2 -2
- package/dist/{audit-HBNXNGD6.js → audit-PHAK5HEW.js} +5 -5
- package/dist/{brief-DOQ2DQEG.js → brief-7MWP35UI.js} +2 -2
- package/dist/{chunk-EJM47PIF.js → chunk-446EZNAQ.js} +1 -1
- package/dist/{chunk-FKDT4RBP.js → chunk-ANFNXFRI.js} +2 -2
- package/dist/{chunk-UYCGP5BS.js → chunk-BUMOGHQA.js} +1 -1
- package/dist/{chunk-Y4E6ERCM.js → chunk-FNA4R5KT.js} +1 -1
- package/dist/{chunk-ANXGT7V3.js → chunk-LVR2DPR7.js} +10 -5
- package/dist/{chunk-OKJ3RGJB.js → chunk-PIJZUDDQ.js} +5 -1
- package/dist/{chunk-UV3YIBDW.js → chunk-WKP7M2B3.js} +2 -2
- package/dist/cli.js +17 -17
- package/dist/{doctor-X6XAGKV7.js → doctor-R4QDCAN5.js} +5 -5
- package/dist/{fleet-UEFLKIRI.js → fleet-WPYEVHVL.js} +5 -5
- package/dist/{gates-NVWWKMT2.js → gates-3HRGYCYY.js} +7 -4
- package/dist/{generate-YEARCSHW.js → generate-FSJQFQPV.js} +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.js +13 -4
- package/dist/{init-Z5O2WVRJ.js → init-6RULX5JZ.js} +3 -3
- package/dist/{premise-4QRU7LRI.js → premise-GFWHSR3K.js} +3 -3
- package/dist/{propose-IKE4CUIM.js → propose-IYNOIWAO.js} +5 -5
- package/dist/scan-5SC47FSM.js +5 -0
- package/dist/{scan-H3NF5IV5.js → scan-LLWW4YOU.js} +2 -2
- package/dist/{screen-E4FC7W5N.js → screen-S736DXQ5.js} +56 -24
- package/package.json +1 -1
- package/dist/scan-64Z6SNYF.js +0 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# etymd
|
|
2
2
|
|
|
3
|
+
## 0.17.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- The content screen's allow file accepts a `generated <path-regex>` record: a path declared
|
|
8
|
+
as regenerated data is still read and still screened, but vocabulary-class patterns drop
|
|
9
|
+
for it — secret-class patterns and the machine-path check stay — and the exempted paths
|
|
10
|
+
are named in the output, so a clean run never reads as fully screened. Provenance
|
|
11
|
+
(reason, date, author) is required.
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- 2bceef1: The fleet's gate-drift check now derives the pre-push audit tier the same way `etymd gates`
|
|
16
|
+
does. In a repo where no risk-tier rule can fire (no package manifest, no state doc) the
|
|
17
|
+
generator lowers the audit line to `--fail-on gap`; the drift comparison planned with the raw
|
|
18
|
+
config tier (`risk`), so its expectation permanently differed from the hook the generator
|
|
19
|
+
itself writes — a `gate-stale` finding on every repo of that shape, unclearable by the action
|
|
20
|
+
it names. The derivation now lives in `planWorkflow` itself, where the hook is built, so every
|
|
21
|
+
caller (the drift check, `etymd init`, the programmatic surface) generates identical bytes; a
|
|
22
|
+
tier the repo pinned in config is still never lowered.
|
|
23
|
+
- 7221fea: The content screen's machine-path rule now fires only at a path boundary (line start,
|
|
24
|
+
whitespace, a quote, `=`, `(`, `[` or `:`). A home path inside a longer token or a URL —
|
|
25
|
+
a test fixture's temp root (`$ROOT/home/‹x›/`), a docs URL with a home segment — is not a
|
|
26
|
+
machine path, and no longer prints the same advisory line on every push. A bare
|
|
27
|
+
`/Users/<name>/…` or `/home/<name>/…` still hits.
|
|
28
|
+
|
|
3
29
|
## 0.16.0
|
|
4
30
|
|
|
5
31
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -375,6 +375,24 @@ missing a field is reported and does not apply: an exemption is a hole in the ga
|
|
|
375
375
|
nobody signed cannot be audited later. The file is read from the repo being screened, never a
|
|
376
376
|
shared location, and it screens itself out (it necessarily contains every string it exempts).
|
|
377
377
|
|
|
378
|
+
The file carries a second record kind, for paths rather than lines:
|
|
379
|
+
|
|
380
|
+
```
|
|
381
|
+
generated ^src/data/corpus\.json$
|
|
382
|
+
reason public-domain corpus, regenerated by scripts/corpus each January
|
|
383
|
+
date 2026-09-04
|
|
384
|
+
author someone
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
A `generated` path is data a pipeline rebuilds — a public-domain corpus, generated fixtures —
|
|
388
|
+
and period English trips credential vocabulary (`passkey`, `secret`) on a schedule, training
|
|
389
|
+
exactly the `--no-verify` habit the screen exists to prevent. The file is still read and still
|
|
390
|
+
screened: only vocabulary-class patterns drop for it, while secret-class patterns and the
|
|
391
|
+
machine-path check stay — a generated file is precisely where a real credential would be least
|
|
392
|
+
visible. Provenance is unconditional (a path is never the repo naming itself), and the paths
|
|
393
|
+
that took the exemption are named in the output, so a clean run never reads as fully screened
|
|
394
|
+
where it was screened narrower.
|
|
395
|
+
|
|
378
396
|
### The commit subject, if you ask for it
|
|
379
397
|
|
|
380
398
|
Off unless you turn it on:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { section, theme, print, renderBaselineDrift, glyph } from './chunk-HI7NWPRA.js';
|
|
3
|
-
import { scanProject } from './chunk-
|
|
4
|
-
import { VERSION } from './chunk-
|
|
3
|
+
import { scanProject } from './chunk-446EZNAQ.js';
|
|
4
|
+
import { VERSION } from './chunk-BUMOGHQA.js';
|
|
5
5
|
import { readBaseline, summarizeBaselineDrift, isDriftEmpty, writeBaseline, deriveProfile } from './chunk-P6ATKV2R.js';
|
|
6
6
|
import { PACK_VERSION } from './chunk-YQZDYDAK.js';
|
|
7
7
|
import './chunk-4VPBP6K6.js';
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
export { run } from './chunk-
|
|
3
|
-
import './chunk-
|
|
4
|
-
import './chunk-
|
|
2
|
+
export { run } from './chunk-ANFNXFRI.js';
|
|
3
|
+
import './chunk-WKP7M2B3.js';
|
|
4
|
+
import './chunk-FNA4R5KT.js';
|
|
5
5
|
import './chunk-3E2IPCRY.js';
|
|
6
6
|
import './chunk-HI7NWPRA.js';
|
|
7
|
-
import './chunk-
|
|
8
|
-
import './chunk-
|
|
7
|
+
import './chunk-446EZNAQ.js';
|
|
8
|
+
import './chunk-BUMOGHQA.js';
|
|
9
9
|
import './chunk-P6ATKV2R.js';
|
|
10
10
|
import './chunk-YQZDYDAK.js';
|
|
11
11
|
import './chunk-4VPBP6K6.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { print, theme } from './chunk-HI7NWPRA.js';
|
|
3
|
-
import { scanProject } from './chunk-
|
|
4
|
-
import './chunk-
|
|
3
|
+
import { scanProject } from './chunk-446EZNAQ.js';
|
|
4
|
+
import './chunk-BUMOGHQA.js';
|
|
5
5
|
import { ETYMD_DIR } from './chunk-P6ATKV2R.js';
|
|
6
6
|
import './chunk-YQZDYDAK.js';
|
|
7
7
|
import './chunk-4VPBP6K6.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { VERSION } from './chunk-
|
|
2
|
+
import { VERSION } from './chunk-BUMOGHQA.js';
|
|
3
3
|
import { PACK_VERSION } from './chunk-YQZDYDAK.js';
|
|
4
4
|
import { normalizeRelPath, isDirectory, readJson, git, matchesAnyGlob, pathExists, readText } from './chunk-4VPBP6K6.js';
|
|
5
5
|
import path from 'path';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { runAudit } from './chunk-
|
|
3
|
-
import { parseFailOnTier, meetsFailOn } from './chunk-
|
|
2
|
+
import { runAudit } from './chunk-WKP7M2B3.js';
|
|
3
|
+
import { parseFailOnTier, meetsFailOn } from './chunk-FNA4R5KT.js';
|
|
4
4
|
import { print, section, theme, renderLensCoverage, renderFindings, renderLedgerDiff } from './chunk-HI7NWPRA.js';
|
|
5
5
|
|
|
6
6
|
// src/commands/audit.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { expandFileGlobs } from './chunk-
|
|
2
|
+
import { expandFileGlobs } from './chunk-446EZNAQ.js';
|
|
3
3
|
import { DEFAULT_CONFIG, CONFIG_FILE } from './chunk-P6ATKV2R.js';
|
|
4
4
|
import { readText, isDirectory, matchesAnyGlob, normalizeRelPath, readJson, pathExists, git } from './chunk-4VPBP6K6.js';
|
|
5
5
|
import path3 from 'path';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { runAudit } from './chunk-
|
|
2
|
+
import { runAudit } from './chunk-WKP7M2B3.js';
|
|
3
3
|
import { readLedger } from './chunk-3E2IPCRY.js';
|
|
4
4
|
import { DEFAULT_CONFIG, ETYMD_DIR } from './chunk-P6ATKV2R.js';
|
|
5
5
|
import { readText, isDirectory, git, pathExists } from './chunk-4VPBP6K6.js';
|
|
@@ -1005,8 +1005,8 @@ async function checkGuardedEmails(manifest, findings, disclosures) {
|
|
|
1005
1005
|
}
|
|
1006
1006
|
}
|
|
1007
1007
|
async function checkGateDrift(manifest, findings, disclosures) {
|
|
1008
|
-
const { planWorkflow } = await import('./generate-
|
|
1009
|
-
const { scanProject } = await import('./scan-
|
|
1008
|
+
const { planWorkflow } = await import('./generate-FSJQFQPV.js');
|
|
1009
|
+
const { scanProject } = await import('./scan-5SC47FSM.js');
|
|
1010
1010
|
const { readConfig } = await import('./config-724Y3IOB.js');
|
|
1011
1011
|
for (const entry of manifest.entries) {
|
|
1012
1012
|
const root = entry.resolvedRoot;
|
|
@@ -1024,8 +1024,13 @@ async function checkGateDrift(manifest, findings, disclosures) {
|
|
|
1024
1024
|
);
|
|
1025
1025
|
continue;
|
|
1026
1026
|
}
|
|
1027
|
-
const { config } = await readConfig(root);
|
|
1028
|
-
const planned = (await planWorkflow(root, facts, {
|
|
1027
|
+
const { config, explicit } = await readConfig(root);
|
|
1028
|
+
const planned = (await planWorkflow(root, facts, {
|
|
1029
|
+
agents: false,
|
|
1030
|
+
gates: true,
|
|
1031
|
+
gateConfig: config.gates,
|
|
1032
|
+
gateFailOnPinned: explicit.gatesFailOn
|
|
1033
|
+
})).filter((f) => f.executable);
|
|
1029
1034
|
const missing = planned.filter((f) => !f.exists).map((f) => f.path);
|
|
1030
1035
|
const differing = planned.filter((f) => f.exists && f.differs);
|
|
1031
1036
|
const stale = differing.filter((f) => f.drift !== "edited").map((f) => f.path);
|
|
@@ -431,9 +431,13 @@ async function planWorkflow(root, facts, opts) {
|
|
|
431
431
|
commitFormat: opts.gateConfig?.commitFormat,
|
|
432
432
|
allowWriting: opts.gateConfig?.allowWriting ?? []
|
|
433
433
|
};
|
|
434
|
+
const tier = deriveFailOn(facts, {
|
|
435
|
+
failOn: gateConfig.failOn,
|
|
436
|
+
explicit: opts.gateFailOnPinned ?? false
|
|
437
|
+
});
|
|
434
438
|
await add(
|
|
435
439
|
".githooks/pre-push",
|
|
436
|
-
generatePrePushHook(facts, gateConfig, selfBuild),
|
|
440
|
+
generatePrePushHook(facts, { ...gateConfig, failOn: tier.failOn }, selfBuild),
|
|
437
441
|
"Correctness gate (pre-push)",
|
|
438
442
|
true
|
|
439
443
|
);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { stateFreshnessLens, rankFindings, listInstructionFiles, buildTruthEnv, emptyCounters, packageManagerUsage, checkDocRefs, listStateDocuments, loadDecisionLedger, checkDecisionRefs, checkTextClaims } from './chunk-
|
|
2
|
+
import { stateFreshnessLens, rankFindings, listInstructionFiles, buildTruthEnv, emptyCounters, packageManagerUsage, checkDocRefs, listStateDocuments, loadDecisionLedger, checkDecisionRefs, checkTextClaims } from './chunk-FNA4R5KT.js';
|
|
3
3
|
import { readLedger, reconcileLedger, writeLedger, visibleFindings } from './chunk-3E2IPCRY.js';
|
|
4
4
|
import { measureContext, contextFileLabel } from './chunk-HI7NWPRA.js';
|
|
5
|
-
import { scanProject } from './chunk-
|
|
5
|
+
import { scanProject } from './chunk-446EZNAQ.js';
|
|
6
6
|
import { DEFAULT_CONFIG, ETYMD_DIR, writeCachedFacts, readBaseline, readConfig, deriveProfile, baselineCarriesMachinePath, BASELINE_FILE, CONFIG_FILE } from './chunk-P6ATKV2R.js';
|
|
7
7
|
import { PACK_VERSION } from './chunk-YQZDYDAK.js';
|
|
8
8
|
import { pathExists, readText, readJson, isCiEnvironment, isExecutable } from './chunk-4VPBP6K6.js';
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { VERSION } from './chunk-
|
|
2
|
+
import { VERSION } from './chunk-BUMOGHQA.js';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import { Command } from 'commander';
|
|
5
5
|
import pc from 'picocolors';
|
|
@@ -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-
|
|
34
|
+
const { run } = await import('./audit-PHAK5HEW.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 asked").option("-y, --yes", "accept defaults without prompting (never overwrites)").option("--with-agents", "also scaffold a minimal AGENTS.md where none exists (off by default)").action(
|
|
46
46
|
(opts, cmd) => action(async () => {
|
|
47
|
-
const { run } = await import('./init-
|
|
47
|
+
const { run } = await import('./init-6RULX5JZ.js');
|
|
48
48
|
await run({ cwd: resolveCwd(cmd), yes: opts.yes, withAgents: opts.withAgents });
|
|
49
49
|
})
|
|
50
50
|
);
|
|
@@ -52,19 +52,19 @@ 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-
|
|
55
|
+
const { run } = await import('./approve-VN4EDBR5.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-
|
|
61
|
+
const { run } = await import('./scan-LLWW4YOU.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-
|
|
67
|
+
const { run } = await import('./doctor-R4QDCAN5.js');
|
|
68
68
|
await run({ cwd: resolveCwd(cmd), json: opts.json });
|
|
69
69
|
})
|
|
70
70
|
);
|
|
@@ -76,7 +76,7 @@ program.command("context").description("Measure the always-loaded context footpr
|
|
|
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-
|
|
79
|
+
const { run } = await import('./brief-7MWP35UI.js');
|
|
80
80
|
await run({ cwd: resolveCwd(cmd), human: opts.human });
|
|
81
81
|
})
|
|
82
82
|
);
|
|
@@ -90,7 +90,7 @@ program.command("premise").argument("[task]", "the task you are about to hand an
|
|
|
90
90
|
"exit non-zero when findings at/above this tier exist (risk|gap|polish)"
|
|
91
91
|
).action(
|
|
92
92
|
(task, opts, cmd) => action(async () => {
|
|
93
|
-
const { run } = await import('./premise-
|
|
93
|
+
const { run } = await import('./premise-GFWHSR3K.js');
|
|
94
94
|
await run({
|
|
95
95
|
cwd: resolveCwd(cmd),
|
|
96
96
|
task,
|
|
@@ -132,7 +132,7 @@ var fleet = program.command("fleet").description(
|
|
|
132
132
|
"exit non-zero when findings at/above this tier exist (risk|gap|polish)"
|
|
133
133
|
).action(
|
|
134
134
|
(opts, cmd) => action(async () => {
|
|
135
|
-
const { sweep } = await import('./fleet-
|
|
135
|
+
const { sweep } = await import('./fleet-WPYEVHVL.js');
|
|
136
136
|
await sweep({
|
|
137
137
|
cwd: resolveCwd(cmd),
|
|
138
138
|
manifest: opts.manifest,
|
|
@@ -147,7 +147,7 @@ var fleet = program.command("fleet").description(
|
|
|
147
147
|
);
|
|
148
148
|
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(
|
|
149
149
|
(_opts, cmd) => action(async () => {
|
|
150
|
-
const { check } = await import('./fleet-
|
|
150
|
+
const { check } = await import('./fleet-WPYEVHVL.js');
|
|
151
151
|
const opts = cmd.optsWithGlobals();
|
|
152
152
|
await check({ cwd: resolveCwd(cmd), manifest: opts.manifest, json: opts.json });
|
|
153
153
|
})
|
|
@@ -156,7 +156,7 @@ fleet.command("board").description(
|
|
|
156
156
|
"Render the fleet board: every project's milestones (contract key `milestones`) plus a ranked initiatives table"
|
|
157
157
|
).option("--manifest <file>", "the fleet manifest \u2014 required unless the cwd holds registry.json").option("--initiatives <file>", "the hand-edited initiatives table (rank | id | initiative | \u2026)").option("--out <file>", "write the Markdown board here instead of printing it").option("--json", "print the board as JSON (EXPERIMENTAL)").action(
|
|
158
158
|
(opts, cmd) => action(async () => {
|
|
159
|
-
const { board } = await import('./fleet-
|
|
159
|
+
const { board } = await import('./fleet-WPYEVHVL.js');
|
|
160
160
|
const shared = cmd.optsWithGlobals();
|
|
161
161
|
await board({
|
|
162
162
|
cwd: resolveCwd(cmd),
|
|
@@ -172,7 +172,7 @@ fleet.command("add").argument("<dir>", "directory of the project to register").d
|
|
|
172
172
|
"public-repo | public-bound | private \u2014 mandatory for personal entries"
|
|
173
173
|
).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(
|
|
174
174
|
(dir, opts, cmd) => action(async () => {
|
|
175
|
-
const { add } = await import('./fleet-
|
|
175
|
+
const { add } = await import('./fleet-WPYEVHVL.js');
|
|
176
176
|
const shared = cmd.optsWithGlobals();
|
|
177
177
|
await add({
|
|
178
178
|
cwd: resolveCwd(cmd),
|
|
@@ -195,7 +195,7 @@ fleet.command("dismiss").argument("<name>", "the registered project name").argum
|
|
|
195
195
|
"Dismiss a project's finding from any cwd \u2014 guarded ledgers persist beside the manifest"
|
|
196
196
|
).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(
|
|
197
197
|
(name, id, _opts, cmd) => action(async () => {
|
|
198
|
-
const { dismiss } = await import('./fleet-
|
|
198
|
+
const { dismiss } = await import('./fleet-WPYEVHVL.js');
|
|
199
199
|
const opts = cmd.optsWithGlobals();
|
|
200
200
|
await dismiss({
|
|
201
201
|
cwd: resolveCwd(cmd),
|
|
@@ -210,7 +210,7 @@ fleet.command("accept").argument("<name>", "the registered project name").argume
|
|
|
210
210
|
"Accept a project's finding as a known trade-off \u2014 guarded ledgers persist beside the manifest"
|
|
211
211
|
).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(
|
|
212
212
|
(name, id, _opts, cmd) => action(async () => {
|
|
213
|
-
const { accept } = await import('./fleet-
|
|
213
|
+
const { accept } = await import('./fleet-WPYEVHVL.js');
|
|
214
214
|
const opts = cmd.optsWithGlobals();
|
|
215
215
|
await accept({ cwd: resolveCwd(cmd), manifest: opts.manifest, name, id, reason: opts.reason });
|
|
216
216
|
})
|
|
@@ -225,7 +225,7 @@ program.command("propose").description(
|
|
|
225
225
|
"the fleet manifest \u2014 runs a read-only sweep now (no delta baseline move)"
|
|
226
226
|
).option("--from <file>", "read a stored `etymd fleet --json` output instead of sweeping").option("--json", "print the proposal/1 records as JSON (EXPERIMENTAL)").action(
|
|
227
227
|
(opts, cmd) => action(async () => {
|
|
228
|
-
const { run } = await import('./propose-
|
|
228
|
+
const { run } = await import('./propose-IYNOIWAO.js');
|
|
229
229
|
await run({
|
|
230
230
|
cwd: resolveCwd(cmd),
|
|
231
231
|
manifest: opts.manifest,
|
|
@@ -242,7 +242,7 @@ program.command("screen").description(
|
|
|
242
242
|
"fork's upstream remote: files byte-identical to its refs skip vocabulary-class patterns (secret patterns stay absolute)"
|
|
243
243
|
).action(
|
|
244
244
|
(opts, cmd) => action(async () => {
|
|
245
|
-
const { run } = await import('./screen-
|
|
245
|
+
const { run } = await import('./screen-S736DXQ5.js');
|
|
246
246
|
const scope = opts.message ? "message" : opts.dir ? "dir" : opts.tree ? "tree" : "staged";
|
|
247
247
|
await run({
|
|
248
248
|
cwd: resolveCwd(cmd),
|
|
@@ -256,7 +256,7 @@ program.command("screen").description(
|
|
|
256
256
|
);
|
|
257
257
|
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(
|
|
258
258
|
(opts, cmd) => action(async () => {
|
|
259
|
-
const { run } = await import('./gates-
|
|
259
|
+
const { run } = await import('./gates-3HRGYCYY.js');
|
|
260
260
|
await run({ cwd: resolveCwd(cmd), ci: opts.ci, yes: opts.yes });
|
|
261
261
|
})
|
|
262
262
|
);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { run } from './chunk-
|
|
3
|
-
import './chunk-
|
|
4
|
-
import './chunk-
|
|
2
|
+
import { run } from './chunk-ANFNXFRI.js';
|
|
3
|
+
import './chunk-WKP7M2B3.js';
|
|
4
|
+
import './chunk-FNA4R5KT.js';
|
|
5
5
|
import './chunk-3E2IPCRY.js';
|
|
6
6
|
import './chunk-HI7NWPRA.js';
|
|
7
|
-
import './chunk-
|
|
8
|
-
import './chunk-
|
|
7
|
+
import './chunk-446EZNAQ.js';
|
|
8
|
+
import './chunk-BUMOGHQA.js';
|
|
9
9
|
import './chunk-P6ATKV2R.js';
|
|
10
10
|
import './chunk-YQZDYDAK.js';
|
|
11
11
|
import './chunk-4VPBP6K6.js';
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { dismiss, accept } from './chunk-HOR4M6EC.js';
|
|
3
|
-
import { sweepFleet, FLEET_JSON_SCHEMA, checkManifest, FLEET_TRUST_VALUES, isFleetTrust, MILESTONES_FILE, parseMilestones, parseInitiatives, BOARD_JSON_SCHEMA, renderBoard, loadFleetManifest, fleetLedgerTarget, ensureFindingRecorded } from './chunk-
|
|
4
|
-
import './chunk-
|
|
5
|
-
import { parseFailOnTier, meetsFailOn } from './chunk-
|
|
3
|
+
import { sweepFleet, FLEET_JSON_SCHEMA, checkManifest, FLEET_TRUST_VALUES, isFleetTrust, MILESTONES_FILE, parseMilestones, parseInitiatives, BOARD_JSON_SCHEMA, renderBoard, loadFleetManifest, fleetLedgerTarget, ensureFindingRecorded } from './chunk-LVR2DPR7.js';
|
|
4
|
+
import './chunk-WKP7M2B3.js';
|
|
5
|
+
import { parseFailOnTier, meetsFailOn } from './chunk-FNA4R5KT.js';
|
|
6
6
|
import './chunk-3E2IPCRY.js';
|
|
7
7
|
import { print, theme, section, renderFleetRows, renderFleetNotes, renderFindings, TIER_BADGE, glyph } from './chunk-HI7NWPRA.js';
|
|
8
|
-
import { scanProject } from './chunk-
|
|
9
|
-
import './chunk-
|
|
8
|
+
import { scanProject } from './chunk-446EZNAQ.js';
|
|
9
|
+
import './chunk-BUMOGHQA.js';
|
|
10
10
|
import './chunk-P6ATKV2R.js';
|
|
11
11
|
import './chunk-YQZDYDAK.js';
|
|
12
12
|
import { readText, pathExists, git } from './chunk-4VPBP6K6.js';
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { applyFiles } from './chunk-GWGKEPRX.js';
|
|
3
|
-
import { deriveFailOn, derivedCommands, planWorkflow, runPrefix, isSafeGateCommand } from './chunk-
|
|
3
|
+
import { deriveFailOn, derivedCommands, planWorkflow, runPrefix, isSafeGateCommand } from './chunk-PIJZUDDQ.js';
|
|
4
4
|
import { section, print, glyph, theme, renderPlan } from './chunk-HI7NWPRA.js';
|
|
5
|
-
import { scanProject } from './chunk-
|
|
6
|
-
import './chunk-
|
|
5
|
+
import { scanProject } from './chunk-446EZNAQ.js';
|
|
6
|
+
import './chunk-BUMOGHQA.js';
|
|
7
7
|
import { readConfig, CONFIG_FILE, configPath } from './chunk-P6ATKV2R.js';
|
|
8
8
|
import './chunk-YQZDYDAK.js';
|
|
9
9
|
import { readText, git } from './chunk-4VPBP6K6.js';
|
|
@@ -202,7 +202,10 @@ async function run(opts) {
|
|
|
202
202
|
const files = await planWorkflow(opts.cwd, facts, {
|
|
203
203
|
agents: false,
|
|
204
204
|
gates: true,
|
|
205
|
-
gateConfig
|
|
205
|
+
gateConfig,
|
|
206
|
+
// A pinned tier is a decision planWorkflow must not lower; an unpinned one it derives —
|
|
207
|
+
// the same flag the fleet's drift comparison passes, so both generate identical bytes.
|
|
208
|
+
gateFailOnPinned: explicit.gatesFailOn
|
|
206
209
|
});
|
|
207
210
|
return files.filter((f) => f.executable);
|
|
208
211
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
export { deriveFailOn, derivedCommands, planWorkflow, riskReachability } from './chunk-
|
|
2
|
+
export { deriveFailOn, derivedCommands, planWorkflow, riskReachability } from './chunk-PIJZUDDQ.js';
|
|
3
3
|
import './chunk-P6ATKV2R.js';
|
|
4
4
|
import './chunk-YQZDYDAK.js';
|
|
5
5
|
import './chunk-4VPBP6K6.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -303,6 +303,14 @@ interface PlanOptions {
|
|
|
303
303
|
publishGate?: boolean;
|
|
304
304
|
/** Recorded gate choices; absent means derive everything from the scan. */
|
|
305
305
|
gateConfig?: GateConfig;
|
|
306
|
+
/**
|
|
307
|
+
* Whether `gateConfig.failOn` was PINNED by the repo's committed config, versus a default the
|
|
308
|
+
* config loader filled in. The tier derivation may only choose between defaults — a recorded
|
|
309
|
+
* tier is a decision and is never lowered (see `deriveFailOn`). Callers that read the config
|
|
310
|
+
* pass `explicit.gatesFailOn` from `readConfig`; callers planning from a bare scan leave it
|
|
311
|
+
* unset, which is the same as unpinned.
|
|
312
|
+
*/
|
|
313
|
+
gateFailOnPinned?: boolean;
|
|
306
314
|
}
|
|
307
315
|
/** Build the file set an onboarding would write, flagging which exist and which differ. */
|
|
308
316
|
declare function planWorkflow(root: string, facts: ProjectFacts, opts: PlanOptions): Promise<GeneratedFile[]>;
|
package/dist/index.js
CHANGED
|
@@ -30,7 +30,7 @@ var init_package = __esm({
|
|
|
30
30
|
"package.json"() {
|
|
31
31
|
package_default = {
|
|
32
32
|
name: "etymd",
|
|
33
|
-
version: "0.
|
|
33
|
+
version: "0.17.0",
|
|
34
34
|
description: "Keep your agent instructions true \u2014 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.",
|
|
35
35
|
keywords: [
|
|
36
36
|
"cli",
|
|
@@ -1449,9 +1449,13 @@ async function planWorkflow(root, facts, opts) {
|
|
|
1449
1449
|
commitFormat: opts.gateConfig?.commitFormat,
|
|
1450
1450
|
allowWriting: opts.gateConfig?.allowWriting ?? []
|
|
1451
1451
|
};
|
|
1452
|
+
const tier = deriveFailOn(facts, {
|
|
1453
|
+
failOn: gateConfig.failOn,
|
|
1454
|
+
explicit: opts.gateFailOnPinned ?? false
|
|
1455
|
+
});
|
|
1452
1456
|
await add(
|
|
1453
1457
|
".githooks/pre-push",
|
|
1454
|
-
generatePrePushHook(facts, gateConfig, selfBuild),
|
|
1458
|
+
generatePrePushHook(facts, { ...gateConfig, failOn: tier.failOn }, selfBuild),
|
|
1455
1459
|
"Correctness gate (pre-push)",
|
|
1456
1460
|
true
|
|
1457
1461
|
);
|
|
@@ -4307,8 +4311,13 @@ async function checkGateDrift(manifest, findings, disclosures) {
|
|
|
4307
4311
|
);
|
|
4308
4312
|
continue;
|
|
4309
4313
|
}
|
|
4310
|
-
const { config } = await readConfig2(root);
|
|
4311
|
-
const planned = (await planWorkflow2(root, facts, {
|
|
4314
|
+
const { config, explicit } = await readConfig2(root);
|
|
4315
|
+
const planned = (await planWorkflow2(root, facts, {
|
|
4316
|
+
agents: false,
|
|
4317
|
+
gates: true,
|
|
4318
|
+
gateConfig: config.gates,
|
|
4319
|
+
gateFailOnPinned: explicit.gatesFailOn
|
|
4320
|
+
})).filter((f) => f.executable);
|
|
4312
4321
|
const missing = planned.filter((f) => !f.exists).map((f) => f.path);
|
|
4313
4322
|
const differing = planned.filter((f) => f.exists && f.differs);
|
|
4314
4323
|
const stale = differing.filter((f) => f.drift !== "edited").map((f) => f.path);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { applyFiles } from './chunk-GWGKEPRX.js';
|
|
3
|
-
import { planWorkflow } from './chunk-
|
|
3
|
+
import { planWorkflow } from './chunk-PIJZUDDQ.js';
|
|
4
4
|
import { theme, renderFacts, print, renderPlan, section, glyph } from './chunk-HI7NWPRA.js';
|
|
5
|
-
import { scanProject } from './chunk-
|
|
6
|
-
import { VERSION } from './chunk-
|
|
5
|
+
import { scanProject } from './chunk-446EZNAQ.js';
|
|
6
|
+
import { VERSION } from './chunk-BUMOGHQA.js';
|
|
7
7
|
import { writeCachedFacts, deriveProfile, writeBaseline, CACHE_DIR } from './chunk-P6ATKV2R.js';
|
|
8
8
|
import { PACK_VERSION } from './chunk-YQZDYDAK.js';
|
|
9
9
|
import { git, readText } from './chunk-4VPBP6K6.js';
|
|
@@ -1,8 +1,8 @@
|
|
|
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, KNOWN_EXTENSIONS, NAMESPACE_IDENT, NAMESPACE_STOP } from './chunk-FNA4R5KT.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-446EZNAQ.js';
|
|
5
|
+
import './chunk-BUMOGHQA.js';
|
|
6
6
|
import { ETYMD_DIR } from './chunk-P6ATKV2R.js';
|
|
7
7
|
import './chunk-YQZDYDAK.js';
|
|
8
8
|
import { readText, pathExists } from './chunk-4VPBP6K6.js';
|
|
@@ -1,11 +1,11 @@
|
|
|
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-LVR2DPR7.js';
|
|
3
|
+
import './chunk-WKP7M2B3.js';
|
|
4
|
+
import './chunk-FNA4R5KT.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-446EZNAQ.js';
|
|
8
|
+
import './chunk-BUMOGHQA.js';
|
|
9
9
|
import './chunk-P6ATKV2R.js';
|
|
10
10
|
import './chunk-YQZDYDAK.js';
|
|
11
11
|
import { readText } from './chunk-4VPBP6K6.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
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-446EZNAQ.js';
|
|
4
|
+
import './chunk-BUMOGHQA.js';
|
|
5
5
|
import { writeCachedFacts } from './chunk-P6ATKV2R.js';
|
|
6
6
|
import './chunk-YQZDYDAK.js';
|
|
7
7
|
import './chunk-4VPBP6K6.js';
|
|
@@ -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.17.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",
|