cli/AGENTS.md at master · diplodoc-platform/cli · GitHub
Skip to content

Latest commit

 

History

History
347 lines (250 loc) · 15.1 KB

AGENTS.md

File metadata and controls

347 lines (250 loc) · 15.1 KB

AGENTS.md

This file contains instructions for AI agents working with the @diplodoc/cli project.

Module Documentation

If a module contains a MODULE.md file, it is considered part of the module's context and should be consulted when working with that module. These files provide module-specific documentation, architecture decisions, and implementation details that complement the general project documentation.

Project Description

@diplodoc/cli is a CLI tool for building documentation from Markdown files with Yandex Flavored Markdown (YFM) support. The project allows you to build full-fledged documentation with navigation, internal transitions, and full YFM support.

Project Structure

Main Directories

  • src/ — source code of the project
    • commands/ — CLI commands (build, publish, translate)
    • core/ — core logic (config, logger, markdown, toc, etc.)
    • extensions/ — extensions (openapi, generic-includer, local-search)
    • steps/ — DEPRECATED processing steps (do not add new code here)
  • build/ — compiled code (generated during build)
  • lib/ — libraries (generated during build)
  • tests/ — project tests
    • e2e/ — end-to-end tests
    • cases/ — test cases
    • fixtures/ — test fixtures
    • mocks/ — test mocks

Packaged tests contract: tests/ and vitest.integration.config.ts are shipped in the npm package (see files in package.json). Downstream consumers run the integration suite from the packaged layout against their own binary via the DIPLODOC_BINARY_PATH env variable. Therefore specs under tests/ must not depend on anything outside tests/ and the built CLI - in particular not on scripts/ or src/, which are not shipped. A spec that needs them must be excluded from the package with a !-pattern in files (see tests/e2e/translate-eval.spec.ts).

