Files
agentic-dev/scripts/work/bump-updated-timestamps.mjs
Danijel Martinek f77e6ea881 chore(template): clean-slate template snapshot from bb4a0c7
Curated, product-agnostic snapshot of the post-story-04 tree: demo
content deleted, auth-only reference feature, web-next shell, all gates
green. Product-specific docs, ADRs 027-029, PRDs/epics/archive, editor
library traces, and product naming are curated out; generic template
repairs (coverage provider devDeps, root test:coverage script, live
lint fixes, root-only release-please) are kept. See TEMPLATE.md for
provenance, curation list, and usage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016j8z4VHjedXDTjEDNg7qHK
2026-07-12 20:40:54 +02:00

80 lines
2.4 KiB
JavaScript

#!/usr/bin/env node
/**
* Stamp every staged `docs/work/**\/*.md` file's frontmatter `updated:` field
* to the current ISO 8601 timestamp. Runs from `.husky/pre-commit` before
* `pnpm work rebuild-state`, so `_state.json` sees the fresh value.
*
* Idempotent: re-running produces the same result. The script silently no-ops
* on files without frontmatter or without an `updated:` line to replace —
* adds the field after `created:` if missing.
*
* Only stamps files explicitly listed in the staged diff; never walks the
* tree. That way the timestamp tracks "the last commit that actually
* modified the file," not "the last commit period."
*/
import { execSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
const REPO_ROOT = execSync("git rev-parse --show-toplevel", {
encoding: "utf8",
}).trim();
function stagedWorkDocs() {
const out = execSync("git diff --cached --name-only --diff-filter=ACMR", {
cwd: REPO_ROOT,
encoding: "utf8",
});
return out
.split("\n")
.map((p) => p.trim())
.filter(
(p) =>
p.startsWith("docs/work/") &&
!p.startsWith("docs/work/archive/") &&
p.endsWith(".md") &&
!p.endsWith("README.md"),
);
}
function stampUpdated(content, isoNow) {
const fmMatch = content.match(/^(---\n)([\s\S]+?)(\n---)/);
if (!fmMatch) return content;
const [full, openDelim, body, closeDelim] = fmMatch;
let newBody;
if (/^updated:\s*/m.test(body)) {
newBody = body.replace(/^updated:\s*.*$/m, `updated: ${isoNow}`);
} else if (/^created:\s*/m.test(body)) {
// Insert `updated:` immediately after the `created:` line.
newBody = body.replace(/^(created:\s*.*)$/m, `$1\nupdated: ${isoNow}`);
} else {
return content;
}
return content.replace(full, `${openDelim}${newBody}${closeDelim}`);
}
function main() {
const files = stagedWorkDocs();
if (files.length === 0) return;
const isoNow = new Date().toISOString();
let touched = 0;
for (const rel of files) {
const abs = path.join(REPO_ROOT, rel);
if (!fs.existsSync(abs)) continue;
const original = fs.readFileSync(abs, "utf8");
const next = stampUpdated(original, isoNow);
if (next === original) continue;
fs.writeFileSync(abs, next);
execSync(`git add ${JSON.stringify(rel)}`, { cwd: REPO_ROOT });
touched++;
}
if (touched > 0) {
console.log(
`bump-updated-timestamps: stamped ${touched} file(s) at ${isoNow}`,
);
}
}
main();