etymd 0.13.0 → 0.15.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 +108 -0
- package/README.md +30 -19
- package/dist/{approve-YUT43YLC.js → approve-MA4Z3TBT.js} +5 -5
- package/dist/audit-YSALDC2L.js +11 -0
- package/dist/{brief-Z5S6OY2M.js → brief-DPZYSAMC.js} +5 -5
- package/dist/{chunk-PXRLOEN5.js → chunk-2RNQ6OLV.js} +146 -717
- package/dist/{chunk-DSAQ5S5D.js → chunk-CEO3BXQB.js} +3 -2
- package/dist/{chunk-D3R74TJ2.js → chunk-DBWDMIYO.js} +1 -1
- package/dist/{chunk-5BVKFJWM.js → chunk-HI7NWPRA.js} +79 -4
- package/dist/{chunk-2VLNI3L2.js → chunk-HOR4M6EC.js} +1 -1
- package/dist/chunk-IWG77WV3.js +758 -0
- package/dist/{chunk-DWL2IKZH.js → chunk-P6ATKV2R.js} +65 -3
- package/dist/{chunk-HRJJQCMT.js → chunk-UFNETE6P.js} +69 -20
- package/dist/{chunk-YXOAPMQH.js → chunk-Y6RZRED3.js} +2 -2
- package/dist/{chunk-LSZGCKIQ.js → chunk-YQZDYDAK.js} +1 -1
- package/dist/cli.js +42 -21
- package/dist/{config-XAH6PA5G.js → config-724Y3IOB.js} +1 -2
- package/dist/{context-F63RSIBH.js → context-JGKU4M7Z.js} +2 -4
- package/dist/doctor-Y3DWDEBT.js +18 -0
- package/dist/{fleet-YQ35KGEP.js → fleet-4FYZ3GBK.js} +11 -12
- package/dist/{gates-DU6SDH2M.js → gates-IBQ7HCAN.js} +6 -7
- package/dist/generate-KEX75XNG.js +5 -0
- package/dist/index.d.ts +173 -2
- package/dist/index.js +713 -198
- package/dist/{init-XJEYU2HC.js → init-H57H2JBE.js} +14 -13
- package/dist/ledger-T54JDHGP.js +6 -0
- package/dist/premise-VMC3UUIB.js +333 -0
- package/dist/scan-W4US23MU.js +5 -0
- package/dist/{scan-B24RZAV2.js → scan-XBOHDXAH.js} +5 -5
- package/dist/{screen-CS6PSG7U.js → screen-E4FC7W5N.js} +2 -1
- package/package.json +2 -2
- package/dist/audit-YRT4SWSQ.js +0 -12
- package/dist/chunk-F75Q43BC.js +0 -59
- package/dist/chunk-JHZ2BN4U.js +0 -67
- package/dist/doctor-7YKDXSKM.js +0 -19
- package/dist/generate-PMCP37DC.js +0 -6
- package/dist/ledger-4FOZ5HAB.js +0 -5
- package/dist/scan-QDNN7ER3.js +0 -5
|
@@ -1,8 +1,70 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { pathExists, readText } from './chunk-4VPBP6K6.js';
|
|
2
|
+
import { readJson, pathExists, readText } from './chunk-4VPBP6K6.js';
|
|
4
3
|
import path from 'path';
|
|
4
|
+
import { promises } from 'fs';
|
|
5
5
|
|
|
6
|
+
var ETYMD_DIR = ".etymd";
|
|
7
|
+
var CACHE_DIR = path.join(ETYMD_DIR, "cache");
|
|
8
|
+
var CACHE_FACTS_FILE = path.join(CACHE_DIR, "facts.json");
|
|
9
|
+
var BASELINE_FILE = path.join(ETYMD_DIR, "baseline.json");
|
|
10
|
+
function cacheFactsPath(root) {
|
|
11
|
+
return path.join(root, CACHE_FACTS_FILE);
|
|
12
|
+
}
|
|
13
|
+
function baselinePath(root) {
|
|
14
|
+
return path.join(root, BASELINE_FILE);
|
|
15
|
+
}
|
|
16
|
+
async function writeJsonFile(target, data) {
|
|
17
|
+
await promises.mkdir(path.dirname(target), { recursive: true });
|
|
18
|
+
await promises.writeFile(target, JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
19
|
+
return target;
|
|
20
|
+
}
|
|
21
|
+
async function writeCachedFacts(root, facts) {
|
|
22
|
+
return writeJsonFile(cacheFactsPath(root), facts);
|
|
23
|
+
}
|
|
24
|
+
function withoutMachinePath(facts) {
|
|
25
|
+
return { ...facts, root: "." };
|
|
26
|
+
}
|
|
27
|
+
function baselineCarriesMachinePath(baseline) {
|
|
28
|
+
const root = baseline.facts?.root;
|
|
29
|
+
return typeof root === "string" && root !== "." && (root.startsWith("/") || /^[A-Za-z]:[\\/]/.test(root));
|
|
30
|
+
}
|
|
31
|
+
async function writeBaseline(root, baseline) {
|
|
32
|
+
return writeJsonFile(baselinePath(root), {
|
|
33
|
+
...baseline,
|
|
34
|
+
facts: withoutMachinePath(baseline.facts)
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
async function readBaseline(root) {
|
|
38
|
+
return readJson(baselinePath(root));
|
|
39
|
+
}
|
|
40
|
+
function deriveProfile(facts) {
|
|
41
|
+
return (facts.git.recentAuthors ?? 1) > 2 ? "team" : "solo";
|
|
42
|
+
}
|
|
43
|
+
var DRIFT_ROLES = ["test", "lint", "typecheck", "format", "formatCheck", "build", "dev"];
|
|
44
|
+
function summarizeBaselineDrift(old, fresh) {
|
|
45
|
+
const commands = [];
|
|
46
|
+
for (const role of DRIFT_ROLES) {
|
|
47
|
+
const from = old.commands[role];
|
|
48
|
+
const to = fresh.commands[role];
|
|
49
|
+
if (from !== to) commands.push({ role, from, to });
|
|
50
|
+
}
|
|
51
|
+
const presentIds = (f) => new Set(f.artifacts.filter((a) => a.exists).map((a) => a.id));
|
|
52
|
+
const oldArtifacts = presentIds(old);
|
|
53
|
+
const freshArtifacts = presentIds(fresh);
|
|
54
|
+
const labelOf = (id) => fresh.artifacts.find((a) => a.id === id)?.label ?? old.artifacts.find((a) => a.id === id)?.label ?? id;
|
|
55
|
+
const artifactsAdded = [...freshArtifacts].filter((id) => !oldArtifacts.has(id)).map(labelOf);
|
|
56
|
+
const artifactsRemoved = [...oldArtifacts].filter((id) => !freshArtifacts.has(id)).map(labelOf);
|
|
57
|
+
const oldDirs = new Set(old.tree.dirs.map((d) => d.name));
|
|
58
|
+
const freshDirs = new Set(fresh.tree.dirs.map((d) => d.name));
|
|
59
|
+
const dirsAdded = [...freshDirs].filter((d) => !oldDirs.has(d));
|
|
60
|
+
const dirsRemoved = [...oldDirs].filter((d) => !freshDirs.has(d));
|
|
61
|
+
return { commands, artifactsAdded, artifactsRemoved, dirsAdded, dirsRemoved };
|
|
62
|
+
}
|
|
63
|
+
function isDriftEmpty(d) {
|
|
64
|
+
return d.commands.length === 0 && d.artifactsAdded.length === 0 && d.artifactsRemoved.length === 0 && d.dirsAdded.length === 0 && d.dirsRemoved.length === 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// src/core/config.ts
|
|
6
68
|
var CONFIG_FILE = path.join(ETYMD_DIR, "config.json");
|
|
7
69
|
var DEFAULT_CONFIG = {
|
|
8
70
|
instructions: { include: [], exclude: [] },
|
|
@@ -106,4 +168,4 @@ async function readConfig(root) {
|
|
|
106
168
|
};
|
|
107
169
|
}
|
|
108
170
|
|
|
109
|
-
export { CONFIG_FILE, DEFAULT_CONFIG, configPath, readConfig };
|
|
171
|
+
export { BASELINE_FILE, CACHE_DIR, CONFIG_FILE, DEFAULT_CONFIG, ETYMD_DIR, baselineCarriesMachinePath, configPath, deriveProfile, isDriftEmpty, readBaseline, readConfig, summarizeBaselineDrift, writeBaseline, writeCachedFacts };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { DEFAULT_CONFIG } from './chunk-
|
|
3
|
-
import { PACK_VERSION } from './chunk-
|
|
2
|
+
import { DEFAULT_CONFIG } from './chunk-P6ATKV2R.js';
|
|
3
|
+
import { PACK_VERSION } from './chunk-YQZDYDAK.js';
|
|
4
4
|
import { readText, pathExists } from './chunk-4VPBP6K6.js';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { createHash } from 'crypto';
|
|
@@ -132,16 +132,37 @@ ${[
|
|
|
132
132
|
"md"
|
|
133
133
|
);
|
|
134
134
|
}
|
|
135
|
-
var
|
|
135
|
+
var SELF_PACKAGE_NAME = "etymd";
|
|
136
|
+
function isSelfBuildRepo(facts) {
|
|
137
|
+
return facts.publishRoute !== "none" && facts.name === SELF_PACKAGE_NAME;
|
|
138
|
+
}
|
|
139
|
+
function contentGateResolution(selfBuild) {
|
|
140
|
+
if (!selfBuild) return `GATE="\${CONTENT_GATE:-$(command -v etymd || true)}"`;
|
|
141
|
+
return `GATE="\${CONTENT_GATE:-$(if [ -x ./dist/cli.js ]; then echo ./dist/cli.js; else command -v etymd || true; fi)}"`;
|
|
142
|
+
}
|
|
143
|
+
function contentScreenCall(opts) {
|
|
144
|
+
const { args, envVar, blocking, indent } = opts;
|
|
145
|
+
const hint = `etymd: this checker does not understand 'screen' (needs etymd 0.11+) \u2014 upgrade it, or set ${envVar} to a checker that does.`;
|
|
146
|
+
return [
|
|
147
|
+
`${indent}if ! "$GATE" screen ${args}; then`,
|
|
148
|
+
`${indent} "$GATE" screen --help >/dev/null 2>&1 ||`,
|
|
149
|
+
`${indent} echo "${hint}" >&2`,
|
|
150
|
+
...blocking ? [`${indent} exit 1`] : [],
|
|
151
|
+
`${indent}fi`
|
|
152
|
+
].join("\n");
|
|
153
|
+
}
|
|
136
154
|
function localHookCall(hook) {
|
|
137
155
|
return `# Repo-owned checks. This file is generated and will be overwritten; \`.githooks/${hook}.local\`
|
|
138
156
|
# is yours \u2014 etymd never reads, writes, or regenerates it. Put project-specific guards there.
|
|
157
|
+
# A guard running tests that build fixture repositories should scrub git's exported GIT_* names
|
|
158
|
+
# first \u2014 a child git inherits them and ignores its cwd, so the suite would hit the real repo:
|
|
159
|
+
# env $(env | grep -o '^GIT_[A-Za-z0-9_]*' | sed 's/^/-u /') <your command>
|
|
139
160
|
LOCAL="$(dirname "$0")/${hook}.local"
|
|
140
161
|
if [ -x "$LOCAL" ]; then
|
|
141
162
|
"$LOCAL" "$@" || exit 1
|
|
142
163
|
fi`;
|
|
143
164
|
}
|
|
144
|
-
function generatePreCommitHook() {
|
|
165
|
+
function generatePreCommitHook(selfBuild = false) {
|
|
145
166
|
return stampGenerated(`#!/usr/bin/env sh
|
|
146
167
|
# etymd: process gate. Cheap, locally-knowable checks belong here (fast, blocks the commit).
|
|
147
168
|
|
|
@@ -153,9 +174,9 @@ ${localHookCall("pre-commit")}
|
|
|
153
174
|
# commit anywhere, active only where you opted in.
|
|
154
175
|
#
|
|
155
176
|
# Bypass, with a reason: git commit --no-verify
|
|
156
|
-
${
|
|
177
|
+
${contentGateResolution(selfBuild)}
|
|
157
178
|
if [ -x "$GATE" ]; then
|
|
158
|
-
|
|
179
|
+
${contentScreenCall({ args: "--staged", envVar: "CONTENT_GATE", blocking: true, indent: " " })}
|
|
159
180
|
fi
|
|
160
181
|
|
|
161
182
|
exit 0
|
|
@@ -210,7 +231,7 @@ function generateCommitMsgHook(gates) {
|
|
|
210
231
|
# Bypass, with a reason: git commit --no-verify
|
|
211
232
|
GATE="\${COMMIT_MSG_GATE:-$(command -v etymd || true)}"
|
|
212
233
|
if [ -x "$GATE" ]; then
|
|
213
|
-
|
|
234
|
+
${contentScreenCall({ args: '--message "$1"', envVar: "COMMIT_MSG_GATE", blocking: true, indent: " " })}
|
|
214
235
|
fi
|
|
215
236
|
${format}
|
|
216
237
|
${localHookCall("commit-msg")}
|
|
@@ -221,11 +242,24 @@ exit 0
|
|
|
221
242
|
function shellcheckStep() {
|
|
222
243
|
return `
|
|
223
244
|
# Shell correctness. Scripts are discovered by shebang over TRACKED files at push time, so a
|
|
224
|
-
# script added later is covered without regenerating this hook.
|
|
245
|
+
# script added later is covered without regenerating this hook. zsh is NOT in the checked set:
|
|
246
|
+
# the checker cannot parse it (SC1071 is a parser-level error no inline directive can silence),
|
|
247
|
+
# so checking it would fail every push on the parser, not on the script. Excluded \u2014 and said so
|
|
248
|
+
# at run time below, because a coverage hole that is silent is indistinguishable from coverage.
|
|
249
|
+
#
|
|
250
|
+
# "the checker", not its name, on purpose: a comment whose first word is that name is read as
|
|
251
|
+
# a DIRECTIVE, and an unparseable directive is itself an error (SC1072/SC1073). A hook that
|
|
252
|
+
# explains why it skips a shell dialect must not break the checker while doing it.
|
|
225
253
|
if command -v shellcheck >/dev/null 2>&1; then
|
|
226
254
|
scripts=$(git ls-files -z \\
|
|
227
|
-
| xargs -0 -I{} sh -c 'head -1 "{}" 2>/dev/null | grep -qE "^#!.*[/ ](ba|da
|
|
255
|
+
| xargs -0 -I{} sh -c 'head -1 "{}" 2>/dev/null | grep -qE "^#!.*[/ ](ba|da)?sh( |$)" && echo "{}"' \\
|
|
256
|
+
| sort)
|
|
257
|
+
zsh_scripts=$(git ls-files -z \\
|
|
258
|
+
| xargs -0 -I{} sh -c 'head -1 "{}" 2>/dev/null | grep -qE "^#!.*[/ ]zsh( |$)" && echo "{}"' \\
|
|
228
259
|
| sort)
|
|
260
|
+
if [ -n "$zsh_scripts" ]; then
|
|
261
|
+
echo "\u203A shellcheck: $(printf '%s\\n' "$zsh_scripts" | wc -l | tr -d ' ') zsh script(s) excluded \u2014 shellcheck cannot parse zsh (SC1071); not checked, not failed"
|
|
262
|
+
fi
|
|
229
263
|
if [ -n "$scripts" ]; then
|
|
230
264
|
echo "\u203A shellcheck ($(printf '%s\\n' "$scripts" | wc -l | tr -d ' ') scripts, blocking at severity=warning)"
|
|
231
265
|
printf '%s\\n' "$scripts" | xargs shellcheck -S warning || {
|
|
@@ -245,7 +279,15 @@ else
|
|
|
245
279
|
echo "\u203A shellcheck skipped (not on PATH) \u2014 install it to gate this repo's shell scripts"
|
|
246
280
|
fi`;
|
|
247
281
|
}
|
|
248
|
-
|
|
282
|
+
var SCRUBBED_RUNNER = `
|
|
283
|
+
# Gate steps run scrubbed of git's exported GIT_* names: a child git that inherits them ignores
|
|
284
|
+
# its cwd, so a hook-run suite building fixture repositories would operate on the real repo.
|
|
285
|
+
run_gate() (
|
|
286
|
+
# shellcheck disable=SC2046 # word-splitting is the point: one -u per exported GIT_* name
|
|
287
|
+
env $(env | grep -o '^GIT_[A-Za-z0-9_]*' | sed 's/^/-u /') "$@"
|
|
288
|
+
)
|
|
289
|
+
`;
|
|
290
|
+
function generatePrePushHook(facts, gates, selfBuild = false) {
|
|
249
291
|
const run = runPrefix(facts.packageManager);
|
|
250
292
|
const c = facts.commands;
|
|
251
293
|
const candidates = gates?.commands?.length ? gates.commands : [c.formatCheck, c.typecheck, c.lint];
|
|
@@ -254,8 +296,9 @@ function generatePrePushHook(facts, gates) {
|
|
|
254
296
|
(key) => Boolean(key) && (allowed.has(key) || isSafeGateCommand(c.raw[key]))
|
|
255
297
|
).map((key) => `${run} ${key}`);
|
|
256
298
|
const shellStep = facts.shell?.scripts ? shellcheckStep() : "";
|
|
299
|
+
const runner = steps.length ? SCRUBBED_RUNNER : "";
|
|
257
300
|
const body = steps.length ? steps.map((s) => `echo "\u203A ${s}"
|
|
258
|
-
${s} || exit 1`).join("\n") : shellStep ? (
|
|
301
|
+
run_gate ${s} || exit 1`).join("\n") : shellStep ? (
|
|
259
302
|
// A repo whose executable surface is shell HAS a correctness command — it just is not in
|
|
260
303
|
// package.json. Claiming "none detected" beside a step that is about to run would be the
|
|
261
304
|
// tool contradicting itself.
|
|
@@ -272,22 +315,22 @@ fi`;
|
|
|
272
315
|
return stampGenerated(`#!/usr/bin/env sh
|
|
273
316
|
# etymd: correctness gate. Mirrors CI cheapest-first; blocks the push on any failure.
|
|
274
317
|
|
|
275
|
-
${localHookCall("pre-push")}
|
|
318
|
+
${localHookCall("pre-push")}${runner}
|
|
276
319
|
${body}${shellStep}
|
|
277
320
|
${auditStep}
|
|
278
321
|
|
|
279
322
|
# Content screen, second pass \u2014 the WHOLE TREE rather than one diff. Catches anything committed
|
|
280
323
|
# with --no-verify and anything a rebase or merge brought in from elsewhere. Advisory here (it
|
|
281
324
|
# never blocks the push): the blocking decision belongs at commit time, where the fix is cheap.
|
|
282
|
-
${
|
|
325
|
+
${contentGateResolution(selfBuild)}
|
|
283
326
|
if [ -x "$GATE" ]; then
|
|
284
|
-
|
|
327
|
+
${contentScreenCall({ args: "--tree --advisory", envVar: "CONTENT_GATE", blocking: false, indent: " " })}
|
|
285
328
|
fi
|
|
286
329
|
|
|
287
330
|
exit 0
|
|
288
331
|
`);
|
|
289
332
|
}
|
|
290
|
-
function generateArtifactCheckScript() {
|
|
333
|
+
function generateArtifactCheckScript(selfBuild = false) {
|
|
291
334
|
return stampGenerated(`#!/usr/bin/env sh
|
|
292
335
|
# etymd: content screen \u2014 the published ARTIFACT, not the repository.
|
|
293
336
|
#
|
|
@@ -298,7 +341,7 @@ function generateArtifactCheckScript() {
|
|
|
298
341
|
# .etymd-screen-allow entries (with provenance) if you must exempt a string.
|
|
299
342
|
set -eu
|
|
300
343
|
|
|
301
|
-
${
|
|
344
|
+
${contentGateResolution(selfBuild)}
|
|
302
345
|
[ -x "$GATE" ] || { echo "\u203A artifact-check: no checker installed \u2014 skipping."; exit 0; }
|
|
303
346
|
|
|
304
347
|
WORK=$(mktemp -d)
|
|
@@ -311,7 +354,7 @@ if [ -f package.json ]; then
|
|
|
311
354
|
tar -xzf "$WORK"/*.tgz -C "$WORK" 2>/dev/null || true
|
|
312
355
|
fi
|
|
313
356
|
|
|
314
|
-
|
|
357
|
+
${contentScreenCall({ args: '--dir "$WORK"', envVar: "CONTENT_GATE", blocking: true, indent: "" })}
|
|
315
358
|
exit 0
|
|
316
359
|
`);
|
|
317
360
|
}
|
|
@@ -368,7 +411,13 @@ async function planWorkflow(root, facts, opts) {
|
|
|
368
411
|
}
|
|
369
412
|
if (opts.gates) {
|
|
370
413
|
const existingPrePush = await readText(path.join(root, ".githooks", "pre-push"));
|
|
371
|
-
|
|
414
|
+
const selfBuild = isSelfBuildRepo(facts);
|
|
415
|
+
await add(
|
|
416
|
+
".githooks/pre-commit",
|
|
417
|
+
generatePreCommitHook(selfBuild),
|
|
418
|
+
"Process gate (pre-commit)",
|
|
419
|
+
true
|
|
420
|
+
);
|
|
372
421
|
await add(
|
|
373
422
|
".githooks/commit-msg",
|
|
374
423
|
generateCommitMsgHook(opts.gateConfig),
|
|
@@ -384,14 +433,14 @@ async function planWorkflow(root, facts, opts) {
|
|
|
384
433
|
};
|
|
385
434
|
await add(
|
|
386
435
|
".githooks/pre-push",
|
|
387
|
-
generatePrePushHook(facts, gateConfig),
|
|
436
|
+
generatePrePushHook(facts, gateConfig, selfBuild),
|
|
388
437
|
"Correctness gate (pre-push)",
|
|
389
438
|
true
|
|
390
439
|
);
|
|
391
440
|
if (opts.gateConfig?.publishGate ?? opts.publishGate ?? facts.publishable) {
|
|
392
441
|
await add(
|
|
393
442
|
"scripts/artifact-check.sh",
|
|
394
|
-
generateArtifactCheckScript(),
|
|
443
|
+
generateArtifactCheckScript(selfBuild),
|
|
395
444
|
"Content screen (published artifact)",
|
|
396
445
|
true
|
|
397
446
|
);
|
|
@@ -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-DBWDMIYO.js';
|
|
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';
|
|
6
6
|
import { promises } from 'fs';
|
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-DBWDMIYO.js';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import { Command } from 'commander';
|
|
5
5
|
import pc from 'picocolors';
|
|
@@ -21,7 +21,7 @@ ${pc.red("\u2716")} ${message}
|
|
|
21
21
|
}
|
|
22
22
|
var program = new Command();
|
|
23
23
|
program.name("etymd").description(
|
|
24
|
-
"Keep your agent instructions true \u2014 verify AGENTS.md & friends against the actual repo, on a budget, with drift caught over time."
|
|
24
|
+
"Keep your agent instructions true \u2014 verify AGENTS.md & friends, and the task you hand an agent, against the actual repo, on a budget, with drift caught over time."
|
|
25
25
|
).version(VERSION, "-v, --version").option("--cwd <dir>", "run against a different project directory", process.cwd());
|
|
26
26
|
program.command("audit").description("Verify every instruction claim against the repo: ranked findings + ledger diff").option("--json", "print the machine-stable audit result as JSON").option("--truth", "truth lenses only (the doctor subset)").option(
|
|
27
27
|
"--lens <id>",
|
|
@@ -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-YSALDC2L.js');
|
|
35
35
|
await run({
|
|
36
36
|
cwd: resolveCwd(cmd),
|
|
37
37
|
json: opts.json,
|
|
@@ -42,59 +42,80 @@ program.command("audit").description("Verify every instruction claim against the
|
|
|
42
42
|
});
|
|
43
43
|
})
|
|
44
44
|
);
|
|
45
|
-
program.command("init").description("Onboard the truth guard: approve the baseline; scaffold AGENTS.md only if
|
|
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-
|
|
48
|
-
await run({ cwd: resolveCwd(cmd), yes: opts.yes });
|
|
47
|
+
const { run } = await import('./init-H57H2JBE.js');
|
|
48
|
+
await run({ cwd: resolveCwd(cmd), yes: opts.yes, withAgents: opts.withAgents });
|
|
49
49
|
})
|
|
50
50
|
);
|
|
51
51
|
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-MA4Z3TBT.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-XBOHDXAH.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-Y3DWDEBT.js');
|
|
68
68
|
await run({ cwd: resolveCwd(cmd), json: opts.json });
|
|
69
69
|
})
|
|
70
70
|
);
|
|
71
71
|
program.command("context").description("Measure the always-loaded context footprint and flag extraction candidates").option("--json", "print the budget as JSON").action(
|
|
72
72
|
(opts, cmd) => action(async () => {
|
|
73
|
-
const { run } = await import('./context-
|
|
73
|
+
const { run } = await import('./context-JGKU4M7Z.js');
|
|
74
74
|
await run({ cwd: resolveCwd(cmd), json: opts.json });
|
|
75
75
|
})
|
|
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-DPZYSAMC.js');
|
|
80
80
|
await run({ cwd: resolveCwd(cmd), human: opts.human });
|
|
81
81
|
})
|
|
82
82
|
);
|
|
83
|
+
program.command("premise").argument("[task]", "the task you are about to hand an agent, quoted").description(
|
|
84
|
+
"Before acting on a task: verify what it names against the repo, then brief the agent on what only it can verify"
|
|
85
|
+
).option(
|
|
86
|
+
"--file <path>",
|
|
87
|
+
"read the task from a file (a plan, an issue, a prompt); `-` reads stdin"
|
|
88
|
+
).option("--json", "print the machine-stable result as JSON (schema premise/1)").option("--no-brief", "do not write or print the agent brief").option(
|
|
89
|
+
"--fail-on <tier>",
|
|
90
|
+
"exit non-zero when findings at/above this tier exist (risk|gap|polish)"
|
|
91
|
+
).action(
|
|
92
|
+
(task, opts, cmd) => action(async () => {
|
|
93
|
+
const { run } = await import('./premise-VMC3UUIB.js');
|
|
94
|
+
await run({
|
|
95
|
+
cwd: resolveCwd(cmd),
|
|
96
|
+
task,
|
|
97
|
+
file: opts.file,
|
|
98
|
+
json: opts.json,
|
|
99
|
+
brief: opts.brief,
|
|
100
|
+
failOn: opts.failOn
|
|
101
|
+
});
|
|
102
|
+
})
|
|
103
|
+
);
|
|
83
104
|
program.command("ledger").description("List every tracked finding grouped by status (open \xB7 accepted \xB7 dismissed \xB7 \u2026)").option("--json", "print the raw ledger as JSON").action(
|
|
84
105
|
(opts, cmd) => action(async () => {
|
|
85
|
-
const { list } = await import('./ledger-
|
|
106
|
+
const { list } = await import('./ledger-T54JDHGP.js');
|
|
86
107
|
await list({ cwd: resolveCwd(cmd), json: opts.json });
|
|
87
108
|
})
|
|
88
109
|
);
|
|
89
110
|
program.command("dismiss").argument("<finding-id>", "the finding id (from `etymd audit`) to dismiss").description("Dismiss a finding as a false positive / not applicable (hidden from future audits)").requiredOption("--reason <text>", "why it is dismissed \u2014 recorded so the decision survives").action(
|
|
90
111
|
(id, opts, cmd) => action(async () => {
|
|
91
|
-
const { dismiss } = await import('./ledger-
|
|
112
|
+
const { dismiss } = await import('./ledger-T54JDHGP.js');
|
|
92
113
|
await dismiss({ cwd: resolveCwd(cmd), id, reason: opts.reason });
|
|
93
114
|
})
|
|
94
115
|
);
|
|
95
116
|
program.command("accept").argument("<finding-id>", "the finding id (from `etymd audit`) to accept").description("Accept a real finding as a known trade-off (hidden from future audits)").option("--reason <text>", "optional note on why the trade-off is accepted").action(
|
|
96
117
|
(id, opts, cmd) => action(async () => {
|
|
97
|
-
const { accept } = await import('./ledger-
|
|
118
|
+
const { accept } = await import('./ledger-T54JDHGP.js');
|
|
98
119
|
await accept({ cwd: resolveCwd(cmd), id, reason: opts.reason });
|
|
99
120
|
})
|
|
100
121
|
);
|
|
@@ -111,7 +132,7 @@ var fleet = program.command("fleet").description(
|
|
|
111
132
|
"exit non-zero when findings at/above this tier exist (risk|gap|polish)"
|
|
112
133
|
).action(
|
|
113
134
|
(opts, cmd) => action(async () => {
|
|
114
|
-
const { sweep } = await import('./fleet-
|
|
135
|
+
const { sweep } = await import('./fleet-4FYZ3GBK.js');
|
|
115
136
|
await sweep({
|
|
116
137
|
cwd: resolveCwd(cmd),
|
|
117
138
|
manifest: opts.manifest,
|
|
@@ -126,7 +147,7 @@ var fleet = program.command("fleet").description(
|
|
|
126
147
|
);
|
|
127
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(
|
|
128
149
|
(_opts, cmd) => action(async () => {
|
|
129
|
-
const { check } = await import('./fleet-
|
|
150
|
+
const { check } = await import('./fleet-4FYZ3GBK.js');
|
|
130
151
|
const opts = cmd.optsWithGlobals();
|
|
131
152
|
await check({ cwd: resolveCwd(cmd), manifest: opts.manifest, json: opts.json });
|
|
132
153
|
})
|
|
@@ -136,7 +157,7 @@ fleet.command("add").argument("<dir>", "directory of the project to register").d
|
|
|
136
157
|
"public-repo | public-bound | private \u2014 mandatory for personal entries"
|
|
137
158
|
).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(
|
|
138
159
|
(dir, opts, cmd) => action(async () => {
|
|
139
|
-
const { add } = await import('./fleet-
|
|
160
|
+
const { add } = await import('./fleet-4FYZ3GBK.js');
|
|
140
161
|
const shared = cmd.optsWithGlobals();
|
|
141
162
|
await add({
|
|
142
163
|
cwd: resolveCwd(cmd),
|
|
@@ -159,7 +180,7 @@ fleet.command("dismiss").argument("<name>", "the registered project name").argum
|
|
|
159
180
|
"Dismiss a project's finding from any cwd \u2014 corp ledgers persist beside the manifest"
|
|
160
181
|
).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(
|
|
161
182
|
(name, id, _opts, cmd) => action(async () => {
|
|
162
|
-
const { dismiss } = await import('./fleet-
|
|
183
|
+
const { dismiss } = await import('./fleet-4FYZ3GBK.js');
|
|
163
184
|
const opts = cmd.optsWithGlobals();
|
|
164
185
|
await dismiss({
|
|
165
186
|
cwd: resolveCwd(cmd),
|
|
@@ -174,7 +195,7 @@ fleet.command("accept").argument("<name>", "the registered project name").argume
|
|
|
174
195
|
"Accept a project's finding as a known trade-off \u2014 corp ledgers persist beside the manifest"
|
|
175
196
|
).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(
|
|
176
197
|
(name, id, _opts, cmd) => action(async () => {
|
|
177
|
-
const { accept } = await import('./fleet-
|
|
198
|
+
const { accept } = await import('./fleet-4FYZ3GBK.js');
|
|
178
199
|
const opts = cmd.optsWithGlobals();
|
|
179
200
|
await accept({ cwd: resolveCwd(cmd), manifest: opts.manifest, name, id, reason: opts.reason });
|
|
180
201
|
})
|
|
@@ -186,7 +207,7 @@ program.command("screen").description(
|
|
|
186
207
|
"fork's upstream remote: files byte-identical to its refs skip vocabulary-class patterns (secret patterns stay absolute)"
|
|
187
208
|
).action(
|
|
188
209
|
(opts, cmd) => action(async () => {
|
|
189
|
-
const { run } = await import('./screen-
|
|
210
|
+
const { run } = await import('./screen-E4FC7W5N.js');
|
|
190
211
|
const scope = opts.message ? "message" : opts.dir ? "dir" : opts.tree ? "tree" : "staged";
|
|
191
212
|
await run({
|
|
192
213
|
cwd: resolveCwd(cmd),
|
|
@@ -200,7 +221,7 @@ program.command("screen").description(
|
|
|
200
221
|
);
|
|
201
222
|
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(
|
|
202
223
|
(opts, cmd) => action(async () => {
|
|
203
|
-
const { run } = await import('./gates-
|
|
224
|
+
const { run } = await import('./gates-IBQ7HCAN.js');
|
|
204
225
|
await run({ cwd: resolveCwd(cmd), ci: opts.ci, yes: opts.yes });
|
|
205
226
|
})
|
|
206
227
|
);
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { measureContext } from './chunk-
|
|
3
|
-
import { readConfig } from './chunk-
|
|
4
|
-
import { print, renderContext } from './chunk-5BVKFJWM.js';
|
|
5
|
-
import './chunk-JHZ2BN4U.js';
|
|
2
|
+
import { measureContext, print, renderContext } from './chunk-HI7NWPRA.js';
|
|
3
|
+
import { readConfig } from './chunk-P6ATKV2R.js';
|
|
6
4
|
import './chunk-4VPBP6K6.js';
|
|
7
5
|
|
|
8
6
|
// src/commands/context.ts
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { run } from './chunk-CEO3BXQB.js';
|
|
3
|
+
import './chunk-2RNQ6OLV.js';
|
|
4
|
+
import './chunk-IWG77WV3.js';
|
|
5
|
+
import './chunk-3E2IPCRY.js';
|
|
6
|
+
import './chunk-HI7NWPRA.js';
|
|
7
|
+
import './chunk-Y6RZRED3.js';
|
|
8
|
+
import './chunk-DBWDMIYO.js';
|
|
9
|
+
import './chunk-P6ATKV2R.js';
|
|
10
|
+
import './chunk-YQZDYDAK.js';
|
|
11
|
+
import './chunk-4VPBP6K6.js';
|
|
12
|
+
|
|
13
|
+
// src/commands/doctor.ts
|
|
14
|
+
async function run2(opts) {
|
|
15
|
+
await run({ cwd: opts.cwd, json: opts.json, truth: true });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export { run2 as run };
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { dismiss, accept } from './chunk-
|
|
3
|
-
import {
|
|
4
|
-
import './chunk-
|
|
2
|
+
import { dismiss, accept } from './chunk-HOR4M6EC.js';
|
|
3
|
+
import { runAudit } from './chunk-2RNQ6OLV.js';
|
|
4
|
+
import { parseFailOnTier, meetsFailOn } from './chunk-IWG77WV3.js';
|
|
5
5
|
import { readLedger } from './chunk-3E2IPCRY.js';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import './chunk-
|
|
10
|
-
import
|
|
11
|
-
import './chunk-LSZGCKIQ.js';
|
|
6
|
+
import { print, theme, section, renderFleetRows, renderFleetNotes, renderFindings, TIER_BADGE, glyph } from './chunk-HI7NWPRA.js';
|
|
7
|
+
import { scanProject } from './chunk-Y6RZRED3.js';
|
|
8
|
+
import './chunk-DBWDMIYO.js';
|
|
9
|
+
import { DEFAULT_CONFIG, ETYMD_DIR } from './chunk-P6ATKV2R.js';
|
|
10
|
+
import './chunk-YQZDYDAK.js';
|
|
12
11
|
import { readText, pathExists, git, isDirectory } from './chunk-4VPBP6K6.js';
|
|
13
12
|
import { promises } from 'fs';
|
|
14
13
|
import os from 'os';
|
|
@@ -687,9 +686,9 @@ async function checkCorpEmails(manifest, findings, disclosures) {
|
|
|
687
686
|
}
|
|
688
687
|
}
|
|
689
688
|
async function checkGateDrift(manifest, findings, disclosures) {
|
|
690
|
-
const { planWorkflow } = await import('./generate-
|
|
691
|
-
const { scanProject: scanProject2 } = await import('./scan-
|
|
692
|
-
const { readConfig } = await import('./config-
|
|
689
|
+
const { planWorkflow } = await import('./generate-KEX75XNG.js');
|
|
690
|
+
const { scanProject: scanProject2 } = await import('./scan-W4US23MU.js');
|
|
691
|
+
const { readConfig } = await import('./config-724Y3IOB.js');
|
|
693
692
|
for (const entry of manifest.entries) {
|
|
694
693
|
const root = entry.resolvedRoot;
|
|
695
694
|
if (!root || !await isDirectory(root)) continue;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { applyFiles } from './chunk-GWGKEPRX.js';
|
|
3
|
-
import { deriveFailOn, derivedCommands, planWorkflow, runPrefix, isSafeGateCommand } from './chunk-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import './chunk-
|
|
8
|
-
import './chunk-
|
|
9
|
-
import './chunk-LSZGCKIQ.js';
|
|
3
|
+
import { deriveFailOn, derivedCommands, planWorkflow, runPrefix, isSafeGateCommand } from './chunk-UFNETE6P.js';
|
|
4
|
+
import { section, print, glyph, theme, renderPlan } from './chunk-HI7NWPRA.js';
|
|
5
|
+
import { scanProject } from './chunk-Y6RZRED3.js';
|
|
6
|
+
import './chunk-DBWDMIYO.js';
|
|
7
|
+
import { readConfig, CONFIG_FILE, configPath } from './chunk-P6ATKV2R.js';
|
|
8
|
+
import './chunk-YQZDYDAK.js';
|
|
10
9
|
import { readText, git } from './chunk-4VPBP6K6.js';
|
|
11
10
|
import { promises } from 'fs';
|
|
12
11
|
import path from 'path';
|