CLI Commands

  1. build — main command for building documentation

    • Location: src/commands/build/
    • Subcommands and features are located in src/commands/build/features/
  2. publish — publishing documentation

    • Location: src/commands/publish/
  3. translate — translating documentation

    • Location: src/commands/translate/

    Seed reuse is not limited to lines changed in the source PR. stableProsePairs in providers/ai/utils/align.ts rejects unanchored prose when its enclosing section diverges. Matched root headings and bold labels ending in a colon immediately before cuts delimit sections only when their pairing is monotone; headings inside cut/note/tab containers do not. A release label can be **Releases:**, not an ATX heading. When verifying preservation, compare every unchanged region with the approved target, including the introduction before the first release cut. Checking only the old release suffix misses this case. Check copied files against their old counterparts too: a same-path diff represents the new include as entirely added. Run translate seed offline to inspect per-file pairs, then exercise composition: extraction can normalize padding before link destinations. The loader restores this padding only when occurrences of the same URL agree; ambiguous padding remains unsupported. seed_partial does not imply PARTIAL: newly translated units can succeed while changing previously approved wording. Exact Markdown copies to new paths use SeedStore document snapshots: a raw source fingerprint includes vars and code mode, and matching approved targets must agree byte for byte. This preserves occurrence-specific wording even when the same source phrase has different translations in one file; the shared dictionary alone picks a single wording. Snapshots are recorded independently of unit alignment, including merged target prose and files without units. Existing paths and edited copies continue through unit translation and markup checks. Verify both branches with the real provider, including copied-file counters; a preservation run that makes zero model requests is not a quality check of newly translated text.

  4. content — render a single file to stdout/file (md or html content fragment)

    • Location: src/commands/content/
    • Reuses the build Run, its normalize/validate and buildConfigDefaults (src/commands/build/config.ts), MarkdownCollector/SELF_CONTAINED (md) and getBaseMdItPlugins (html).
    • Root/file resolution is the pure resolveContentConfig (src/commands/content/config-resolve.ts): picks the project root from -c's directory or CWD (falling back to the file's own dir when it lives outside that root), sets config.input/output to that root with originAsInput = true, stores the target as config.file, and populates config.template itself (build's Templating feature is not run).
    • stdout has two modes: default wraps the result in CONTENT_START/CONTENT_END markers (so it can be fished out of the framework banners); --raw (config.raw) emits only the content. In raw mode src/index.ts also skips the version/timer/completion banners via isRawContentRun(argv) (exported from the content command). -o always writes raw (no markers), regardless of --raw.
    • Note: resolveConfig treats ENOTDIR like ENOENT so a single-file --input doesn't break config discovery.
    • Tests: unit specs co-located in src/commands/content/*.spec.ts (resolution, render md/html, emit stdout/-o, watch paths/rebuild, ContentWatcher) drive Sonar coverage; e2e lives in tests/e2e/content.spec.ts (out-of-process, not counted by Sonar).

Tech Stack

  • Language: TypeScript
  • Runtime: Node.js >= 22
  • Testing: Vitest
  • Build: esbuild
  • Linting: ESLint (via @diplodoc/lint)

Development Commands

# Build project
npm run build

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Run E2E tests
npm run e2e

# Type checking
npm run typecheck

# Linting
npm run lint
npm run lint:fix

Working with Code

Imports

The project uses path aliases:

  • ~/ — points to src/
  • Example: import {Program} from '~/core/program'

Architecture

  1. Program — main class that manages command execution

    • Located in src/commands/index.ts
    • Uses decorator pattern (@withConfigDefaults)
  2. Commands — CLI commands inherit from BaseProgram

    • Each command can have its own options, hooks, and handlers
  3. Features — functionality is grouped into features

    • Examples: output-html, search, watch, etc.
    • Each feature can have its own configuration and hooks
  4. Hooks — hook system for extending functionality

    • Uses tapable library

Command Structure

Every command should follow a well-defined structure to ensure maintainability and separation of concerns.

Command Organization

  • Main logic is concisely gathered in index.ts
  • Implementation is divided into separate functionalities through features/
  • Features do not depend on each other
  • A command can extract part of functionality into services, located in services/ directory
  • Services do not depend on each other
  • If multiple features need to use the same computed data, such data (and logic for working with them) should be extracted into a service
  • If multiple features use the same logic for processing their own data, such logic should likely be extracted into a common utility in the utils/ directory at the same level as features/ and services/
  • Utils may depend on each other
  • Utils cannot depend on anything outside of utils/

Command Files

  • index.ts — main entry point with concise core logic
  • hooks.ts — command hooks for external interaction are always described here
  • config.ts — command and feature configurations for CLI are described here
  • types.ts — public types are always described here and exported from the module via index.ts
    • Only public types are exported from types.ts
    • Common types used only at the module level should be described next to the entity that produces these types

Features

Features represent separate functionalities of a command:

  • Located in features/[feature-name]/ directory
  • Features are independent and do not depend on each other
  • Each feature can have its own:
    • index.ts — feature implementation
    • config.ts — feature configuration
    • hooks.ts — feature hooks (optional)

Services

Services contain shared business logic:

  • Located in services/[service-name]/ directory
  • Services are independent and do not depend on each other
  • Services are used when multiple features need shared computed data or logic
  • Services can have:
    • index.ts — service implementation
    • types.ts — service-specific types
    • hooks.ts — service hooks (optional)

Utils

Utility functions for shared logic:

  • Located in utils/ directory at the same level as features/ and services/
  • Utils may depend on each other
  • Utils cannot depend on anything outside of utils/ (no dependencies on features, services, or external modules)
  • Use utils when multiple features need the same data processing logic

Core Modules

The core/ directory contains logic common to all commands:

  • Most often this logic is organized into services
  • But base (abstract) classes are also possible, for example BaseProgram
  • Used in external extensions in a fully bundled form, i.e., dependencies from core are fully bundled

Core Structure Rules

The same rules apply to core/ as to commands:

  • types.ts — only public types are exported
  • hooks.ts — hooks are always described here
  • Service concept applies — logic is organized into services
  • Common types used only at the module level should be described next to the entity that produces these types

Code Conventions

  1. File naming:

    • Type files: types.ts
    • Configuration: config.ts
    • Main module file: index.ts
    • Tests: *.spec.ts or *.test.ts
  2. Comments and documentation:

    • All code comments must be in English
    • All documentation files (ADR, AGENTS.md, README, etc.) must be in English
    • JSDoc comments are used for exported functions/classes
  3. Variables:

    • Avoid single-letter variable names
    • Don't use overly long variable names

Testing

CLI diagnostics share the YFM numbering namespace with yfmlint. YFM024 is the published empty-heading-ID rule; YFM025 is the CLI-only missing-local-anchor rule. Check both registries before assigning a number and keep their configuration independent.

  1. Unit tests:

    • Uses Vitest
    • Tests are next to code or in __tests__/
    • Prefer using vitest-when for mocking instead of standard mockImplementation
  2. E2E tests:

    • Located in tests/e2e/
    • Snapshots are used for output verification
  3. Test fixtures:

    • Data preparation (Arrange) should be grouped into helper functions when the same setup is repeated across tests

Working with Playwright (if used)

  • Prefer using page.goto() instead of page.evaluate() for navigation
  • Avoid page.locator(selector).first() — use more explicit and reliable selectors

Key Modules

Core Modules

  • core/config/ — configuration management
  • core/logger/ — logging
  • core/markdown/ — Markdown processing
  • core/toc/ — table of contents management
  • core/vcs/ — version control systems integration
  • core/program/ — base program and extension system

Build Command

Main build logic is located in:

  • src/commands/build/handler.ts — command handler
  • src/commands/build/run.ts — command execution
  • src/commands/build/features/ — various build features

llms.txt OpenAPI companions

src/commands/build/features/llms/ collects entries from the resolved TOC recursively while excluding hidden subtrees and external links. Preserve the parent TOC item name on collected entries: for an OpenAPI include, the parent name labels the whole API section, while leadingPage.name labels only the generated landing page. In llms.txt, emit the companion *.openapi.json link with the parent name immediately before its matching landing-page link. run.openapiCompanions provides the leadingPage -> companionPath mapping.

Extensions

Extensions integrate with CLI through hooks. There are two integration patterns based on initialization approach:

  1. Independent extensions — extensions that are not automatically initialized by CLI (can use peerDependency regardless of monorepo membership)
  2. Auto-initialized extensions — extensions that CLI automatically imports and initializes on startup (require wrapper logic in src/extensions/ to avoid circular dependencies)

For details, see ADR-001: Dependent Extensions.

Auto-initialized extensions:

  • extensions/openapi/ — OpenAPI support (wrapper for @diplodoc/openapi-extension)
  • extensions/generic-includer/ — generic includer
  • extensions/local-search/ — local search (wrapper for @diplodoc/search-extension)
  • extensions/github-vcs/ — GitHub integration
  • extensions/arcadia-vcs/ — Arcadia integration

Configuration

The project supports configuration via:

  1. .yfm file (YAML)
  2. Command-line arguments
  3. Environment variables

Main configuration files:

  • YFM_CONFIG_FILENAME — configuration file name (usually .yfm)

Additional Resources

  • README.md — main documentation
  • CONTRIBUTING.md — contributor guide
  • CHANGELOG.md — change history
  • adr/arch-quality.md — architectural quality principles
  • adr/ADR-001-dependent-extensions.md — architecture decision record for extension integration patterns

Module Documentation

  • MODULE.md — if present in a module directory, this file contains module-specific documentation and is part of the module's context for AI agents
    • Provides module architecture, implementation details, and usage patterns
    • Should be consulted when working with that specific module
    • Example locations: src/core/MODULE.md, src/commands/build/MODULE.md, etc.

Common Tasks

Adding a New Command

  1. Create directory in src/commands/[command-name]/
  2. Create command class inheriting from BaseProgram
  3. Register command in src/commands/index.ts

Adding a New Feature to Build

  1. Create directory in src/commands/build/features/[feature-name]/
  2. Implement feature with hooks
  3. Register feature in src/commands/build/index.ts

Adding a New Extension

  1. Create directory in src/extensions/[extension-name]/
  2. Implement extension
  3. Register in project configuration

Important Notes

  1. The project uses a monorepo (nx)
  2. All changes must pass linter and tests
  3. Types must be correct (checked via npm run typecheck)
  4. When working with VCS (GitHub/Arcadia), token configuration is required in .env or .yfm
  5. All comments and documentation files (ADR, AGENTS.md, README, etc.) must be written in English
  6. The src/steps/ directory is deprecated. Do not add new code there. If you need to fix existing code, carefully move it to commands/build/features/
  7. When changing TypeScript types that have a corresponding schema in schemas/, always update the schema to match, and vice versa