65 lines
3.2 KiB
Text
65 lines
3.2 KiB
Text
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
||
|
|
// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
||
|
|
|
||
|
|
export module Crafter.Build:Agents;
|
||
|
|
import std;
|
||
|
|
namespace fs = std::filesystem;
|
||
|
|
|
||
|
|
// Dependency notes. A crafter-build project ships an AGENTS.consumer.md beside
|
||
|
|
// its project.cpp, written for the agents of the projects that depend on it,
|
||
|
|
// and crafter-build keeps those files in each consumer's AGENTS.md. Without
|
||
|
|
// that, an agent working on a consumer knows nothing about the libraries it
|
||
|
|
// builds against unless someone copied the knowledge in by hand, and a copy
|
||
|
|
// goes stale the moment the library changes.
|
||
|
|
export namespace Crafter {
|
||
|
|
struct Configuration;
|
||
|
|
|
||
|
|
// Which dependencies' notes a project's AGENTS.md carries: the value of
|
||
|
|
// Configuration::dependencyNotes.
|
||
|
|
enum class DependencyNotes {
|
||
|
|
// The projects this one builds against, and the projects those build
|
||
|
|
// against, all the way down.
|
||
|
|
Transitive,
|
||
|
|
// Only the projects this one's own configurations, tests and
|
||
|
|
// `#pragma crafter dependency` lines name.
|
||
|
|
Direct,
|
||
|
|
// None. A section an earlier build wrote is removed.
|
||
|
|
None,
|
||
|
|
};
|
||
|
|
|
||
|
|
// One dependency's AGENTS.consumer.md, ready to merge.
|
||
|
|
struct DependencyNote {
|
||
|
|
// Where it came from, written into the comment above it: the git URL,
|
||
|
|
// or for a local project the file's path relative to the consumer.
|
||
|
|
std::string source;
|
||
|
|
// The file's content, without leading blank lines or trailing
|
||
|
|
// whitespace.
|
||
|
|
std::string text;
|
||
|
|
};
|
||
|
|
|
||
|
|
// `agentsMd` with its dependency notes section holding `notes`, in order.
|
||
|
|
// A file without a section gets one appended after a blank line; one
|
||
|
|
// with a section has it rewritten in place, wherever it was moved to;
|
||
|
|
// and empty `notes` remove it together with that blank line, so a file
|
||
|
|
// that only ever gained the section gets its own bytes back.
|
||
|
|
//
|
||
|
|
// The two marker lines count only as whole lines outside fenced code
|
||
|
|
// blocks, which is what lets a document quote them. Throws, naming the
|
||
|
|
// line, when the markers are unbalanced or the document ends inside a
|
||
|
|
// code block: guessing which part of someone's file is generated would
|
||
|
|
// overwrite their text, and missing the section would add a second one
|
||
|
|
// on every build. Also throws for a note that would break the section
|
||
|
|
// when it is read back: one with a marker line of its own, or a code
|
||
|
|
// block it never closes.
|
||
|
|
std::string MergeDependencyNotes(std::string_view agentsMd, std::span<const DependencyNote> notes);
|
||
|
|
|
||
|
|
// Refresh the dependency notes section of the AGENTS.md beside
|
||
|
|
// `projectFile` from the AGENTS.consumer.md of every dependency
|
||
|
|
// project.dependencyNotes selects. `project` is the Configuration that
|
||
|
|
// file returned, after LoadProject: loading is what found the
|
||
|
|
// dependencies. Does nothing when there is no AGENTS.md, which is never
|
||
|
|
// created. Writes only when the text changes, and returns whether it
|
||
|
|
// did. An unreadable file, a failed write, malformed markers and a
|
||
|
|
// dependency's unusable notes are warnings: the notes never fail a build.
|
||
|
|
bool UpdateAgentsMd(const Configuration& project, const fs::path& projectFile);
|
||
|
|
}
|