_manifest.json
_manifest.json is a file in GovLab Extension Host. 88 lines of code and 0 definitions.
{
"label": "GovLab Extension Host",
"summary": "The consumer-side extension host govlab loads by convention: the local lint rules and the workspace plugins that gate this repo's architecture, the checker-driven codemods that apply the fixes a linter cannot apply safely, and the doc-verb registry govlab.docs reads. Govlab discovers it by directory shape instead of a registration list, so dropping a file in is the whole wiring.",
"maturity": "stable",
"domains": [
{"meta": "developer-tooling",
"sub": "linting-quality"},
{"meta": "developer-tooling",
"sub": "code-generation"}
],
"capabilities": [
"local-rule-hosting",
"workspace-plugin-hosting",
"rule-index-generation",
"project-scope-guarding",
"checker-driven-codemods",
"syntax-verified-rewriting",
"doc-verb-extension"
],
"overlaps": [],
"incompatibleWith": [],
"supersedes": [],
"governedBy": [
"type-safety",
"separation-of-concerns",
"duplicate-code"
],
"visibility": {"private": true,
"hidden": false},
"ecosystem": "typescript",
"deliverAs": "source",
"entries": [
"rules/plugins/*.plugin.ts",
"rules/entrypoints/*.entrypoint.ts",
"shared/manifests/*.manifest.ts",
"codemods/entrypoints/*.entrypoint.ts",
"codemods/validators/*.validator.ts"
],
"docs": {
"overview": "Govlab reads every consumer's `.govlab/` by convention, so this directory is wiring-free: a file's location is its registration. `rules/eslint/` holds the local rules. `rules/entrypoints/index.entrypoint.ts` walks it and writes the generated rule index, the exclusion markers and the file budget under `shared/generated/`. `rules/plugins/rule.plugin.ts` wraps each rule once with the `isGovernedFile` guard, which reaches every governed root the taxonomy declares. `rules/entrypoints/writing.entrypoint.ts` renders the writing canon from `shared/manifests/writing.*.manifest.ts` into `.claude/rules/register.md` and checks the canon's records, `CLAUDE.md` and every `_manifest.json` against it. A rule whose meta declares `workspaceWide` sits outside that guard, as does any wrapper file in `rules/eslint/` that default-exports `{ tool, plugins }`. `codemods/` holds the TypeScript-program-driven rewriters: each is an analyzer under `codemods/analyzers/` producing findings with a `reason` plus an entrypoint under `codemods/entrypoints/` that applies only what the checker proves safe. `codemods/validators/` holds the whole-program checks the gate runs, such as field reach and closed values. `shared/` holds the seams the rules compose: selectors over the syntax tree, the listener factory, the anchor resolver, the manifests, the allowlists and the exclusions. `types/` is the host's flat type bucket.",
"whenToUse": [
"Adding a rule that governs the governed roots. The rule is a file in `rules/eslint/`, and the index is regenerated after it lands.",
"Adding a rule that governs the whole workspace. The rule is a file in `rules/eslint/` exporting `{ tool, plugins }`, named explicitly in the quality config.",
"Replacing a linter's unsafe auto-fixer. The replacement is an analyzer plus an entrypoint under `codemods/`, which verifies its own output before writing.",
"Changing how a string is written. The rules are records in `shared/manifests/writing.*.manifest.ts`, and the writing entry point renders them again."
],
"whenNotToUse": [
"Rules that belong to the framework instead of this consumer. Those live in `@govlab/quality`'s own plugins and reach every consumer through the catalog.",
"Mechanical rewrites a linter already applies safely. A codemod is for the cases where a fixer would produce unverified output.",
"Anything needing a published entry point. The host exposes no API for other members to import."
],
"quickStart": [
{
"intent": "Add a member-scoped lint rule and activate it",
"code": "# drop the rule in, then regenerate the index govlab.config reads\nnode .govlab/rules/entrypoints/index.entrypoint.ts"
},
{
"intent": "Run a codemod, which applies fixes by default",
"code": "node .govlab/codemods/entrypoints/increment.entrypoint.ts"
},
{
"intent": "Inspect what a codemod would touch, without writing",
"code": "node .govlab/codemods/entrypoints/code-point.entrypoint.ts --map"
},
{
"intent": "Replace an exact string across data files, listing the matches first",
"code": "npm run codemod:literal -- --from '\"old_id\"' --to '\"new_id\"' --root govlab.root/govlab.context/configuration --ext .json --map"
},
{
"intent": "Narrow a codemod to the programs one member owns",
"code": "node .govlab/codemods/entrypoints/increment.entrypoint.ts --tsconfig banes-lab.root/banes-lab.web/tsconfig.json"
}
],
"configuration": "No config file of its own. Roots resolve through `@ssot/paths`. `shared/resolvers/anchor.resolver.ts` is the single anchor: it names the application member, exports the roots every local rule shares and resolves a file to the container of its own governed root. `types/rule.types.ts` carries the typed ESLint surface: `LocalRule`, `RuleContext` and `RuleListener`. Discovery skips `_`-prefixed and `.generated.ts` files. Codemods read the tsconfig list in `codemods/selectors/program.selector.ts`, which defaults to one program per workspace member and narrows to whatever `--tsconfig <comma list>` names.",
"disposal": [
"Deleting a rule file and regenerating the index removes the rule from the gate, with no registration list to clean up.",
"Deleting a workspace plugin file also requires dropping its entries from `eslint.rules` in the root `.govlab/govlab.config.ts`, which names them explicitly.",
"Deleting a codemod also removes its step from the pipeline's auto-fix stage, where the stage planner lists each one."
],
"aiContext": [
"Location is registration. The plugin's guard scopes a rule in `rules/eslint/` to the governed roots. A rule declaring `workspaceWide`, or a wrapper exporting `{ tool, plugins }`, bypasses the guard. The declaration chooses the blast radius.",
"Codemods verify their own output: `applyEdits` re-parses the rewritten file and refuses to write when the rewrite introduces a syntax error.",
"A codemod splits findings into convertible and blocked, and a blocked finding carries a `reason`. `gateOnBlocked` decides whether a blocked finding fails the run.",
"A codemod's coverage is its tsconfig list. A member absent from that list is never scanned and the run still reports success. Adding a member means adding its tsconfig here as well as to the workspaces glob.",
"Never rely on `node.parent` or `node.getSourceFile()` in an analyzer: parent pointers are populated only once the binder runs, which happens when a checker is requested. Thread `sourceFile` and `parent` through the walk instead."
]
}
}