etymd 0.19.2 → 0.19.3
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 +6 -0
- package/dist/{approve-Z4NMEGDM.js → approve-R24ZMJWB.js} +3 -3
- package/dist/audit-AZW4QGOE.js +11 -0
- package/dist/{brief-2N6X3CFR.js → brief-HEJJU3GB.js} +3 -3
- package/dist/{chunk-FG5XKFR2.js → chunk-5RRX2ONV.js} +3 -3
- package/dist/{chunk-WYJFZ2MB.js → chunk-635GEE4V.js} +2 -2
- package/dist/{chunk-DWPMANIC.js → chunk-7LRLA2XZ.js} +1 -1
- package/dist/{chunk-6FT7KSKU.js → chunk-AXUYE7HH.js} +1 -1
- package/dist/{chunk-X5GR2EJK.js → chunk-BXBSFDYL.js} +81 -43
- package/dist/{chunk-WIBN7PBH.js → chunk-IEHSNXR3.js} +4 -4
- package/dist/{chunk-W6GGG4LG.js → chunk-VCEA7333.js} +1 -1
- package/dist/{chunk-OKHNNWOV.js → chunk-VVUEOA4V.js} +2 -2
- package/dist/{chunk-TZGRV7UY.js → chunk-XYJIDPKZ.js} +1 -1
- package/dist/cli.js +16 -16
- package/dist/{doctor-7YG342YP.js → doctor-UGW5G5IZ.js} +6 -6
- package/dist/{fleet-XZVQLY53.js → fleet-Y22JBWLP.js} +7 -7
- package/dist/{gates-633B6G2T.js → gates-D6QPKN63.js} +5 -5
- package/dist/{generate-S5KGZIIM.js → generate-5AF7V3DH.js} +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +82 -44
- package/dist/{init-SL3HEB3H.js → init-FNLRAYP4.js} +5 -5
- package/dist/{premise-62AXRQUK.js → premise-FYOWXHUH.js} +4 -4
- package/dist/{propose-4UWLIFWJ.js → propose-5XOMTLW7.js} +6 -6
- package/dist/{scan-VEHQEEXY.js → scan-QBPWNLNC.js} +3 -3
- package/dist/scan-WPXLF2J4.js +5 -0
- package/package.json +1 -1
- package/dist/audit-4PGVS2TW.js +0 -11
- package/dist/scan-M7STYIYQ.js +0 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# etymd
|
|
2
2
|
|
|
3
|
+
## 0.19.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- bcd629d: Generated pre-push hooks read each pushed commit's scripts as raw blobs from git instead of checking the commit out. A checkout applied `.gitattributes` line-ending conversion, so under `eol=crlf` a script's shebang line ended in a carriage return and the script left the checked set without a message. The hook also no longer writes a commit's whole tree: one `git grep` pass finds the changed files with a `#!` line, and only those are read, which makes a whole-tree check faster than before. Symlink entries are now a disclosed skip, since a link's target is checked under its own path. The classifier refuses the old call shape, so a hand-edited pre-push kept across a regeneration stops the push and says to run `etymd gates`. Regenerate existing hooks with `etymd gates --yes`.
|
|
8
|
+
|
|
3
9
|
## 0.19.2
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
|
@@ -1,9 +1,9 @@
|
|
|
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-VVUEOA4V.js';
|
|
4
|
+
import { VERSION } from './chunk-VCEA7333.js';
|
|
5
5
|
import { readBaseline, summarizeBaselineDrift, isDriftEmpty, writeBaseline, deriveProfile } from './chunk-P6ATKV2R.js';
|
|
6
|
-
import { PACK_VERSION } from './chunk-
|
|
6
|
+
import { PACK_VERSION } from './chunk-AXUYE7HH.js';
|
|
7
7
|
import './chunk-4VPBP6K6.js';
|
|
8
8
|
|
|
9
9
|
// src/commands/approve.ts
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export { run } from './chunk-635GEE4V.js';
|
|
3
|
+
import './chunk-5RRX2ONV.js';
|
|
4
|
+
import './chunk-7LRLA2XZ.js';
|
|
5
|
+
import './chunk-3E2IPCRY.js';
|
|
6
|
+
import './chunk-HI7NWPRA.js';
|
|
7
|
+
import './chunk-VVUEOA4V.js';
|
|
8
|
+
import './chunk-VCEA7333.js';
|
|
9
|
+
import './chunk-P6ATKV2R.js';
|
|
10
|
+
import './chunk-AXUYE7HH.js';
|
|
11
|
+
import './chunk-4VPBP6K6.js';
|
|
@@ -1,9 +1,9 @@
|
|
|
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-VVUEOA4V.js';
|
|
4
|
+
import './chunk-VCEA7333.js';
|
|
5
5
|
import { ETYMD_DIR } from './chunk-P6ATKV2R.js';
|
|
6
|
-
import './chunk-
|
|
6
|
+
import './chunk-AXUYE7HH.js';
|
|
7
7
|
import './chunk-4VPBP6K6.js';
|
|
8
8
|
import { promises } from 'fs';
|
|
9
9
|
import path from 'path';
|
|
@@ -1,10 +1,10 @@
|
|
|
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-7LRLA2XZ.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-VVUEOA4V.js';
|
|
6
6
|
import { DEFAULT_CONFIG, ETYMD_DIR, writeCachedFacts, readBaseline, readConfig, deriveProfile, baselineCarriesMachinePath, BASELINE_FILE, CONFIG_FILE } from './chunk-P6ATKV2R.js';
|
|
7
|
-
import { PACK_VERSION } from './chunk-
|
|
7
|
+
import { PACK_VERSION } from './chunk-AXUYE7HH.js';
|
|
8
8
|
import { pathExists, readText, readJson, isCiEnvironment, isExecutable } from './chunk-4VPBP6K6.js';
|
|
9
9
|
import path from 'path';
|
|
10
10
|
import YAML from 'yaml';
|
|
@@ -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-5RRX2ONV.js';
|
|
3
|
+
import { parseFailOnTier, meetsFailOn } from './chunk-7LRLA2XZ.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-VVUEOA4V.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 { PACK_VERSION } from './chunk-
|
|
2
|
+
import { PACK_VERSION } from './chunk-AXUYE7HH.js';
|
|
3
3
|
import { createHash } from 'crypto';
|
|
4
4
|
|
|
5
5
|
var GENERATION_MARKER_RE = /^(?:# |<!-- )etymd:generated pack-v\S+ ([0-9a-f]{16})(?: -->)?$/;
|
|
@@ -257,34 +257,58 @@ exit 0
|
|
|
257
257
|
}
|
|
258
258
|
function generateShellDiscoveryScript() {
|
|
259
259
|
return stampGenerated(`#!/usr/bin/env sh
|
|
260
|
-
# etymd: shell script discovery for the pre-push shellcheck step.
|
|
261
|
-
#
|
|
262
|
-
#
|
|
263
|
-
#
|
|
260
|
+
# etymd: shell script discovery for the pre-push shellcheck step. Two calls per commit:
|
|
261
|
+
# discover-shell-scripts.sh --skips <scratch> <ls-tree record>...
|
|
262
|
+
# discover-shell-scripts.sh --commit <scratch> <tree> <commit> <commit>:<path>...
|
|
263
|
+
# The first counts the changed paths that are symlinks or submodule entries. The second reads
|
|
264
|
+
# the candidates \`git grep\` found with a line starting \`#!\`, and classifies each by its FIRST
|
|
265
|
+
# line. Verdicts land in the scratch: scripts (NUL-delimited matches) and one dot per decision
|
|
266
|
+
# into count / zsh-count / skip-count, tallied by the hook after the pipeline. Each script found
|
|
267
|
+
# is written into <tree> at its path, so the checker reads it there.
|
|
264
268
|
#
|
|
265
|
-
#
|
|
266
|
-
#
|
|
267
|
-
#
|
|
268
|
-
#
|
|
269
|
-
#
|
|
270
|
-
#
|
|
269
|
+
# Every byte comes from git's object store as the raw blob \u2014 \`git cat-file blob\`, which
|
|
270
|
+
# applies no eol, text or filter attribute. A checkout converts: under \`eol=crlf\` the shebang
|
|
271
|
+
# line ends in a carriage return, the match below fails, and the script leaves the checked set
|
|
272
|
+
# without a word. Only the entries handed in are read, never the whole commit.
|
|
273
|
+
#
|
|
274
|
+
# A symlink or submodule entry has no script bytes of its own \u2014 a link's target is a tracked
|
|
275
|
+
# path checked under its own name \u2014 so it is a disclosed skip, never a block. A candidate that
|
|
276
|
+
# cannot be read fails, naming the path: coverage would otherwise silently shrink.
|
|
271
277
|
#
|
|
272
278
|
# The match/error protocol: grep reports "no match" as 1 and a failure as 2 or more, and only
|
|
273
279
|
# the first is a verdict. Letting a failure fall through would pass a broken matcher as "not a
|
|
274
280
|
# shell script" \u2014 the exact silent coverage-shrink the fail-closed rules exist to prevent. The
|
|
275
281
|
# status is captured on the grep's own line (\`|| st=$?\`), so no command added later can come
|
|
276
282
|
# between the grep and the check and silently replace the status being read.
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
283
|
+
case \${1-} in
|
|
284
|
+
(--skips)
|
|
285
|
+
# Records only: a symlink or submodule entry is counted, everything else is left to the
|
|
286
|
+
# candidate pass. Builtins only \u2014 this loop sees every changed path.
|
|
287
|
+
work=$2
|
|
288
|
+
shift 2
|
|
289
|
+
for record do
|
|
290
|
+
case \${record%% *} in
|
|
291
|
+
(100644|100755) ;;
|
|
292
|
+
(*) printf . >> "$work/skip-count" || exit 1 ;;
|
|
293
|
+
esac
|
|
294
|
+
done
|
|
295
|
+
exit 0 ;;
|
|
296
|
+
(--commit)
|
|
297
|
+
[ $# -ge 4 ] || exit 1 ;;
|
|
298
|
+
(*)
|
|
299
|
+
echo "etymd: discover-shell-scripts.sh expects --commit or --skips; the pre-push beside it is older than this classifier \u2014 run 'etymd gates'" >&2
|
|
300
|
+
exit 1 ;;
|
|
301
|
+
esac
|
|
302
|
+
work=$2
|
|
303
|
+
tree=$3
|
|
304
|
+
sha=$4
|
|
305
|
+
shift 4
|
|
306
|
+
for entry do
|
|
307
|
+
file=\${entry#"$sha":}
|
|
308
|
+
# 4096 bytes bound the classifying read \u2014 a binary with no newline would otherwise be copied
|
|
309
|
+
# whole into the next step. The second head restores line-1-only semantics, so a shebang
|
|
310
|
+
# embedded on a LATER line of a document cannot match the patterns below.
|
|
311
|
+
git cat-file blob "$sha:$file" > "$work/blob" && head -c 4096 "$work/blob" > "$work/head-bytes" || {
|
|
288
312
|
echo "etymd: cannot read tracked file for shellcheck: $file" >&2
|
|
289
313
|
exit 1
|
|
290
314
|
}
|
|
@@ -293,6 +317,14 @@ for file do
|
|
|
293
317
|
grep -qE "^#!.*[/ ](ba|da)?sh( |$)" "$work/first-line" || st=$?
|
|
294
318
|
case $st in
|
|
295
319
|
(0)
|
|
320
|
+
case $file in
|
|
321
|
+
(*/*) dir=\${file%/*} ;;
|
|
322
|
+
(*) dir=. ;;
|
|
323
|
+
esac
|
|
324
|
+
mkdir -p -- "$tree/$dir" && mv -- "$work/blob" "$tree/$file" || {
|
|
325
|
+
echo "etymd: cannot stage tracked file for shellcheck: $file" >&2
|
|
326
|
+
exit 1
|
|
327
|
+
}
|
|
296
328
|
printf "./%s\\0" "$file" >> "$work/scripts" || exit 1
|
|
297
329
|
printf . >> "$work/count" || exit 1 ;;
|
|
298
330
|
(1)
|
|
@@ -312,7 +344,7 @@ function shellcheckStep() {
|
|
|
312
344
|
return `
|
|
313
345
|
# Shell correctness. Scripts are discovered by shebang over TRACKED files at push time, so a
|
|
314
346
|
# script added later is covered without regenerating this hook. The commits BEING PUSHED are
|
|
315
|
-
# the bytes that ship, so each
|
|
347
|
+
# the bytes that ship, so each script is read as its raw blob from git's object store \u2014
|
|
316
348
|
# never the working tree (wrong in both directions: a fixed tree let an unfixed commit ship, and
|
|
317
349
|
# a dirty tree shared by several sessions blocked an unrelated push) and never the tip alone (a
|
|
318
350
|
# bad commit under a clean tip shipped while the gate read only the tip's fix). The classifier
|
|
@@ -381,28 +413,15 @@ if command -v shellcheck >/dev/null 2>&1; then
|
|
|
381
413
|
else
|
|
382
414
|
echo "\u203A shellcheck: no commit in the pushed refs (deletes only, or nothing on stdin) \u2014 nothing to check"
|
|
383
415
|
fi
|
|
384
|
-
# Resolved once, before any cd: the
|
|
416
|
+
# Resolved once, before any cd: the checker runs inside each commit's scratch tree, and a
|
|
385
417
|
# relative hook path would no longer point at it from there.
|
|
386
418
|
discover="$(cd "$(dirname "$0")" && pwd)/discover-shell-scripts.sh" || exit 1
|
|
387
419
|
for sha in $shas; do
|
|
388
|
-
# A fresh directory per commit
|
|
389
|
-
#
|
|
390
|
-
# every early exit.
|
|
420
|
+
# A fresh directory per commit holding only that commit's scripts, removed once it is
|
|
421
|
+
# checked; the subshell trap above still cleans the root on every early exit.
|
|
391
422
|
tree=$(mktemp -d "$shellcheck_tmp/commit.XXXXXX") || exit 1
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
# the checked set without a word. read-tree + checkout-index writes every tracked blob.
|
|
395
|
-
# Large-file pointers stay pointers \u2014 they are never shell, and a push must not need the
|
|
396
|
-
# network to be checked.
|
|
397
|
-
if ! git cat-file -e "\${sha}^{commit}" 2>/dev/null \\
|
|
398
|
-
|| ! GIT_INDEX_FILE="$shellcheck_tmp/index" git read-tree "$sha" 2>/dev/null \\
|
|
399
|
-
|| ! GIT_INDEX_FILE="$shellcheck_tmp/index" GIT_LFS_SKIP_SMUDGE=1 \\
|
|
400
|
-
git checkout-index -a -f --prefix="$tree/" 2>/dev/null; then
|
|
401
|
-
echo "\u2717 shellcheck: could not materialise $(git rev-parse --short "$sha" 2>/dev/null || echo "$sha") \u2014 refusing the push rather than certifying bytes this gate did not read" >&2
|
|
402
|
-
exit 1
|
|
403
|
-
fi
|
|
404
|
-
if [ -n "$(git ls-tree -r --name-only "$sha")" ] && [ -z "$(ls -A "$tree")" ]; then
|
|
405
|
-
echo "\u2717 shellcheck: $(git rev-parse --short "$sha" 2>/dev/null || echo "$sha") extracted to an empty tree \u2014 refusing the push" >&2
|
|
423
|
+
if ! git cat-file -e "\${sha}^{commit}" 2>/dev/null; then
|
|
424
|
+
echo "\u2717 shellcheck: cannot read commit $(git rev-parse --short "$sha" 2>/dev/null || echo "$sha") \u2014 refusing the push rather than certifying bytes this gate did not read" >&2
|
|
406
425
|
exit 1
|
|
407
426
|
fi
|
|
408
427
|
: > "$shellcheck_tmp/scripts" && : > "$shellcheck_tmp/count" && : > "$shellcheck_tmp/zsh-count" && : > "$shellcheck_tmp/skip-count" || exit 1
|
|
@@ -448,7 +467,26 @@ if command -v shellcheck >/dev/null 2>&1; then
|
|
|
448
467
|
echo "etymd: shell script discovery failed; cannot tell whether $short changes the gate, its classifier or a .shellcheckrc" >&2
|
|
449
468
|
exit 1 ;;
|
|
450
469
|
esac
|
|
451
|
-
|
|
470
|
+
# Only these paths are read, each as its raw blob \u2014 never a checkout of the commit, which
|
|
471
|
+
# would apply eol and filter attributes (a CRLF shebang left the checked set silently) and
|
|
472
|
+
# write the whole tree to check a handful of files. Never \`git archive\` either: it honours
|
|
473
|
+
# export-ignore, so a script so marked would leave the set without a word.
|
|
474
|
+
: > "$shellcheck_tmp/records" && : > "$shellcheck_tmp/candidates" || exit 1
|
|
475
|
+
if [ -s "$shellcheck_tmp/tracked" ]; then
|
|
476
|
+
# The candidates: changed blobs holding a line that starts \`#!\`, found in one pass over
|
|
477
|
+
# the raw blobs (git grep reads no eol or filter conversion). Only these are read one by
|
|
478
|
+
# one \u2014 a file with no such line cannot have a shebang first line. grep's "no match" is
|
|
479
|
+
# 1, a verdict; xargs would fold it into a failure, so the wrapper maps 1 to 0 and lets
|
|
480
|
+
# anything higher through as the failure it is.
|
|
481
|
+
xargs -0 git --literal-pathspecs ls-tree -z "$sha" -- < "$shellcheck_tmp/tracked" > "$shellcheck_tmp/records" \\
|
|
482
|
+
&& xargs -0 sh -c 'git --literal-pathspecs grep -z -l --full-name -e "^#!" "$0" -- "$@"; st=$?; [ "$st" -le 1 ]' "$sha" \\
|
|
483
|
+
< "$shellcheck_tmp/tracked" > "$shellcheck_tmp/candidates" || {
|
|
484
|
+
echo "etymd: shell script discovery failed; cannot list the tracked entries of $short" >&2
|
|
485
|
+
exit 1
|
|
486
|
+
}
|
|
487
|
+
fi
|
|
488
|
+
xargs -0 "$discover" --skips "$shellcheck_tmp" < "$shellcheck_tmp/records" \\
|
|
489
|
+
&& xargs -0 "$discover" --commit "$shellcheck_tmp" "$tree" "$sha" < "$shellcheck_tmp/candidates" || {
|
|
452
490
|
echo "etymd: shell script discovery failed; shellcheck coverage is incomplete" >&2
|
|
453
491
|
exit 1
|
|
454
492
|
}
|
|
@@ -456,7 +494,7 @@ if command -v shellcheck >/dev/null 2>&1; then
|
|
|
456
494
|
zsh_count=$(wc -c < "$shellcheck_tmp/zsh-count") || exit 1
|
|
457
495
|
skip_count=$(wc -c < "$shellcheck_tmp/skip-count") || exit 1
|
|
458
496
|
if [ "$skip_count" -gt 0 ]; then
|
|
459
|
-
echo "\u203A shellcheck: $((skip_count)) tracked path(s)
|
|
497
|
+
echo "\u203A shellcheck: $((skip_count)) tracked path(s) that are symlinks or submodule entries \u2014 no script bytes of their own (a link's target is checked under its own path); not checked, not failed"
|
|
460
498
|
fi
|
|
461
499
|
if [ "$zsh_count" -gt 0 ]; then
|
|
462
500
|
echo "\u203A shellcheck: $((zsh_count)) zsh script(s) excluded \u2014 shellcheck cannot parse zsh (SC1071); not checked, not failed"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { runAudit } from './chunk-
|
|
2
|
+
import { runAudit } from './chunk-5RRX2ONV.js';
|
|
3
3
|
import { readLedger } from './chunk-3E2IPCRY.js';
|
|
4
|
-
import { checkClaudePointer, CLAUDE_AGENTS_FALLBACK_VERSION } from './chunk-
|
|
4
|
+
import { checkClaudePointer, CLAUDE_AGENTS_FALLBACK_VERSION } from './chunk-VVUEOA4V.js';
|
|
5
5
|
import { DEFAULT_CONFIG, ETYMD_DIR } from './chunk-P6ATKV2R.js';
|
|
6
6
|
import { readText, isDirectory, git, pathExists } from './chunk-4VPBP6K6.js';
|
|
7
7
|
import os from 'os';
|
|
@@ -1006,8 +1006,8 @@ async function checkGuardedEmails(manifest, findings, disclosures) {
|
|
|
1006
1006
|
}
|
|
1007
1007
|
}
|
|
1008
1008
|
async function checkGateDrift(manifest, findings, disclosures) {
|
|
1009
|
-
const { planWorkflow } = await import('./generate-
|
|
1010
|
-
const { scanProject } = await import('./scan-
|
|
1009
|
+
const { planWorkflow } = await import('./generate-5AF7V3DH.js');
|
|
1010
|
+
const { scanProject } = await import('./scan-WPXLF2J4.js');
|
|
1011
1011
|
const { readConfig } = await import('./config-724Y3IOB.js');
|
|
1012
1012
|
for (const entry of manifest.entries) {
|
|
1013
1013
|
const root = entry.resolvedRoot;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { VERSION } from './chunk-
|
|
3
|
-
import { PACK_VERSION } from './chunk-
|
|
2
|
+
import { VERSION } from './chunk-VCEA7333.js';
|
|
3
|
+
import { PACK_VERSION } from './chunk-AXUYE7HH.js';
|
|
4
4
|
import { normalizeRelPath, isDirectory, pathExists, readText, readJson, git, matchesAnyGlob } from './chunk-4VPBP6K6.js';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { execFile } from 'child_process';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { isSafeGateCommand, generateAgentsMd, generateClaudePointerMd, isSelfBuildRepo, generatePreCommitHook, generateCommitMsgHook, generatePrePushHook, generateShellDiscoveryScript, generateArtifactCheckScript, fileOrigin } from './chunk-
|
|
2
|
+
import { isSafeGateCommand, generateAgentsMd, generateClaudePointerMd, isSelfBuildRepo, generatePreCommitHook, generateCommitMsgHook, generatePrePushHook, generateShellDiscoveryScript, generateArtifactCheckScript, fileOrigin } from './chunk-BXBSFDYL.js';
|
|
3
3
|
import { DEFAULT_CONFIG } from './chunk-P6ATKV2R.js';
|
|
4
4
|
import { readText, pathExists } from './chunk-4VPBP6K6.js';
|
|
5
5
|
import path from 'path';
|
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-VCEA7333.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-AZW4QGOE.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-FNLRAYP4.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-R24ZMJWB.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-QBPWNLNC.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-UGW5G5IZ.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-HEJJU3GB.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-FYOWXHUH.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-Y22JBWLP.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-Y22JBWLP.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-Y22JBWLP.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-Y22JBWLP.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-Y22JBWLP.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-Y22JBWLP.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-5XOMTLW7.js');
|
|
229
229
|
await run({
|
|
230
230
|
cwd: resolveCwd(cmd),
|
|
231
231
|
manifest: opts.manifest,
|
|
@@ -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-D6QPKN63.js');
|
|
260
260
|
await run({ cwd: resolveCwd(cmd), ci: opts.ci, yes: opts.yes });
|
|
261
261
|
})
|
|
262
262
|
);
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { run } from './chunk-
|
|
3
|
-
import './chunk-
|
|
4
|
-
import './chunk-
|
|
2
|
+
import { run } from './chunk-635GEE4V.js';
|
|
3
|
+
import './chunk-5RRX2ONV.js';
|
|
4
|
+
import './chunk-7LRLA2XZ.js';
|
|
5
5
|
import './chunk-3E2IPCRY.js';
|
|
6
6
|
import './chunk-HI7NWPRA.js';
|
|
7
|
-
import './chunk-
|
|
8
|
-
import './chunk-
|
|
7
|
+
import './chunk-VVUEOA4V.js';
|
|
8
|
+
import './chunk-VCEA7333.js';
|
|
9
9
|
import './chunk-P6ATKV2R.js';
|
|
10
|
-
import './chunk-
|
|
10
|
+
import './chunk-AXUYE7HH.js';
|
|
11
11
|
import './chunk-4VPBP6K6.js';
|
|
12
12
|
|
|
13
13
|
// src/commands/doctor.ts
|
|
@@ -1,15 +1,15 @@
|
|
|
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-IEHSNXR3.js';
|
|
4
|
+
import './chunk-5RRX2ONV.js';
|
|
5
|
+
import { parseFailOnTier, meetsFailOn } from './chunk-7LRLA2XZ.js';
|
|
6
6
|
import './chunk-3E2IPCRY.js';
|
|
7
|
-
import { generateClaudePointerMd } from './chunk-
|
|
7
|
+
import { generateClaudePointerMd } from './chunk-BXBSFDYL.js';
|
|
8
8
|
import { print, theme, section, renderFleetRows, renderFleetNotes, renderFindings, TIER_BADGE, glyph } from './chunk-HI7NWPRA.js';
|
|
9
|
-
import { checkClaudePointer, scanProject } from './chunk-
|
|
10
|
-
import './chunk-
|
|
9
|
+
import { checkClaudePointer, scanProject } from './chunk-VVUEOA4V.js';
|
|
10
|
+
import './chunk-VCEA7333.js';
|
|
11
11
|
import './chunk-P6ATKV2R.js';
|
|
12
|
-
import './chunk-
|
|
12
|
+
import './chunk-AXUYE7HH.js';
|
|
13
13
|
import { readText, pathExists, git } from './chunk-4VPBP6K6.js';
|
|
14
14
|
import { promises } from 'fs';
|
|
15
15
|
import os from 'os';
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { applyFiles } from './chunk-GWGKEPRX.js';
|
|
3
|
-
import { deriveFailOn, derivedCommands, planWorkflow } from './chunk-
|
|
4
|
-
import { runPrefix, isSafeGateCommand } from './chunk-
|
|
3
|
+
import { deriveFailOn, derivedCommands, planWorkflow } from './chunk-XYJIDPKZ.js';
|
|
4
|
+
import { runPrefix, isSafeGateCommand } from './chunk-BXBSFDYL.js';
|
|
5
5
|
import { section, print, glyph, theme, renderPlan } from './chunk-HI7NWPRA.js';
|
|
6
|
-
import { scanProject } from './chunk-
|
|
7
|
-
import './chunk-
|
|
6
|
+
import { scanProject } from './chunk-VVUEOA4V.js';
|
|
7
|
+
import './chunk-VCEA7333.js';
|
|
8
8
|
import { readConfig, CONFIG_FILE, configPath } from './chunk-P6ATKV2R.js';
|
|
9
|
-
import './chunk-
|
|
9
|
+
import './chunk-AXUYE7HH.js';
|
|
10
10
|
import { readText, git } from './chunk-4VPBP6K6.js';
|
|
11
11
|
import { promises } from 'fs';
|
|
12
12
|
import path from 'path';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
export { deriveFailOn, derivedCommands, planWorkflow, riskReachability } from './chunk-
|
|
3
|
-
import './chunk-
|
|
2
|
+
export { deriveFailOn, derivedCommands, planWorkflow, riskReachability } from './chunk-XYJIDPKZ.js';
|
|
3
|
+
import './chunk-BXBSFDYL.js';
|
|
4
4
|
import './chunk-P6ATKV2R.js';
|
|
5
|
-
import './chunk-
|
|
5
|
+
import './chunk-AXUYE7HH.js';
|
|
6
6
|
import './chunk-4VPBP6K6.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1127,7 +1127,7 @@ declare const gateIntegrityLens: Lens;
|
|
|
1127
1127
|
* Gaps in the sequence are deliberate: a number stays retired even when the change that took it
|
|
1128
1128
|
* never shipped, so a version cited in a baseline or a record means exactly one pack, ever.
|
|
1129
1129
|
*/
|
|
1130
|
-
declare const PACK_VERSION = "
|
|
1130
|
+
declare const PACK_VERSION = "17";
|
|
1131
1131
|
|
|
1132
1132
|
declare const VERSION: string;
|
|
1133
1133
|
declare const NAME: string;
|
package/dist/index.js
CHANGED
|
@@ -20,7 +20,7 @@ var __export = (target, all) => {
|
|
|
20
20
|
var PACK_VERSION;
|
|
21
21
|
var init_version = __esm({
|
|
22
22
|
"src/pack/version.ts"() {
|
|
23
|
-
PACK_VERSION = "
|
|
23
|
+
PACK_VERSION = "17";
|
|
24
24
|
}
|
|
25
25
|
});
|
|
26
26
|
|
|
@@ -30,7 +30,7 @@ var init_package = __esm({
|
|
|
30
30
|
"package.json"() {
|
|
31
31
|
package_default = {
|
|
32
32
|
name: "etymd",
|
|
33
|
-
version: "0.19.
|
|
33
|
+
version: "0.19.3",
|
|
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",
|
|
@@ -1336,34 +1336,58 @@ exit 0
|
|
|
1336
1336
|
}
|
|
1337
1337
|
function generateShellDiscoveryScript() {
|
|
1338
1338
|
return stampGenerated(`#!/usr/bin/env sh
|
|
1339
|
-
# etymd: shell script discovery for the pre-push shellcheck step.
|
|
1340
|
-
#
|
|
1341
|
-
#
|
|
1342
|
-
#
|
|
1339
|
+
# etymd: shell script discovery for the pre-push shellcheck step. Two calls per commit:
|
|
1340
|
+
# discover-shell-scripts.sh --skips <scratch> <ls-tree record>...
|
|
1341
|
+
# discover-shell-scripts.sh --commit <scratch> <tree> <commit> <commit>:<path>...
|
|
1342
|
+
# The first counts the changed paths that are symlinks or submodule entries. The second reads
|
|
1343
|
+
# the candidates \`git grep\` found with a line starting \`#!\`, and classifies each by its FIRST
|
|
1344
|
+
# line. Verdicts land in the scratch: scripts (NUL-delimited matches) and one dot per decision
|
|
1345
|
+
# into count / zsh-count / skip-count, tallied by the hook after the pipeline. Each script found
|
|
1346
|
+
# is written into <tree> at its path, so the checker reads it there.
|
|
1343
1347
|
#
|
|
1344
|
-
#
|
|
1345
|
-
#
|
|
1346
|
-
#
|
|
1347
|
-
#
|
|
1348
|
-
#
|
|
1349
|
-
#
|
|
1348
|
+
# Every byte comes from git's object store as the raw blob \u2014 \`git cat-file blob\`, which
|
|
1349
|
+
# applies no eol, text or filter attribute. A checkout converts: under \`eol=crlf\` the shebang
|
|
1350
|
+
# line ends in a carriage return, the match below fails, and the script leaves the checked set
|
|
1351
|
+
# without a word. Only the entries handed in are read, never the whole commit.
|
|
1352
|
+
#
|
|
1353
|
+
# A symlink or submodule entry has no script bytes of its own \u2014 a link's target is a tracked
|
|
1354
|
+
# path checked under its own name \u2014 so it is a disclosed skip, never a block. A candidate that
|
|
1355
|
+
# cannot be read fails, naming the path: coverage would otherwise silently shrink.
|
|
1350
1356
|
#
|
|
1351
1357
|
# The match/error protocol: grep reports "no match" as 1 and a failure as 2 or more, and only
|
|
1352
1358
|
# the first is a verdict. Letting a failure fall through would pass a broken matcher as "not a
|
|
1353
1359
|
# shell script" \u2014 the exact silent coverage-shrink the fail-closed rules exist to prevent. The
|
|
1354
1360
|
# status is captured on the grep's own line (\`|| st=$?\`), so no command added later can come
|
|
1355
1361
|
# between the grep and the check and silently replace the status being read.
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1362
|
+
case \${1-} in
|
|
1363
|
+
(--skips)
|
|
1364
|
+
# Records only: a symlink or submodule entry is counted, everything else is left to the
|
|
1365
|
+
# candidate pass. Builtins only \u2014 this loop sees every changed path.
|
|
1366
|
+
work=$2
|
|
1367
|
+
shift 2
|
|
1368
|
+
for record do
|
|
1369
|
+
case \${record%% *} in
|
|
1370
|
+
(100644|100755) ;;
|
|
1371
|
+
(*) printf . >> "$work/skip-count" || exit 1 ;;
|
|
1372
|
+
esac
|
|
1373
|
+
done
|
|
1374
|
+
exit 0 ;;
|
|
1375
|
+
(--commit)
|
|
1376
|
+
[ $# -ge 4 ] || exit 1 ;;
|
|
1377
|
+
(*)
|
|
1378
|
+
echo "etymd: discover-shell-scripts.sh expects --commit or --skips; the pre-push beside it is older than this classifier \u2014 run 'etymd gates'" >&2
|
|
1379
|
+
exit 1 ;;
|
|
1380
|
+
esac
|
|
1381
|
+
work=$2
|
|
1382
|
+
tree=$3
|
|
1383
|
+
sha=$4
|
|
1384
|
+
shift 4
|
|
1385
|
+
for entry do
|
|
1386
|
+
file=\${entry#"$sha":}
|
|
1387
|
+
# 4096 bytes bound the classifying read \u2014 a binary with no newline would otherwise be copied
|
|
1388
|
+
# whole into the next step. The second head restores line-1-only semantics, so a shebang
|
|
1389
|
+
# embedded on a LATER line of a document cannot match the patterns below.
|
|
1390
|
+
git cat-file blob "$sha:$file" > "$work/blob" && head -c 4096 "$work/blob" > "$work/head-bytes" || {
|
|
1367
1391
|
echo "etymd: cannot read tracked file for shellcheck: $file" >&2
|
|
1368
1392
|
exit 1
|
|
1369
1393
|
}
|
|
@@ -1372,6 +1396,14 @@ for file do
|
|
|
1372
1396
|
grep -qE "^#!.*[/ ](ba|da)?sh( |$)" "$work/first-line" || st=$?
|
|
1373
1397
|
case $st in
|
|
1374
1398
|
(0)
|
|
1399
|
+
case $file in
|
|
1400
|
+
(*/*) dir=\${file%/*} ;;
|
|
1401
|
+
(*) dir=. ;;
|
|
1402
|
+
esac
|
|
1403
|
+
mkdir -p -- "$tree/$dir" && mv -- "$work/blob" "$tree/$file" || {
|
|
1404
|
+
echo "etymd: cannot stage tracked file for shellcheck: $file" >&2
|
|
1405
|
+
exit 1
|
|
1406
|
+
}
|
|
1375
1407
|
printf "./%s\\0" "$file" >> "$work/scripts" || exit 1
|
|
1376
1408
|
printf . >> "$work/count" || exit 1 ;;
|
|
1377
1409
|
(1)
|
|
@@ -1391,7 +1423,7 @@ function shellcheckStep() {
|
|
|
1391
1423
|
return `
|
|
1392
1424
|
# Shell correctness. Scripts are discovered by shebang over TRACKED files at push time, so a
|
|
1393
1425
|
# script added later is covered without regenerating this hook. The commits BEING PUSHED are
|
|
1394
|
-
# the bytes that ship, so each
|
|
1426
|
+
# the bytes that ship, so each script is read as its raw blob from git's object store \u2014
|
|
1395
1427
|
# never the working tree (wrong in both directions: a fixed tree let an unfixed commit ship, and
|
|
1396
1428
|
# a dirty tree shared by several sessions blocked an unrelated push) and never the tip alone (a
|
|
1397
1429
|
# bad commit under a clean tip shipped while the gate read only the tip's fix). The classifier
|
|
@@ -1460,28 +1492,15 @@ if command -v shellcheck >/dev/null 2>&1; then
|
|
|
1460
1492
|
else
|
|
1461
1493
|
echo "\u203A shellcheck: no commit in the pushed refs (deletes only, or nothing on stdin) \u2014 nothing to check"
|
|
1462
1494
|
fi
|
|
1463
|
-
# Resolved once, before any cd: the
|
|
1495
|
+
# Resolved once, before any cd: the checker runs inside each commit's scratch tree, and a
|
|
1464
1496
|
# relative hook path would no longer point at it from there.
|
|
1465
1497
|
discover="$(cd "$(dirname "$0")" && pwd)/discover-shell-scripts.sh" || exit 1
|
|
1466
1498
|
for sha in $shas; do
|
|
1467
|
-
# A fresh directory per commit
|
|
1468
|
-
#
|
|
1469
|
-
# every early exit.
|
|
1499
|
+
# A fresh directory per commit holding only that commit's scripts, removed once it is
|
|
1500
|
+
# checked; the subshell trap above still cleans the root on every early exit.
|
|
1470
1501
|
tree=$(mktemp -d "$shellcheck_tmp/commit.XXXXXX") || exit 1
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
# the checked set without a word. read-tree + checkout-index writes every tracked blob.
|
|
1474
|
-
# Large-file pointers stay pointers \u2014 they are never shell, and a push must not need the
|
|
1475
|
-
# network to be checked.
|
|
1476
|
-
if ! git cat-file -e "\${sha}^{commit}" 2>/dev/null \\
|
|
1477
|
-
|| ! GIT_INDEX_FILE="$shellcheck_tmp/index" git read-tree "$sha" 2>/dev/null \\
|
|
1478
|
-
|| ! GIT_INDEX_FILE="$shellcheck_tmp/index" GIT_LFS_SKIP_SMUDGE=1 \\
|
|
1479
|
-
git checkout-index -a -f --prefix="$tree/" 2>/dev/null; then
|
|
1480
|
-
echo "\u2717 shellcheck: could not materialise $(git rev-parse --short "$sha" 2>/dev/null || echo "$sha") \u2014 refusing the push rather than certifying bytes this gate did not read" >&2
|
|
1481
|
-
exit 1
|
|
1482
|
-
fi
|
|
1483
|
-
if [ -n "$(git ls-tree -r --name-only "$sha")" ] && [ -z "$(ls -A "$tree")" ]; then
|
|
1484
|
-
echo "\u2717 shellcheck: $(git rev-parse --short "$sha" 2>/dev/null || echo "$sha") extracted to an empty tree \u2014 refusing the push" >&2
|
|
1502
|
+
if ! git cat-file -e "\${sha}^{commit}" 2>/dev/null; then
|
|
1503
|
+
echo "\u2717 shellcheck: cannot read commit $(git rev-parse --short "$sha" 2>/dev/null || echo "$sha") \u2014 refusing the push rather than certifying bytes this gate did not read" >&2
|
|
1485
1504
|
exit 1
|
|
1486
1505
|
fi
|
|
1487
1506
|
: > "$shellcheck_tmp/scripts" && : > "$shellcheck_tmp/count" && : > "$shellcheck_tmp/zsh-count" && : > "$shellcheck_tmp/skip-count" || exit 1
|
|
@@ -1527,7 +1546,26 @@ if command -v shellcheck >/dev/null 2>&1; then
|
|
|
1527
1546
|
echo "etymd: shell script discovery failed; cannot tell whether $short changes the gate, its classifier or a .shellcheckrc" >&2
|
|
1528
1547
|
exit 1 ;;
|
|
1529
1548
|
esac
|
|
1530
|
-
|
|
1549
|
+
# Only these paths are read, each as its raw blob \u2014 never a checkout of the commit, which
|
|
1550
|
+
# would apply eol and filter attributes (a CRLF shebang left the checked set silently) and
|
|
1551
|
+
# write the whole tree to check a handful of files. Never \`git archive\` either: it honours
|
|
1552
|
+
# export-ignore, so a script so marked would leave the set without a word.
|
|
1553
|
+
: > "$shellcheck_tmp/records" && : > "$shellcheck_tmp/candidates" || exit 1
|
|
1554
|
+
if [ -s "$shellcheck_tmp/tracked" ]; then
|
|
1555
|
+
# The candidates: changed blobs holding a line that starts \`#!\`, found in one pass over
|
|
1556
|
+
# the raw blobs (git grep reads no eol or filter conversion). Only these are read one by
|
|
1557
|
+
# one \u2014 a file with no such line cannot have a shebang first line. grep's "no match" is
|
|
1558
|
+
# 1, a verdict; xargs would fold it into a failure, so the wrapper maps 1 to 0 and lets
|
|
1559
|
+
# anything higher through as the failure it is.
|
|
1560
|
+
xargs -0 git --literal-pathspecs ls-tree -z "$sha" -- < "$shellcheck_tmp/tracked" > "$shellcheck_tmp/records" \\
|
|
1561
|
+
&& xargs -0 sh -c 'git --literal-pathspecs grep -z -l --full-name -e "^#!" "$0" -- "$@"; st=$?; [ "$st" -le 1 ]' "$sha" \\
|
|
1562
|
+
< "$shellcheck_tmp/tracked" > "$shellcheck_tmp/candidates" || {
|
|
1563
|
+
echo "etymd: shell script discovery failed; cannot list the tracked entries of $short" >&2
|
|
1564
|
+
exit 1
|
|
1565
|
+
}
|
|
1566
|
+
fi
|
|
1567
|
+
xargs -0 "$discover" --skips "$shellcheck_tmp" < "$shellcheck_tmp/records" \\
|
|
1568
|
+
&& xargs -0 "$discover" --commit "$shellcheck_tmp" "$tree" "$sha" < "$shellcheck_tmp/candidates" || {
|
|
1531
1569
|
echo "etymd: shell script discovery failed; shellcheck coverage is incomplete" >&2
|
|
1532
1570
|
exit 1
|
|
1533
1571
|
}
|
|
@@ -1535,7 +1573,7 @@ if command -v shellcheck >/dev/null 2>&1; then
|
|
|
1535
1573
|
zsh_count=$(wc -c < "$shellcheck_tmp/zsh-count") || exit 1
|
|
1536
1574
|
skip_count=$(wc -c < "$shellcheck_tmp/skip-count") || exit 1
|
|
1537
1575
|
if [ "$skip_count" -gt 0 ]; then
|
|
1538
|
-
echo "\u203A shellcheck: $((skip_count)) tracked path(s)
|
|
1576
|
+
echo "\u203A shellcheck: $((skip_count)) tracked path(s) that are symlinks or submodule entries \u2014 no script bytes of their own (a link's target is checked under its own path); not checked, not failed"
|
|
1539
1577
|
fi
|
|
1540
1578
|
if [ "$zsh_count" -gt 0 ]; then
|
|
1541
1579
|
echo "\u203A shellcheck: $((zsh_count)) zsh script(s) excluded \u2014 shellcheck cannot parse zsh (SC1071); not checked, not failed"
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { applyFiles } from './chunk-GWGKEPRX.js';
|
|
3
|
-
import { planWorkflow } from './chunk-
|
|
4
|
-
import './chunk-
|
|
3
|
+
import { planWorkflow } from './chunk-XYJIDPKZ.js';
|
|
4
|
+
import './chunk-BXBSFDYL.js';
|
|
5
5
|
import { theme, renderFacts, print, renderPlan, section, glyph } from './chunk-HI7NWPRA.js';
|
|
6
|
-
import { scanProject, checkClaudePointer } from './chunk-
|
|
7
|
-
import { VERSION } from './chunk-
|
|
6
|
+
import { scanProject, checkClaudePointer } from './chunk-VVUEOA4V.js';
|
|
7
|
+
import { VERSION } from './chunk-VCEA7333.js';
|
|
8
8
|
import { writeCachedFacts, deriveProfile, writeBaseline, CACHE_DIR } from './chunk-P6ATKV2R.js';
|
|
9
|
-
import { PACK_VERSION } from './chunk-
|
|
9
|
+
import { PACK_VERSION } from './chunk-AXUYE7HH.js';
|
|
10
10
|
import { git, readText } from './chunk-4VPBP6K6.js';
|
|
11
11
|
import { promises } from 'fs';
|
|
12
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, HOSTNAME_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-7LRLA2XZ.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-VVUEOA4V.js';
|
|
5
|
+
import './chunk-VCEA7333.js';
|
|
6
6
|
import { ETYMD_DIR } from './chunk-P6ATKV2R.js';
|
|
7
|
-
import './chunk-
|
|
7
|
+
import './chunk-AXUYE7HH.js';
|
|
8
8
|
import { readText, pathExists } from './chunk-4VPBP6K6.js';
|
|
9
9
|
import path from 'path';
|
|
10
10
|
import { promises } from 'fs';
|
|
@@ -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-IEHSNXR3.js';
|
|
3
|
+
import './chunk-5RRX2ONV.js';
|
|
4
|
+
import './chunk-7LRLA2XZ.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-VVUEOA4V.js';
|
|
8
|
+
import './chunk-VCEA7333.js';
|
|
9
9
|
import './chunk-P6ATKV2R.js';
|
|
10
|
-
import './chunk-
|
|
10
|
+
import './chunk-AXUYE7HH.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-VVUEOA4V.js';
|
|
4
|
+
import './chunk-VCEA7333.js';
|
|
5
5
|
import { writeCachedFacts } from './chunk-P6ATKV2R.js';
|
|
6
|
-
import './chunk-
|
|
6
|
+
import './chunk-AXUYE7HH.js';
|
|
7
7
|
import './chunk-4VPBP6K6.js';
|
|
8
8
|
|
|
9
9
|
// src/commands/scan.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "etymd",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.3",
|
|
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",
|
package/dist/audit-4PGVS2TW.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
export { run } from './chunk-WYJFZ2MB.js';
|
|
3
|
-
import './chunk-FG5XKFR2.js';
|
|
4
|
-
import './chunk-DWPMANIC.js';
|
|
5
|
-
import './chunk-3E2IPCRY.js';
|
|
6
|
-
import './chunk-HI7NWPRA.js';
|
|
7
|
-
import './chunk-OKHNNWOV.js';
|
|
8
|
-
import './chunk-W6GGG4LG.js';
|
|
9
|
-
import './chunk-P6ATKV2R.js';
|
|
10
|
-
import './chunk-6FT7KSKU.js';
|
|
11
|
-
import './chunk-4VPBP6K6.js';
|