@piercebarney/whs-eleventy 2026.9.8 → 2026.9.10
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/cli.js +2 -0
- package/lib/compliance.js +8 -1
- package/lib/status.js +108 -0
- package/package.json +1 -1
- package/standard/CHANGELOG.md +44 -0
- package/standard/core.md +2 -2
package/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// whs — the web house style's Eleventy + Netlify tooling.
|
|
3
3
|
//
|
|
4
|
+
// whs status [--hook] standard-version drift, at a glance
|
|
4
5
|
// whs compliance [--strict] codebase-vs-standard conformance sweep
|
|
5
6
|
// whs doctor [--live|--deploy-preflight] infrastructure drift check
|
|
6
7
|
// whs links built-output link / CSP / JSON-LD integrity
|
|
@@ -16,6 +17,7 @@ const path = require("node:path");
|
|
|
16
17
|
const { spawnSync } = require("node:child_process");
|
|
17
18
|
|
|
18
19
|
const COMMANDS = {
|
|
20
|
+
status: "status.js",
|
|
19
21
|
compliance: "compliance.js",
|
|
20
22
|
doctor: "doctor.js",
|
|
21
23
|
links: "check-links.js",
|
package/lib/compliance.js
CHANGED
|
@@ -832,4 +832,11 @@ if (require.main === module) main();
|
|
|
832
832
|
|
|
833
833
|
// CHECKS is exported for the "coverage" test — nothing else should read it as
|
|
834
834
|
// data (call runCompliance() for results).
|
|
835
|
-
module.exports = {
|
|
835
|
+
module.exports = {
|
|
836
|
+
runCompliance,
|
|
837
|
+
summarize,
|
|
838
|
+
changelogSlugs,
|
|
839
|
+
changelogEntries,
|
|
840
|
+
versionDrift,
|
|
841
|
+
CHECKS,
|
|
842
|
+
};
|
package/lib/status.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Standard-version drift, at a glance (core.md#compliance). The delta-only
|
|
2
|
+
// slice of `whs compliance` — how far the project's pinned standard-version is
|
|
3
|
+
// behind the standard, and which chapters that means re-checking — without the
|
|
4
|
+
// full codebase sweep. Cheap enough to run on every Claude Code SessionStart.
|
|
5
|
+
//
|
|
6
|
+
// whs status print the version delta + the re-check rows
|
|
7
|
+
// whs status --hook silent when current; one line when behind (for the
|
|
8
|
+
// SessionStart hook — never non-zero, never noisy)
|
|
9
|
+
//
|
|
10
|
+
// Exit code is always 0: like `compliance` without --strict, drift is a
|
|
11
|
+
// backlog signal, not a build break.
|
|
12
|
+
|
|
13
|
+
const fs = require("node:fs");
|
|
14
|
+
const os = require("node:os");
|
|
15
|
+
const path = require("node:path");
|
|
16
|
+
|
|
17
|
+
// `status` answers "is there a newer standard available on this machine?" — so
|
|
18
|
+
// before the compliance module resolves its standard text, prefer the local
|
|
19
|
+
// canonical checkout (the ~/.claude symlink the README keeps) when one exists
|
|
20
|
+
// and nothing more specific was set. `whs compliance` still measures the
|
|
21
|
+
// codebase against the tooling's own bundled snapshot; `status` measures the
|
|
22
|
+
// pin against the freshest tree available, which is what a "you're behind"
|
|
23
|
+
// nudge should reflect. Machines without the symlink (CI, a fresh clone) fall
|
|
24
|
+
// back to the bundled snapshot unchanged.
|
|
25
|
+
if (!process.env.WHS_STANDARD) {
|
|
26
|
+
const local = path.join(os.homedir(), ".claude", "standards", "web-house-style");
|
|
27
|
+
if (fs.existsSync(path.join(local, "core.md"))) process.env.WHS_STANDARD = local;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const { versionDrift } = require("./compliance.js");
|
|
31
|
+
const { resolveStandard } = require("./_project.js");
|
|
32
|
+
|
|
33
|
+
// Distinct CHANGELOG dates after the pin — the "N versions behind" count. The
|
|
34
|
+
// standard versions by date, and several entries can share one date (one
|
|
35
|
+
// release); this counts releases, not entries.
|
|
36
|
+
function versionsBehind(pin) {
|
|
37
|
+
const std = resolveStandard();
|
|
38
|
+
if (!std || !pin) return 0;
|
|
39
|
+
try {
|
|
40
|
+
const changelog = fs.readFileSync(path.join(std, "CHANGELOG.md"), "utf8");
|
|
41
|
+
const dates = new Set();
|
|
42
|
+
for (const line of changelog.split("\n")) {
|
|
43
|
+
const m = line.match(/^##\s+([0-9]{4}-[0-9]{2}-[0-9]{2})\b/);
|
|
44
|
+
if (m && m[1] > pin) dates.add(m[1]);
|
|
45
|
+
}
|
|
46
|
+
return dates.size;
|
|
47
|
+
} catch {
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function main() {
|
|
53
|
+
const hook = process.argv.includes("--hook");
|
|
54
|
+
const { pin, current, rows } = versionDrift();
|
|
55
|
+
|
|
56
|
+
const unresolved =
|
|
57
|
+
rows.length === 1 && rows[0].startsWith("MANUAL: standard text not resolvable");
|
|
58
|
+
if (unresolved) {
|
|
59
|
+
if (!hook) console.log(rows[0]);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!rows.length) {
|
|
64
|
+
if (!hook) {
|
|
65
|
+
console.log(
|
|
66
|
+
pin && current
|
|
67
|
+
? `web house style: up to date (pinned ${pin}, standard at ${current})`
|
|
68
|
+
: "web house style: standard-version not pinned in CLAUDE.md",
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const breaking = rows.filter((r) => r.startsWith("BREAKING:")).length;
|
|
75
|
+
const versions = versionsBehind(pin);
|
|
76
|
+
const behind = `${versions} version${versions === 1 ? "" : "s"} behind`;
|
|
77
|
+
const recheck = `${rows.length} re-check${rows.length === 1 ? "" : "s"}${
|
|
78
|
+
breaking ? ` (${breaking} breaking)` : ""
|
|
79
|
+
}`;
|
|
80
|
+
|
|
81
|
+
if (hook) {
|
|
82
|
+
console.log(
|
|
83
|
+
`⚠ web house style: ${behind}, ${recheck} — pinned ${pin}, standard at ${current}. ` +
|
|
84
|
+
`Run /whs:upgrade to catch up.`,
|
|
85
|
+
);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
console.log(
|
|
90
|
+
`\nstandard-version: pinned ${pin}, standard at ${current} — ${behind}, ${recheck}\n`,
|
|
91
|
+
);
|
|
92
|
+
for (const row of rows) console.log(` ${row}`);
|
|
93
|
+
|
|
94
|
+
const hasUpgrade = fs.existsSync(
|
|
95
|
+
path.join(process.cwd(), ".claude", "commands", "whs", "upgrade.md"),
|
|
96
|
+
);
|
|
97
|
+
console.log(
|
|
98
|
+
hasUpgrade
|
|
99
|
+
? "\nRun /whs:upgrade in a Claude Code session to work this backlog.\n"
|
|
100
|
+
: "\nThis project predates /whs:upgrade. Copy .claude/commands/whs/upgrade.md,\n" +
|
|
101
|
+
".claude/hooks/standard-drift.sh, and the settings.json SessionStart entry\n" +
|
|
102
|
+
"from templates/eleventy-netlify/ in the standard, then run /whs:upgrade.\n",
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (require.main === module) main();
|
|
107
|
+
|
|
108
|
+
module.exports = { versionsBehind };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@piercebarney/whs-eleventy",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.10",
|
|
4
4
|
"description": "The web house style's Eleventy + Netlify tooling — the compliance sweep, the infra doctor, the link/CSP integrity check, and the a11y scan, shared by every project on the stack.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"whs": "cli.js"
|
package/standard/CHANGELOG.md
CHANGED
|
@@ -18,6 +18,50 @@ enforced, new *opt-in* chapters/capabilities, tooling-only changes — is
|
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
+
## 2026-09-10 — a one-command standard-version catch-up, and drift that surfaces itself [non-breaking]
|
|
22
|
+
|
|
23
|
+
Catching an adopted project up to a moved-on standard was a hand-written prompt
|
|
24
|
+
every time. The detection existed (`whs compliance`'s severity-tagged
|
|
25
|
+
`re-check #<slug>` rows) but was passive — nothing said "you're behind" unless
|
|
26
|
+
someone ran it. `core.md#compliance` already expects the assistant to run
|
|
27
|
+
compliance "whenever `standard-version:` is behind"; this makes the Eleventy
|
|
28
|
+
stack actually do that, and adds the command that works the result. Non-breaking:
|
|
29
|
+
a project compliant before is still compliant — this is an opt-in reporter, a
|
|
30
|
+
session-start notice, and a new command; no requirement changes. Eleventy-only
|
|
31
|
+
pilot, same stance as `/whs:build`; Phoenix/SvelteKit keep the by-hand path
|
|
32
|
+
until they have a tooling package.
|
|
33
|
+
|
|
34
|
+
### stacks/eleventy-netlify.md: compliance
|
|
35
|
+
|
|
36
|
+
- Documented `whs status` (the drift row alone — pinned vs. current version,
|
|
37
|
+
versions behind, the `re-check` list — no codebase sweep) and its
|
|
38
|
+
`SessionStart` wiring in the `compliance` section's **Wiring** bullet. Added a
|
|
39
|
+
migration-section note: an already-adopted project that has only fallen behind
|
|
40
|
+
runs `/whs:upgrade`; one scaffolded before the command shipped copies three
|
|
41
|
+
files from the template first.
|
|
42
|
+
|
|
43
|
+
### templates/eleventy-netlify
|
|
44
|
+
|
|
45
|
+
- New `/whs:upgrade` command (`.claude/commands/whs/upgrade.md`) — reads the
|
|
46
|
+
CHANGELOG delta since the pin, bumps `@piercebarney/whs-eleventy`, works the
|
|
47
|
+
`compliance` backlog one `re-check` row at a time (delegating to the
|
|
48
|
+
`brand`/`content`/`layout`/`pack` stage agents where a slug is theirs), then
|
|
49
|
+
re-pins `standard-version`. Never deploys. Structured like `/whs:build`.
|
|
50
|
+
- New `.claude/hooks/standard-drift.sh` + a `SessionStart` entry in
|
|
51
|
+
`.claude/settings.json` — runs `whs status --hook` at the top of every Claude
|
|
52
|
+
Code session; one line when the pin is behind, silent when current, never
|
|
53
|
+
blocks.
|
|
54
|
+
- `package.json` gains a `status` script (`whs status`).
|
|
55
|
+
- `CLAUDE.md` points at `/whs:upgrade` for the behind-the-standard case.
|
|
56
|
+
|
|
57
|
+
### packages/whs-eleventy
|
|
58
|
+
|
|
59
|
+
- New `whs status` subcommand (`lib/status.js`) — reuses `compliance.js`'s
|
|
60
|
+
`versionDrift()` (now exported) and reports the delta without running the
|
|
61
|
+
`CHECKS` sweep. `--hook` mode: one compact line when behind, nothing when
|
|
62
|
+
current, always exit 0. Registered in `cli.js`. Tests in `test/status.test.js`
|
|
63
|
+
plus a `versionDrift`-export assertion in `test/compliance.test.js`.
|
|
64
|
+
|
|
21
65
|
## 2026-09-08 — content-ops: reservation becomes a real opt-in, not a hardcoded default [non-breaking]
|
|
22
66
|
|
|
23
67
|
Found while building `/whs:build`'s Content stage agent, which needs to know
|
package/standard/core.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Web project house style — CORE (stack-agnostic)
|
|
2
2
|
|
|
3
|
-
**Version:** 2026-09-
|
|
3
|
+
**Version:** 2026-09-10 · **Status:** active
|
|
4
4
|
|
|
5
5
|
This is the stack-agnostic contract every web project follows, regardless of
|
|
6
6
|
framework, host, or CSS system. It says **what** must be true, with concrete
|
|
@@ -1422,7 +1422,7 @@ governs it and follow that chapter — the slugs are the index (a `<script>` →
|
|
|
1422
1422
|
- production-url: https://example.com
|
|
1423
1423
|
- content-type: tool # tool | article (article => feeds)
|
|
1424
1424
|
- publishing-rate: ~5 pages/week
|
|
1425
|
-
- standard-version: 2026-09-
|
|
1425
|
+
- standard-version: 2026-09-10 # recommended — enables standard-version drift tracking (#compliance)
|
|
1426
1426
|
```
|
|
1427
1427
|
|
|
1428
1428
|
If the section is absent, the assistant's first action is to run the flow above
|