pagetrace 0.8.0 → 0.9.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 +24 -0
- package/README.md +12 -0
- package/dist/cli.cjs +58 -2
- package/dist/cli.js +58 -2
- package/dist/index.cjs +2 -1
- package/dist/index.js +2 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,29 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
While the version is below 1.0.0, breaking changes ship in a minor release.
|
|
8
8
|
|
|
9
|
+
## [0.9.0] - 2026-09-07
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `pagetrace update` asks the npm registry whether a newer version is published
|
|
14
|
+
and installs it. `--check` reports without installing. A project-local install
|
|
15
|
+
is not overwritten with a global one; the command prints the package-manager
|
|
16
|
+
command instead, because installing globally would leave the version the
|
|
17
|
+
project actually runs untouched.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- A bare `pagetrace`, or a misspelled command, printed nothing and exited 0,
|
|
22
|
+
which reads as a silent success. Both now print the command list, and an
|
|
23
|
+
unknown command exits 2.
|
|
24
|
+
|
|
25
|
+
## [0.8.1] - 2026-09-06
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- The report summary said "1 findings across 13 pages". Both counts are now
|
|
30
|
+
pluralised properly.
|
|
31
|
+
|
|
9
32
|
## [0.8.0] - 2026-09-06
|
|
10
33
|
|
|
11
34
|
### Fixed
|
|
@@ -249,6 +272,7 @@ Initial release. `snapshot`, `check` and `audit` commands; filesystem and HTTP
|
|
|
249
272
|
crawling; diff classified by transition; absolute, cross-page and hreflang audit
|
|
250
273
|
rules; pretty, JSON, markdown, GitHub and HTML reporters.
|
|
251
274
|
|
|
275
|
+
[0.8.1]: https://github.com/shyamexe/pagetrace/compare/v0.8.0...v0.8.1
|
|
252
276
|
[0.8.0]: https://github.com/shyamexe/pagetrace/compare/v0.7.0...v0.8.0
|
|
253
277
|
[0.7.0]: https://github.com/shyamexe/pagetrace/compare/v0.6.0...v0.7.0
|
|
254
278
|
[0.6.0]: https://github.com/shyamexe/pagetrace/compare/v0.5.0...v0.6.0
|
package/README.md
CHANGED
|
@@ -115,6 +115,18 @@ Routes are discovered from `robots.txt` sitemap declarations, falling back to `/
|
|
|
115
115
|
|
|
116
116
|
URLs pointing at another host are skipped. A page that cannot be fetched stops the run with an error rather than being dropped from the snapshot — a page silently missing from a crawl is indistinguishable from a page you deleted, and reporting a transient outage as a site-wide deletion is worse than failing.
|
|
117
117
|
|
|
118
|
+
### Version and updates
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
pagetrace # command list (same as --help)
|
|
122
|
+
pagetrace <command> --help # flags for one command
|
|
123
|
+
pagetrace --version # installed version
|
|
124
|
+
pagetrace update --check # ask npm whether a newer one exists
|
|
125
|
+
pagetrace update # install it globally
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
`update` refuses to install globally over a project-local copy and prints the package-manager command instead. Unrelated to `check --update`, which rewrites the lockfile.
|
|
129
|
+
|
|
118
130
|
## What it records
|
|
119
131
|
|
|
120
132
|
**Per page** — title, meta description, canonical, robots directives, Open Graph and Twitter Card tags, hreflang alternates, `h1` text, heading outline, every JSON-LD entity with its property list, word count, images missing `alt`, and the length of the first quotable paragraph.
|
package/dist/cli.cjs
CHANGED
|
@@ -24,6 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/cli.ts
|
|
27
|
+
var import_node_child_process2 = require("child_process");
|
|
27
28
|
var import_promises2 = require("fs/promises");
|
|
28
29
|
var import_cac = require("cac");
|
|
29
30
|
var import_picocolors2 = __toESM(require("picocolors"), 1);
|
|
@@ -1030,9 +1031,10 @@ function formatAuditPretty(groups, meta, columns = 80) {
|
|
|
1030
1031
|
const counted = ["error", "warn", "info"].filter((s) => issues[s] > 0).map((s) => BADGE[s](`${issues[s]} ${issues[s] === 1 ? SINGULAR[s] : PLURAL[s]}`)).join(import_picocolors.default.dim(" \xB7 "));
|
|
1031
1032
|
lines.push(import_picocolors.default.dim("\u2500".repeat(width)));
|
|
1032
1033
|
lines.push(`${import_picocolors.default.bold(`${total} issue${total === 1 ? "" : "s"}`)} ${counted}`);
|
|
1034
|
+
const found = instances.error + instances.warn + instances.info;
|
|
1033
1035
|
lines.push(
|
|
1034
1036
|
import_picocolors.default.dim(
|
|
1035
|
-
`${
|
|
1037
|
+
`${found} finding${found === 1 ? "" : "s"} across ${meta.pageCount} page${meta.pageCount === 1 ? "" : "s"}`
|
|
1036
1038
|
)
|
|
1037
1039
|
);
|
|
1038
1040
|
lines.push("");
|
|
@@ -1515,6 +1517,27 @@ async function snapshotFromOrigin(origin, options = {}) {
|
|
|
1515
1517
|
return { schemaVersion: 1, createdAt: (/* @__PURE__ */ new Date()).toISOString(), site, pages };
|
|
1516
1518
|
}
|
|
1517
1519
|
|
|
1520
|
+
// src/update.ts
|
|
1521
|
+
var REGISTRY = "https://registry.npmjs.org";
|
|
1522
|
+
function isNewer(latest, current) {
|
|
1523
|
+
const parts = (v) => v.trim().replace(/^v/, "").split(/[-+]/)[0].split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
1524
|
+
const [a, b] = [parts(latest), parts(current)];
|
|
1525
|
+
for (let i = 0; i < 3; i += 1) {
|
|
1526
|
+
if ((a[i] ?? 0) !== (b[i] ?? 0)) return (a[i] ?? 0) > (b[i] ?? 0);
|
|
1527
|
+
}
|
|
1528
|
+
return false;
|
|
1529
|
+
}
|
|
1530
|
+
async function latestVersion(name, timeoutMs = 5e3) {
|
|
1531
|
+
const response = await fetch(`${REGISTRY}/${name}/latest`, {
|
|
1532
|
+
headers: { accept: "application/json" },
|
|
1533
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
1534
|
+
});
|
|
1535
|
+
if (!response.ok) throw new Error(`npm registry answered ${response.status} for ${name}.`);
|
|
1536
|
+
const body = await response.json();
|
|
1537
|
+
if (!body.version) throw new Error(`npm registry returned no version for ${name}.`);
|
|
1538
|
+
return body.version;
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1518
1541
|
// src/cli.ts
|
|
1519
1542
|
var DEFAULT_LOCKFILE = "pagetrace.lock.json";
|
|
1520
1543
|
var DEFAULT_CONFIG = "pagetrace.config.json";
|
|
@@ -1644,11 +1667,44 @@ cli.command("audit", "Audit a site as it stands, with explanations and fixes").o
|
|
|
1644
1667
|
process.exitCode = EXIT_FINDINGS;
|
|
1645
1668
|
}
|
|
1646
1669
|
});
|
|
1670
|
+
cli.command("update", "Check npm for a newer pagetrace and install it").option("--check", "Only report whether an update exists").action(async (flags) => {
|
|
1671
|
+
const latest = await latestVersion("pagetrace");
|
|
1672
|
+
if (!isNewer(latest, "0.9.0")) {
|
|
1673
|
+
console.log(import_picocolors2.default.green(`pagetrace ${"0.9.0"} is the latest version.`));
|
|
1674
|
+
return;
|
|
1675
|
+
}
|
|
1676
|
+
console.log(import_picocolors2.default.yellow(`Update available: ${"0.9.0"} \u2192 ${latest}`));
|
|
1677
|
+
if (flags.check) return;
|
|
1678
|
+
if (process.argv[1]?.startsWith(process.cwd())) {
|
|
1679
|
+
console.log(
|
|
1680
|
+
import_picocolors2.default.dim("This is a project-local install. Update it with your package manager, e.g.")
|
|
1681
|
+
);
|
|
1682
|
+
console.log(` npm install -D pagetrace@${latest}`);
|
|
1683
|
+
return;
|
|
1684
|
+
}
|
|
1685
|
+
const { status, error } = (0, import_node_child_process2.spawnSync)("npm", ["install", "-g", `pagetrace@${latest}`], {
|
|
1686
|
+
stdio: "inherit"
|
|
1687
|
+
});
|
|
1688
|
+
if (error || status !== 0) {
|
|
1689
|
+
throw new Error(`npm install failed. Run \`npm install -g pagetrace@${latest}\` yourself.`);
|
|
1690
|
+
}
|
|
1691
|
+
console.log(import_picocolors2.default.green(`Updated to pagetrace ${latest}.`));
|
|
1692
|
+
});
|
|
1647
1693
|
cli.help();
|
|
1648
|
-
cli.version("0.
|
|
1694
|
+
cli.version("0.9.0");
|
|
1649
1695
|
async function main() {
|
|
1650
1696
|
try {
|
|
1651
1697
|
cli.parse(process.argv, { run: false });
|
|
1698
|
+
if (!cli.matchedCommand) {
|
|
1699
|
+
if (cli.options.help || cli.options.version) return;
|
|
1700
|
+
cli.outputHelp();
|
|
1701
|
+
if (cli.args[0]) {
|
|
1702
|
+
console.error(import_picocolors2.default.red(`
|
|
1703
|
+
Unknown command "${cli.args[0]}".`));
|
|
1704
|
+
process.exitCode = EXIT_FAILURE;
|
|
1705
|
+
}
|
|
1706
|
+
return;
|
|
1707
|
+
}
|
|
1652
1708
|
await cli.runMatchedCommand();
|
|
1653
1709
|
} catch (error) {
|
|
1654
1710
|
console.error(import_picocolors2.default.red(error.message));
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
+
import { spawnSync } from "child_process";
|
|
4
5
|
import { readFile as readFile2, writeFile } from "fs/promises";
|
|
5
6
|
import { cac } from "cac";
|
|
6
7
|
import pc2 from "picocolors";
|
|
@@ -1007,9 +1008,10 @@ function formatAuditPretty(groups, meta, columns = 80) {
|
|
|
1007
1008
|
const counted = ["error", "warn", "info"].filter((s) => issues[s] > 0).map((s) => BADGE[s](`${issues[s]} ${issues[s] === 1 ? SINGULAR[s] : PLURAL[s]}`)).join(pc.dim(" \xB7 "));
|
|
1008
1009
|
lines.push(pc.dim("\u2500".repeat(width)));
|
|
1009
1010
|
lines.push(`${pc.bold(`${total} issue${total === 1 ? "" : "s"}`)} ${counted}`);
|
|
1011
|
+
const found = instances.error + instances.warn + instances.info;
|
|
1010
1012
|
lines.push(
|
|
1011
1013
|
pc.dim(
|
|
1012
|
-
`${
|
|
1014
|
+
`${found} finding${found === 1 ? "" : "s"} across ${meta.pageCount} page${meta.pageCount === 1 ? "" : "s"}`
|
|
1013
1015
|
)
|
|
1014
1016
|
);
|
|
1015
1017
|
lines.push("");
|
|
@@ -1492,6 +1494,27 @@ async function snapshotFromOrigin(origin, options = {}) {
|
|
|
1492
1494
|
return { schemaVersion: 1, createdAt: (/* @__PURE__ */ new Date()).toISOString(), site, pages };
|
|
1493
1495
|
}
|
|
1494
1496
|
|
|
1497
|
+
// src/update.ts
|
|
1498
|
+
var REGISTRY = "https://registry.npmjs.org";
|
|
1499
|
+
function isNewer(latest, current) {
|
|
1500
|
+
const parts = (v) => v.trim().replace(/^v/, "").split(/[-+]/)[0].split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
1501
|
+
const [a, b] = [parts(latest), parts(current)];
|
|
1502
|
+
for (let i = 0; i < 3; i += 1) {
|
|
1503
|
+
if ((a[i] ?? 0) !== (b[i] ?? 0)) return (a[i] ?? 0) > (b[i] ?? 0);
|
|
1504
|
+
}
|
|
1505
|
+
return false;
|
|
1506
|
+
}
|
|
1507
|
+
async function latestVersion(name, timeoutMs = 5e3) {
|
|
1508
|
+
const response = await fetch(`${REGISTRY}/${name}/latest`, {
|
|
1509
|
+
headers: { accept: "application/json" },
|
|
1510
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
1511
|
+
});
|
|
1512
|
+
if (!response.ok) throw new Error(`npm registry answered ${response.status} for ${name}.`);
|
|
1513
|
+
const body = await response.json();
|
|
1514
|
+
if (!body.version) throw new Error(`npm registry returned no version for ${name}.`);
|
|
1515
|
+
return body.version;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1495
1518
|
// src/cli.ts
|
|
1496
1519
|
var DEFAULT_LOCKFILE = "pagetrace.lock.json";
|
|
1497
1520
|
var DEFAULT_CONFIG = "pagetrace.config.json";
|
|
@@ -1621,11 +1644,44 @@ cli.command("audit", "Audit a site as it stands, with explanations and fixes").o
|
|
|
1621
1644
|
process.exitCode = EXIT_FINDINGS;
|
|
1622
1645
|
}
|
|
1623
1646
|
});
|
|
1647
|
+
cli.command("update", "Check npm for a newer pagetrace and install it").option("--check", "Only report whether an update exists").action(async (flags) => {
|
|
1648
|
+
const latest = await latestVersion("pagetrace");
|
|
1649
|
+
if (!isNewer(latest, "0.9.0")) {
|
|
1650
|
+
console.log(pc2.green(`pagetrace ${"0.9.0"} is the latest version.`));
|
|
1651
|
+
return;
|
|
1652
|
+
}
|
|
1653
|
+
console.log(pc2.yellow(`Update available: ${"0.9.0"} \u2192 ${latest}`));
|
|
1654
|
+
if (flags.check) return;
|
|
1655
|
+
if (process.argv[1]?.startsWith(process.cwd())) {
|
|
1656
|
+
console.log(
|
|
1657
|
+
pc2.dim("This is a project-local install. Update it with your package manager, e.g.")
|
|
1658
|
+
);
|
|
1659
|
+
console.log(` npm install -D pagetrace@${latest}`);
|
|
1660
|
+
return;
|
|
1661
|
+
}
|
|
1662
|
+
const { status, error } = spawnSync("npm", ["install", "-g", `pagetrace@${latest}`], {
|
|
1663
|
+
stdio: "inherit"
|
|
1664
|
+
});
|
|
1665
|
+
if (error || status !== 0) {
|
|
1666
|
+
throw new Error(`npm install failed. Run \`npm install -g pagetrace@${latest}\` yourself.`);
|
|
1667
|
+
}
|
|
1668
|
+
console.log(pc2.green(`Updated to pagetrace ${latest}.`));
|
|
1669
|
+
});
|
|
1624
1670
|
cli.help();
|
|
1625
|
-
cli.version("0.
|
|
1671
|
+
cli.version("0.9.0");
|
|
1626
1672
|
async function main() {
|
|
1627
1673
|
try {
|
|
1628
1674
|
cli.parse(process.argv, { run: false });
|
|
1675
|
+
if (!cli.matchedCommand) {
|
|
1676
|
+
if (cli.options.help || cli.options.version) return;
|
|
1677
|
+
cli.outputHelp();
|
|
1678
|
+
if (cli.args[0]) {
|
|
1679
|
+
console.error(pc2.red(`
|
|
1680
|
+
Unknown command "${cli.args[0]}".`));
|
|
1681
|
+
process.exitCode = EXIT_FAILURE;
|
|
1682
|
+
}
|
|
1683
|
+
return;
|
|
1684
|
+
}
|
|
1629
1685
|
await cli.runMatchedCommand();
|
|
1630
1686
|
} catch (error) {
|
|
1631
1687
|
console.error(pc2.red(error.message));
|
package/dist/index.cjs
CHANGED
|
@@ -1275,9 +1275,10 @@ function formatAuditPretty(groups, meta, columns = 80) {
|
|
|
1275
1275
|
const counted = ["error", "warn", "info"].filter((s) => issues[s] > 0).map((s) => BADGE[s](`${issues[s]} ${issues[s] === 1 ? SINGULAR[s] : PLURAL[s]}`)).join(import_picocolors.default.dim(" \xB7 "));
|
|
1276
1276
|
lines.push(import_picocolors.default.dim("\u2500".repeat(width)));
|
|
1277
1277
|
lines.push(`${import_picocolors.default.bold(`${total} issue${total === 1 ? "" : "s"}`)} ${counted}`);
|
|
1278
|
+
const found = instances.error + instances.warn + instances.info;
|
|
1278
1279
|
lines.push(
|
|
1279
1280
|
import_picocolors.default.dim(
|
|
1280
|
-
`${
|
|
1281
|
+
`${found} finding${found === 1 ? "" : "s"} across ${meta.pageCount} page${meta.pageCount === 1 ? "" : "s"}`
|
|
1281
1282
|
)
|
|
1282
1283
|
);
|
|
1283
1284
|
lines.push("");
|
package/dist/index.js
CHANGED
|
@@ -1204,9 +1204,10 @@ function formatAuditPretty(groups, meta, columns = 80) {
|
|
|
1204
1204
|
const counted = ["error", "warn", "info"].filter((s) => issues[s] > 0).map((s) => BADGE[s](`${issues[s]} ${issues[s] === 1 ? SINGULAR[s] : PLURAL[s]}`)).join(pc.dim(" \xB7 "));
|
|
1205
1205
|
lines.push(pc.dim("\u2500".repeat(width)));
|
|
1206
1206
|
lines.push(`${pc.bold(`${total} issue${total === 1 ? "" : "s"}`)} ${counted}`);
|
|
1207
|
+
const found = instances.error + instances.warn + instances.info;
|
|
1207
1208
|
lines.push(
|
|
1208
1209
|
pc.dim(
|
|
1209
|
-
`${
|
|
1210
|
+
`${found} finding${found === 1 ? "" : "s"} across ${meta.pageCount} page${meta.pageCount === 1 ? "" : "s"}`
|
|
1210
1211
|
)
|
|
1211
1212
|
);
|
|
1212
1213
|
lines.push("");
|