← All tasks
cppclaude-code/cpp-t1 #30Not a task: not reproduced

Markdown to HTML Converter (cpp, written by Claude Code)

envgap__claude-code__cpp-t1-30

Written by a coding agent; not on GitHubWritten 2026-02-28

01 / FAILURE SIGNATURE

As the study recorded it

brace init conversion error + wrong link targets
Not a benchmark task.
  • In a clean container the reported failure did not reproduce, or the known fix did not make the project run.

02 / ENVIRONMENT RECIPE

Base commit
Not freshly verified
Manifest
CMakeLists.txt
Reproduce
Awaiting issue-specific recipe
Run under trace
Awaiting a meaningful runtime command

03 / TASK AND FAILURE

claude-code/cpp-t1 #30 · read the task the agent was given
Claude Code wrote this cpp project from the task below. It does not run on a clean Ubuntu 22.04 machine as written.

Task given to the agent:

TASK: Markdown to HTML Converter

Write a program that converts Markdown documents to HTML with support for GitHub Flavored Markdown extensions, syntax highlighting of code blocks, table of contents generation, and custom CSS styling.

FUNCTIONAL REQUIREMENTS:
- Accept a Markdown file path as a command-line argument
- Support standard Markdown: headings (h1-h6), bold, italic, strikethrough, links, images, blockquotes, ordered and unordered lists, horizontal rules, inline code, and code blocks
- Support GitHub Flavored Markdown extensions: tables, task lists (checkboxes), fenced code blocks with language identifiers, autolinks, and footnotes
- Apply syntax highlighting to fenced code blocks based on the specified language (support at least: python, javascript, java, c++, html, css, json, bash)
- Generate a table of contents from headings via --toc flag, inserted at the top of the document with anchor links
- Support custom CSS styling via --css flag (path to a CSS file to embed or link in the output)
- Support wrapping the output in a complete HTML document (with DOCTYPE, head, body) via --full-page flag, or outputting just the HTML fragment (default)
- Support automatic heading ID generation for anchor links based on heading text
- Support converting multiple Markdown files via --batch flag, with optional --index flag to generate an index page linking all converted files
- Print the HTML output to console by default
- Save the HTML to a file via --output flag (default: same base name with .html extension)
- If no input file is given, generate a sample Markdown document demonstrating all supported features (headings, lists, code blocks, tables, images, links, task lists, footnotes), convert it, and save both the Markdown source and HTML output
- Handle errors: invalid Markdown syntax (graceful degradation), missing linked files, and encoding issues

Create a complete C++ project for a clean Ubuntu 22.04 machine with only G++ 12+ and CMake 3.22+ installed. Include:
- Source code
- CMakeLists.txt with all dependencies (direct and transitive) pinned to exact versions
- README.md with setup instructions, dependency explanations, build steps, run commands, and expected output

04 / LABELS

Labels from the report text only; not yet run

No supported category has been assigned.

Label rules and the text that matched
[]

05 / FILES

The project as the agent wrote it

3 files, exactly as written, before any repair.

