Skip to content

Version Packages - #190

Open
github-actions[bot] wants to merge 1 commit into
mainfrom
changeset-release/main
Open

Version Packages#190
github-actions[bot] wants to merge 1 commit into
mainfrom
changeset-release/main

Conversation

@github-actions

@github-actions github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

leadtype@0.5.0

Minor Changes

  • 4c1b962: Add a canonical config vocabulary and one resolved-config normalizer.

    defineLeadtypeConfig names the project/site config in leadtype.config.ts, alongside defineDocsConfig for a source repo's content-owned docs.config.ts. Three collection fields are renamed: prefixroutePrefix, sourceConfiginheritConfig, schemafrontmatterSchema.

    Every existing config keeps working. Both spellings normalize to one internal ResolvedDocsConfig that generate, sync, lint, score, and the runtime source all read, so no subsystem re-derives the project from raw config. The resolved shape adds a deduped source graph — collections sharing a (repository, ref) resolve to one acquisition — and per-field provenance recording whether each value was authored, inherited from a source repo, inferred, or defaulted.

    Deprecated fields carry @deprecated guidance in the IDE and warn once per config file at load. Setting an old name and its replacement together is an error naming both rather than a silent precedence rule. Nothing is removed before 1.0.

  • 5aa8d2b: Derive navigation and the llms.txt body when they aren't authored, so a new project reaches useful output from identity alone.

    Navigation is derived from the content tree — root pages at the root, one section per top-level directory titled from its index page, ordered index first then frontmatter order then path, so it never depends on filesystem enumeration order. The llms.txt body becomes a "Best Starting Points" block built from that same resolved navigation, which keeps an agent's entry points from drifting from a reader's. Product name and tagline fall back to package.json.

    Both leadtype generate and createDocsSource() derive the same tree, so the rendered sidebar and the generated artifacts agree. Explicit configuration always wins: authoring navigation, groups, or llms.sections turns inference off for that field, and inference never merges with or rewrites an authored value.

    leadtype generate --explain reports every derived value, what it was derived from, and the field that takes control of it. Ambiguous derivations — pages with no frontmatter title, or more pages than the starting-points block lists — warn with the field to set.

    leadtype init now scaffolds identity only.

  • 2fda088: Add createDocsProject() — the resolved project config as a runtime source.

    createDocsSource() describes one content directory, so an app restates what its config already says: the content root, navigation, mounts, the frontmatter schema, and for a multi-collection project all of that per collection plus route prefixes and source-owned inheritance. Two descriptions of one project drift, and when they do the rendered site and the generated agent artifacts disagree about what exists.

    A project reads the same resolved config the artifact pipeline reads, and returns a superset of DocsSource, so every first-party adapter accepts it unchanged:

    const source = await createDocsProject({
      config: docsConfig,
      configPath: "docs/docs.config.ts",
      baseUrl: "https://example.com",
    });

    Multi-collection projects get one merged, route-aware page API — listPages() tags each page with its collection, loadPage() accepts a collection-local slug or the full route — plus project.collections, project.sources, and project.getSource(key) for custom integrations. Source-owned config inheritance now runs through one shared implementation, so human rendering and generated artifacts cannot resolve it differently.

    Remote collections are cache-only: a missing, unverifiable, or wrong-revision cache fails with a diagnostic naming leadtype sync rather than cloning inside a request. Route collisions name both collections.

    createDocsSource() stays fully supported and is what the project is built on. leadtype init now scaffolds the project primitive.

  • 43883be: Add gitSource() for declaring one git acquisition with its content collections beneath it.

    The flat collections map makes every collection carry repository, ref, and cacheDir even when several come from the same repository — so a config repeats acquisition three times for one clone, and a reader has to know that matching (repository, ref) pairs are deduped. A source group declares the clone once:

    sources: {
      c15t: gitSource({
        repository: "https://github.com/c15t/c15t.git",
        ref: "main",
        inheritConfig: true,
        collections: {
          docs: { dir: "docs", routePrefix: "/docs" },
          changelog: { dir: "changelog", routePrefix: "/changelog", inheritConfig: false },
        },
      }),
    }

    The source owns acquisition and the default inheritance policy; each collection owns its directory, route prefix, navigation, and any inheritance exception. Both forms normalize to the same source graph, and sources may be used alongside collections.

    Collection ids stay global rather than being scoped to their source, because they name staging mounts, error messages, and JSON output — two sources declaring the same id is an error naming both, not an auto-rename. So is declaring one (repository, ref) under two source names.

    sparse limits a checkout to the repository paths you actually need, via a blobless partial clone — pinning a docs directory out of a monorepo no longer downloads the whole repository. Collections sharing an acquisition must agree on the path set, and the set is recorded in the sync manifest so adding a path re-clones rather than reusing an incomplete cache.

    leadtype sync now reports each source id with its dependent collections, and warns when a source tracks a mutable ref instead of a pinned commit. leadtype generate --json reports the same acquisition graph, using the same ids — a named source keeps its authored name, an anonymous one is identified by repository#ref. inheritConfig: false opts a collection out of a source-level inheritance default.

  • c21b6b9: Add leadtype doctor — a read-only explanation of the resolved project.

    The other commands each answer a question about a project by doing something to it. None answered "what is this project, and why?" — which config was discovered, whether it resolved single-source or multi-repo, which values were authored versus inherited versus inferred, which collections share one clone, what routes will exist, and which command fixes what is currently wrong.

    Doctor never clones, refreshes, writes, or generates, so an unsynced remote is a finding naming leadtype sync rather than a fetch. Everything it reports comes from the same config loader and resolvers generate and sync use, so a clean doctor run and a clean generate run cannot disagree.

    Checks cover config discovery and provenance, deprecated aliases, the deduped acquisition graph with pinned-versus-mutable refs and cache freshness, collection directories and include globs, the resolved navigation tree and pages that fall back to the root instead of being placed, expected output artifacts and their staleness, the detected framework adapter, and enabled agent surfaces.

    Human output is concise and every finding names its owning config field and a concrete next command. --json carries stable finding ids and provenance so agents can act without parsing prose. Exit 0 when nothing is an error, 1 when a required input is missing or invalid.

  • ba6ecdb: Reduce navigation config churn for large and repeated docs trees.

    A curated tree earns its cost while every entry is a decision. It stops earning it when a section is mostly inventory — twenty pages where three must lead and the rest could be alphabetical — because then every new page is added twice, on disk and in the config, and the two drift.

    navigation.fromDirectory() (from leadtype/navigation) includes a directory without listing it, and the new pin option on include entries keeps the pages whose position is a decision at the front:

    {
      title: "Concepts",
      base: "concepts",
      pages: navigation.fromDirectory(".", {
        pin: ["initialization-flow", "consent-models"],
        exclude: "internal-*",
      }),
    }

    Pinned pages lead in the order given; the rest follow in sort order, so adding a page appends it to the tail and never displaces a deliberate choice. Explicit refs and an expansion can share one pages array. A pin matching nothing is an error rather than a silent no-op — that is almost always a rename the config missed. Expansion still happens once during navigation resolution, so one resolved tree keeps driving the sidebar, llms.txt, AGENTS.md, the sitemap, and Agent Readability metadata.

    leadtype nav prints the tree your config actually resolves to and reports drift: pages no curated entry places, pages two entries both claim, and pages whose group: names a group the config never declares. Human and --json output, per collection, read-only — it never writes config, moves content, or changes a public route.

  • 8e3c431: Add resolveProject() — one function for the whole config pipeline.

    Answering "what is this project?" takes five ordered steps: discover the config, apply source-owned inheritance, normalize to canonical names, derive what wasn't authored, and resolve each collection's content directory through the sync cache. generate, doctor, nav, and createDocsProject each assembled those by hand, and doctor and nav shipped with the same two bugs as a result — both skipped inheritance, and both resolved a remote collection's dir against the config directory rather than its checkout.

    They now read one resolved project. It throws only for a malformed config; everything environmental — an unsynced source, a missing directory, unreadable source config — is a diagnostic carrying a stable id, the owning config field, and the command that fixes it. That split is what lets doctor report a problem and keep going while createDocsProject refuses to hand a renderer a source it cannot read.

    createDocsProject() no longer needs a config passed to it: it discovers leadtype.config.* or docs.config.* the same way the CLI does, so an app with a config file doesn't import it just to hand it back.

    export const source = await createDocsProject({
      baseUrl: "https://example.com",
    });

    Config loading also moves out of the CLI into leadtype's config module, so the runtime no longer reaches through the generate pipeline to answer which config describes a project.

