Files
Nicolò Boschi 1b74e3efa8 docs(coding-agents): generate the companion skill from the README (#3735) (#3753)
The skill and the README documented the same configuration in two hand-
maintained files, and they drifted in both directions.

The skill never named `bankIdTemplate`, `dynamicBankId`, `optInOnly`,
`optInPaths`, `retainTags`, `retainMetadata`, `resolveWorktrees`,
`maxParallelRetains` or any daemon setting, and it stated outright that
the package reads "no environment variables" — there are 35
(core/config.ts ENV_KEYS). That is the half #3735 reported. The README
had lost the other half: `autoReflect` and `surveyRefreshCommits` were
documented only in the skill, and neither file mentioned that
`HINDSIGHT_CONFIG` relocates the config file, that the layering chain
ends at `banks.<resolvedBankId>`, or that `optInPaths` takes a
comma-separated env value like its sibling `retainTags`.

The README is now the single source. scripts/build-skill.mjs copies the
regions it marks with `skill:begin` / `skill:end` into skill/SKILL.md,
normalising heading levels per region; only the agent-facing half — which
tools to call, crediting memory, correcting a stale memory — stays
separate, in skill-src/preamble.md. The docs page was already generated
from the README; its generator now strips the markers, which MDX cannot
parse.

The skill's operative debugging knowledge (sync-status readiness,
resetting a bank, the survey-baseline/gitlog marker documents, the
session_start/deepen_started triage rule) moved into the README, so it
reaches users and the docs site too.

src/docs-freshness.test.ts fails when the skill is stale, when a field of
`RawConfig` is readable from a config file but named nowhere in the
README — the check that makes this class of drift impossible to
reintroduce — and when a documented claim about the env layer stops
holding (every key really is `HINDSIGHT_<FIELD_IN_CAPS>`; the four
map-valued settings really are file-only). It also unit-tests the marker
parser. prepublishOnly regenerates the skill so a publish cannot ship a
stale copy.
2026-08-24 11:06:28 +02:00

96 lines
4.5 KiB
JavaScript

#!/usr/bin/env node
/**
* Generate docs-integrations/coding-agents.md from the integration's README.
*
* The two pages said the same things in different words and drifted — the docs page kept install
* instructions that no longer worked and a harness table that had fallen behind. The README is the
* single source now; this rewrites the doc page from it so "keep them in sync" is mechanical
* instead of a habit.
*
* Two adjustments are applied, both because the audience differs:
* - Docusaurus frontmatter replaces the README's H1 (the title comes from frontmatter).
* - Repo-relative links (`src/…`, `../other-integration`) are dropped to plain text: they resolve
* on GitHub but 404 on the docs site.
* - Absolute asset URLs on our own domain become site-relative. The README must use absolute URLs
* so images render on npm and GitHub, but on the docs site those same URLs pin every image to
* PRODUCTION — so a new asset shows as broken locally and in previews until it is deployed,
* which is exactly when you are trying to look at it.
* - The `skill:begin` / `skill:end` markers are dropped. They tell the integration's
* scripts/build-skill.mjs which regions the companion skill copies; MDX has no HTML comments,
* so leaving them in would fail the docs build outright.
*
* Run: node hindsight-docs/scripts/sync-coding-agents-doc.mjs [--check]
* `--check` fails when the doc page is out of date instead of writing it (for CI).
*/
import { readFileSync, writeFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
const here = dirname(fileURLToPath(import.meta.url));
const readme = join(here, '..', '..', 'hindsight-integrations', 'coding-agents', 'README.md');
const page = join(here, '..', 'docs-integrations', 'coding-agents.md');
// Kept in the doc page's frontmatter rather than derived, so title/description stay tuned for
// search without touching the README's own heading.
const FRONTMATTER = `---
sidebar_position: 6
title: "Coding Agents"
description: "One Hindsight memory plugin for coding agents — per-repo memory banks built automatically from git history and past sessions, injected into the agent as it works."
---
{/* GENERATED from hindsight-integrations/coding-agents/README.md — edit that file, then run
node hindsight-docs/scripts/sync-coding-agents-doc.mjs */}
`;
/** Sections that only make sense inside the repo (contributor-facing), dropped from the doc page. */
const DROP_SECTIONS = ['Layout', 'Ingestion internals (no CLI)', 'Companion skill (generated)'];
function build() {
const src = readFileSync(readme, 'utf8');
const lines = src.split('\n');
const out = [];
let dropping = false;
for (const line of lines) {
const heading = /^(#{1,6})\s+(.*)$/.exec(line);
if (heading) {
const [, hashes, text] = heading;
if (hashes.length === 1) continue; // the H1 becomes frontmatter `title`
dropping = hashes.length === 2 && DROP_SECTIONS.includes(text.trim());
if (dropping) continue;
}
if (!dropping) out.push(line);
}
const body = out
.join('\n')
// Region markers for the companion-skill generator — invalid syntax in MDX, and meaningless
// to a reader of the docs site either way.
.replace(/^<!--\s*skill:(?:begin|end)[^>]*-->\n?/gm, '')
// Repo-relative links 404 on the docs site; keep the label, drop the link.
.replace(/\[([^\]]+)\]\((?!https?:|\/)[^)]+\)/g, '$1')
// Our own absolute URLs -> site-relative. Assets so the page uses THIS build's static
// files rather than whatever is live in production; doc links so they resolve within the
// site (and so the docs-skill generator can turn them into file-relative paths, which it
// cannot do with an absolute URL). The README keeps them absolute because it also renders
// on GitHub, where site-relative would 404.
.replace(/https:\/\/hindsight\.vectorize\.io\/([^\s"')]+)/g, '/$1')
.replace(/\n{3,}/g, '\n\n')
.trim();
return `${FRONTMATTER}\n${body}\n`;
}
const generated = build();
if (process.argv.includes('--check')) {
const current = readFileSync(page, 'utf8');
if (current !== generated) {
console.error(
'[coding-agents] ❌ docs page is out of date with the README.\n' +
' Run: node hindsight-docs/scripts/sync-coding-agents-doc.mjs',
);
process.exit(1);
}
console.log('[coding-agents] ✅ docs page matches the README.');
} else {
writeFileSync(page, generated);
console.log(`[coding-agents] wrote ${page} from the README.`);
}