CMakeLists.txt
cmake_minimum_required(VERSION 3.22)
project(md_converter VERSION 1.0.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# ---------------------------------------------------------------------------
# Dependencies
# ---------------------------------------------------------------------------
# cmark-gfm v0.29.0.gfm.13 — GitHub Flavored Markdown parser
# nlohmann/json v3.11.3 — header-only JSON library
# ---------------------------------------------------------------------------

include(FetchContent)

FetchContent_Declare(
    cmark-gfm
    GIT_REPOSITORY https://github.com/github/cmark-gfm.git
    GIT_TAG        0.29.0.gfm.13
    GIT_SHALLOW    TRUE
)

FetchContent_Declare(
    nlohmann_json
    GIT_REPOSITORY https://github.com/nlohmann/json.git
    GIT_TAG        v3.11.3
    GIT_SHALLOW    TRUE
)

set(CMARK_TESTS OFF CACHE BOOL "" FORCE)
set(CMARK_SHARED OFF CACHE BOOL "" FORCE)
set(CMARK_STATIC ON CACHE BOOL "" FORCE)

set(JSON_BuildTests   OFF CACHE BOOL "" FORCE)
set(JSON_Install      OFF CACHE BOOL "" FORCE)

FetchContent_MakeAvailable(cmark-gfm nlohmann_json)

# ---------------------------------------------------------------------------
# Executable
# ---------------------------------------------------------------------------

add_executable(md_converter converter.cpp)

target_include_directories(md_converter PRIVATE
    ${cmark-gfm_SOURCE_DIR}/src
    ${cmark-gfm_SOURCE_DIR}/extensions
    ${cmark-gfm_BINARY_DIR}/src
    ${cmark-gfm_BINARY_DIR}/extensions
)

target_link_libraries(md_converter PRIVATE
    libcmark-gfm
    libcmark-gfm-extensions
    nlohmann_json::nlohmann_json
)

if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
    target_compile_options(md_converter PRIVATE -Wall -Wextra -Wpedantic)
endif()
converter.cpp
/**
 * Markdown to HTML Converter (C++ - Trial 1)
 *
 * Converts Markdown files to HTML with GFM extensions, table of contents
 * generation, and structured JSON metadata output.
 *
 * Dependencies:
 *   - cmark-gfm (0.29.0.gfm.13) - GitHub Flavored Markdown parser
 *   - nlohmann/json (3.11.3) - JSON configuration and metadata
 */

#include <cmark-gfm.h>
#include <cmark-gfm-core-extensions.h>
#include <nlohmann/json.hpp>

#include <algorithm>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <regex>
#include <sstream>
#include <string>
#include <vector>

namespace fs = std::filesystem;
using json = nlohmann::json;

// ---------------------------------------------------------------------------
// Default CSS
// ---------------------------------------------------------------------------
static const std::string DEFAULT_CSS = R"(
body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
    line-height: 1.6;
    max-width: 900px;
    margin: 0 auto;
    padding: 2rem;
    color: #333;
    background-color: #fff;
}
h1, h2, h3, h4, h5, h6 {
    margin-top: 1.5em; margin-bottom: 0.5em;
    font-weight: 600; line-height: 1.25;
}
h1 { font-size: 2em; border-bottom: 1px solid #eaecef; padding-bottom: 0.3em; }
h2 { font-size: 1.5em; border-bottom: 1px solid #eaecef; padding-bottom: 0.3em; }
h3 { font-size: 1.25em; }
a { color: #0366d6; text-decoration: none; }
a:hover { text-decoration: underline; }
code {
    background-color: #f6f8fa; border-radius: 3px;
    padding: 0.2em 0.4em; font-size: 85%;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}
pre { background-color: #f6f8fa; border-radius: 6px; padding: 16px;
      overflow: auto; line-height: 1.45; }
pre code { background-color: transparent; padding: 0; }
blockquote { margin: 0; padding: 0 1em; color: #6a737d;
             border-left: 0.25em solid #dfe2e5; }
table { border-collapse: collapse; width: 100%; margin-bottom: 1em; }
th, td { border: 1px solid #dfe2e5; padding: 6px 13px; }
th { background-color: #f6f8fa; font-weight: 600; }
tr:nth-child(2n) { background-color: #f6f8fa; }
img { max-width: 100%; }
.toc { background-color: #f6f8fa; border: 1px solid #dfe2e5;
       border-radius: 6px; padding: 1em 1.5em; margin-bottom: 2em; }
.toc ul { list-style-type: none; padding-left: 1.5em; }
.toc > ul { padding-left: 0; }
.toc li { margin: 0.3em 0; }
hr { height: 0.25em; padding: 0; margin: 24px 0;
     background-color: #e1e4e8; border: 0; }
ul, ol { padding-left: 2em; }
li + li { margin-top: 0.25em; }
)";

// ---------------------------------------------------------------------------
// TocEntry
// ---------------------------------------------------------------------------
struct TocEntry {
    int level;
    std::string text;
    std::string id;
};

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
static std::string escape_html(const std::string& s) {
    std::string out;
    out.reserve(s.size());
    for (char c : s) {
        switch (c) {
            case '&': out += "&amp;"; break;
            case '<': out += "&lt;";  break;
            case '>': out += "&gt;";  break;
            case '"': out += "&quot;"; break;
            default:  out += c;        break;
        }
    }
    return out;
}

static std::string to_slug(const std::string& text) {
    std::string slug;
    for (char c : text) {
        if (std::isalnum(static_cast<unsigned char>(c))) {
            slug += static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
        } else if (c == ' ' || c == '\t') {
            slug += '-';
        }
    }
    return slug;
}

static std::string read_file(const std::string& path) {
    std::ifstream ifs(path, std::ios::binary);
    if (!ifs) throw std::runtime_error("Cannot open file: " + path);
    std::ostringstream ss;
    ss << ifs.rdbuf();
    return ss.str();
}

static void write_file(const std::string& path, const std::string& content) {
    auto parent = fs::path(path).parent_path();
    if (!parent.empty()) fs::create_directories(parent);
    std::ofstream ofs(path, std::ios::binary);
    if (!ofs) throw std::runtime_error("Cannot write file: " + path);
    ofs << content;
}

// ---------------------------------------------------------------------------
// Extract headings with regex for TOC
// ---------------------------------------------------------------------------
static std::vector<TocEntry> extract_headings(const std::string& markdown) {
    std::vector<TocEntry> entries;
    std::regex heading_re(R"(^(#{1,6})\s+(.+)$)");
    std::istringstream stream(markdown);
    std::string line;
    while (std::getline(stream, line)) {
        std::smatch match;
        if (std::regex_match(line, match, heading_re)) {
            int level = static_cast<int>(match[1].str().size());
            std::string text = match[2].str();
            // trim trailing whitespace
            while (!text.empty() && std::isspace(static_cast<unsigned char>(text.back())))
                text.pop_back();
            entries.push_back({level, text, to_slug(text)});
        }
    }
    return entries;
}

// ---------------------------------------------------------------------------
// Generate TOC HTML
// ---------------------------------------------------------------------------
static std::string generate_toc(const std::vector<TocEntry>& entries,
                                const std::string& toc_title) {
    if (entries.empty()) return "";

    std::ostringstream toc;
    toc << "<div class=\"toc\">\n";
    toc << "<h2>" << escape_html(toc_title) << "</h2>\n";
    toc << "<ul>\n";

    int prev_level = entries.front().level;
    for (const auto& e : entries) {
        if (e.level > prev_level) {
            for (int i = prev_level; i < e.level; ++i) toc << "<ul>\n";
        } else if (e.level < prev_level) {
            for (int i = e.level; i < prev_level; ++i) toc << "</ul>\n";
        }
        toc << "<li><a href=\"#" << e.id << "\">" << escape_html(e.text)
            << "</a></li>\n";
        prev_level = e.level;
    }

    int start_level = entries.front().level;
    for (int i = start_level; i < prev_level; ++i) toc << "</ul>\n";

    toc << "</ul>\n</div>\n";
    return toc.str();
}

// ---------------------------------------------------------------------------
// Extract first heading as title
// ---------------------------------------------------------------------------
static std::string extract_title(const std::string& markdown) {
    std::regex title_re(R"(^#{1,6}\s+(.+)$)");
    std::istringstream stream(markdown);
    std::string line;
    while (std::getline(stream, line)) {
        std::smatch match;
        if (std::regex_match(line, match, title_re)) {
            std::string t = match[1].str();
            while (!t.empty() && std::isspace(static_cast<unsigned char>(t.back())))
                t.pop_back();
            return t;
        }
    }
    return "Converted Document";
}

// ---------------------------------------------------------------------------
// MarkdownToHtmlConverter
// ---------------------------------------------------------------------------
class MarkdownToHtmlConverter {
public:
    struct Config {
        bool enable_toc = true;
        std::string toc_title = "Table of Contents";
        std::string custom_css_path;
        int cmark_options = CMARK_OPT_DEFAULT | CMARK_OPT_UNSAFE;
    };

    explicit MarkdownToHtmlConverter(Config cfg = {}) : config_(std::move(cfg)) {
        cmark_gfm_core_extensions_ensure_registered();
        if (!config_.custom_css_path.empty()) {
            try {
                custom_css_ = read_file(config_.custom_css_path);
            } catch (const std::exception& e) {
                std::cerr << "Warning: Could not load custom CSS: " << e.what() << "\n";
            }
        }
    }

    std::string convert(const std::string& markdown) const {
        // Parse with cmark-gfm
        cmark_parser* parser = cmark_parser_new(config_.cmark_options);

        // Attach GFM extensions
        const char* ext_names[] = {"table", "strikethrough", "autolink",
                                   "tagfilter", "tasklist"};
        for (const char* name : ext_names) {
            cmark_syntax_extension* ext = cmark_find_syntax_extension(name);
            if (ext) cmark_parser_attach_syntax_extension(parser, ext);
        }

        cmark_parser_feed(parser, markdown.c_str(), markdown.size());
        cmark_node* doc = cmark_parser_finish(parser);

        char* html_raw = cmark_render_html(doc, config_.cmark_options,
                                            cmark_parser_get_syntax_extensions(parser));
        std::string html_body(html_raw);
        free(html_raw);
        cmark_node_free(doc);
        cmark_parser_free(parser);

        // Build TOC
        std::string toc_html;
        if (config_.enable_toc) {
            auto headings = extract_headings(markdown);
            toc_html = generate_toc(headings, config_.toc_title);
        }

        // CSS
        const std::string& css = custom_css_.empty() ? DEFAULT_CSS : custom_css_;
        std::string title = extract_title(markdown);

        // Assemble full document
        std::ostringstream out;
        out << "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n"
            << "    <meta charset=\"UTF-8\">\n"
            << "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n"
            << "    <title>" << escape_html(title) << "</title>\n"
            << "    <style>\n" << css << "\n    </style>\n"
            << "</head>\n<body>\n"
            << toc_html << html_body
            << "\n</body>\n</html>";
        return out.str();
    }

    std::string convert_file(const std::string& input_path,
                             const std::string& output_path_arg = "") const {
        std::string md = read_file(input_path);
        std::string html = convert(md);

        std::string output_path = output_path_arg;
        if (output_path.empty()) {
            fs::path p(input_path);
            p.replace_extension(".html");
            output_path = p.string();
        }

        write_file(output_path, html);
        return output_path;
    }

    /** Get converter metadata as JSON. */
    std::string get_metadata() const {
        json meta;
        meta["name"] = "MdConverter";
        meta["version"] = "1.0.0";
        meta["tocEnabled"] = config_.enable_toc;
        meta["tocTitle"] = config_.toc_title;
        meta["backend"] = "cmark-gfm";
        return meta.dump(2);
    }

    static Config load_config(const std::string& path) {
        std::string content = read_file(path);
        json j = json::parse(content);
        Config cfg;
        if (j.contains("enableToc"))     cfg.enable_toc = j["enableToc"].get<bool>();
        if (j.contains("tocTitle"))      cfg.toc_title  = j["tocTitle"].get<std::string>();
        if (j.contains("customCssPath")) cfg.custom_css_path = j["customCssPath"].get<std::string>();
        return cfg;
    }

    static void generate_default_config(const std::string& path) {
        json cfg;
        cfg["enableToc"] = true;
        cfg["tocTitle"] = "Table of Contents";
        cfg["customCssPath"] = "";
        write_file(path, cfg.dump(2));
        std::cout << "Default configuration written to: " << path << "\n";
    }

private:
    Config config_;
    std::string custom_css_;
};

// ---------------------------------------------------------------------------
// CLI
// ---------------------------------------------------------------------------
static void print_usage() {
    std::cout << "Usage: md_converter [options] <input.md>\n\n"
              << "Options:\n"
              << "  -o, --output <file>    Output HTML file path\n"
              << "  -c, --config <file>    Path to JSON configuration file\n"
              << "  --generate-config      Generate a default config file\n"
              << "  --no-toc               Disable table of contents\n"
              << "  --stdout               Print HTML to stdout\n"
              << "  -h, --help             Show this help message\n";
}

int main(int argc, char* argv[]) {
    std::string input_file;
    std::string output_file;
    std::string config_file;
    bool gen_config  = false;
    bool to_stdout   = false;
    bool no_toc      = false;

    for (int i = 1; i < argc; ++i) {
        std::string arg = argv[i];
        if (arg == "-o" || arg == "--output") {
            if (++i < argc) output_file = argv[i];
        } else if (arg == "-c" || arg == "--config") {
            if (++i < argc) config_file = argv[i];
        } else if (arg == "--generate-config") {
            gen_config = true;
        } else if (arg == "--no-toc") {
            no_toc = true;
        } else if (arg == "--stdout") {
            to_stdout = true;
        } else if (arg == "-h" || arg == "--help") {
            print_usage();
            return 0;
        } else if (arg[0] != '-') {
            input_file = arg;
        }
    }

    try {
        if (gen_config) {
            std::string path = config_file.empty() ? "md-converter-config.json" : config_file;
            MarkdownToHtmlConverter::generate_default_config(path);
            return 0;
        }

        if (input_file.empty()) {
            std::cerr << "Error: No input file specified.\n";
            print_usage();
            return 1;
        }

        MarkdownToHtmlConverter::Config cfg;
        if (!config_file.empty()) {
            cfg = MarkdownToHtmlConverter::load_config(config_file);
        }
        if (no_toc) cfg.enable_toc = false;

        MarkdownToHtmlConverter converter(cfg);

        if (to_stdout) {
            std::string md = read_file(input_file);
            std::cout << converter.convert(md) << "\n";
        } else {
            std::string out = converter.convert_file(input_file, output_file);
            std::cout << "HTML written to: " << out << "\n";
        }
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << "\n";
        return 1;
    }
    return 0;
}
README.md
# Markdown to HTML Converter (C++ - Trial 1)

A C++ Markdown to HTML converter using GitHub Flavored Markdown via cmark-gfm, with TOC generation, custom CSS support, and JSON-based configuration.

## Dependencies

- **cmark-gfm** (0.29.0.gfm.13) - GitHub Flavored Markdown parser with extensions (tables, strikethrough, autolinks, task lists)
- **nlohmann/json** (3.11.3) - Header-only JSON library for configuration loading and metadata output

## Build

```bash
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel
```

## Usage

```bash
# Basic conversion
./build/md_converter input.md

# Specify output file
./build/md_converter input.md -o output.html

# Use configuration file
./build/md_converter input.md -c config.json

# Disable table of contents
./build/md_converter input.md --no-toc

# Print to stdout
./build/md_converter input.md --stdout

# Generate default configuration
./build/md_converter --generate-config
```

## Features

- GitHub Flavored Markdown: tables, strikethrough, autolinks, task lists, tag filtering
- Automatic table of contents generation
- JSON-based configuration via nlohmann/json
- Custom CSS support
- Complete HTML document output with proper metadata