Patch Changes

  • d517dc5: Make the generated docs-skill and the leadtype init AGENTS.md pointer describe documentation authoring, not just retrieval. A skill's description is the whole activation signal a client sees before loading it, so "read and search the docs" lost the most common docs task there is — writing, editing, reviewing, and restructuring the pages themselves.

  • f9d2185: Hash paths.lock.json entries from authored source, not generated markdown.

    The lockfile exists to remember published paths so a later generate can detect renames. Fingerprinting the generated .md mirror folded ExtractedTypeTable rows, expanded includes, and converter formatting into every hash — so working on unrelated types, running generate in --watch, or even regenerating with a slightly different pipeline rewrote a committed lockfile. Hashes now come from the source .mdx/.md body when one exists (frontmatter still excluded). Pages with no authored source, such as generated OpenAPI reference pages, still hash the mirror. redirectFrom is still read from the generated mirror, so afterFrontmatter transformers that add it keep working.

    The next generate after upgrading rewrites hashes once. Old and new hashes cannot match, so a rename in that same generate will fail as an unmatched disappearance instead of auto-redirecting. Upgrade and rename in two separate generates (two commits). After the first rewrite, authored pages only change the lockfile when their source body or the path set changes.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@github-actions
github-actions Bot force-pushed the changeset-release/main branch from 60d8461 to 5708316 Compare August 19, 2026 21:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants