diff --git a/.factory/prompts/docs-automation/phase2-explore.md b/.factory/prompts/docs-automation/phase2-explore.md deleted file mode 100644 index e8f0b1861912f9665d70e42dd02e1bb8a398b01e..0000000000000000000000000000000000000000 --- a/.factory/prompts/docs-automation/phase2-explore.md +++ /dev/null @@ -1,55 +0,0 @@ -# Phase 2: Explore Repository - -You are analyzing a codebase to understand its structure before reviewing documentation impact. - -## Objective -Produce a structured overview of the repository to inform subsequent documentation analysis. - -## Instructions - -1. **Identify Primary Languages and Frameworks** - - Scan for Cargo.toml, package.json, or other manifest files - - Note the primary language(s) and key dependencies - -2. **Map Documentation Structure** - - This project uses **mdBook** (https://rust-lang.github.io/mdBook/) - - Documentation is in `docs/src/` - - Table of contents: `docs/src/SUMMARY.md` (mdBook format: https://rust-lang.github.io/mdBook/format/summary.html) - - Style guide: `docs/.rules` - - Agent guidelines: `docs/AGENTS.md` - - Formatting: Prettier (config in `docs/.prettierrc`) - -3. **Identify Build and Tooling** - - Note build systems (cargo, npm, etc.) - - Identify documentation tooling (mdbook, etc.) - -4. **Output Format** -Produce a JSON summary: - -```json -{ - "primary_language": "Rust", - "frameworks": ["GPUI"], - "documentation": { - "system": "mdBook", - "location": "docs/src/", - "toc_file": "docs/src/SUMMARY.md", - "toc_format": "https://rust-lang.github.io/mdBook/format/summary.html", - "style_guide": "docs/.rules", - "agent_guidelines": "docs/AGENTS.md", - "formatter": "prettier", - "formatter_config": "docs/.prettierrc", - "custom_preprocessor": "docs_preprocessor (handles {#kb action::Name} syntax)" - }, - "key_directories": { - "source": "crates/", - "docs": "docs/src/", - "extensions": "extensions/" - } -} -``` - -## Constraints -- Read-only: Do not modify any files -- Focus on structure, not content details -- Complete within 2 minutes diff --git a/.github/workflows/docs_automation.yml b/.github/workflows/docs_automation.yml index 46dcfa56616c24a78f61e075d3e1a7909655b8aa..319f993cfc3f872623f8308f597976bc26de7702 100644 --- a/.github/workflows/docs_automation.yml +++ b/.github/workflows/docs_automation.yml @@ -83,19 +83,6 @@ jobs: env: GH_TOKEN: ${{ github.token }} - # Phase 0: Guardrails are loaded via AGENTS.md in each phase - - # Phase 2: Explore Repository (Read-Only - default) - - name: "Phase 2: Explore Repository" - id: phase2 - run: | - "$DROID_BIN" exec \ - -m "$DROID_MODEL" \ - -f .factory/prompts/docs-automation/phase2-explore.md \ - > /tmp/phase2-output.txt 2>&1 || true - echo "Repository exploration complete" - cat /tmp/phase2-output.txt - # Phase 3: Analyze Changes (Read-Only - default) - name: "Phase 3: Analyze Changes" id: phase3 @@ -103,19 +90,6 @@ jobs: CHANGED_FILES=$(tr '\n' ' ' < /tmp/changed_files.txt) echo "Analyzing changes in: $CHANGED_FILES" - # Build prompt with context - cat > /tmp/phase3-prompt.md << 'EOF' - $(cat .factory/prompts/docs-automation/phase3-analyze.md) - - ## Context - - ### Changed Files - $CHANGED_FILES - - ### Phase 2 Output - $(cat /tmp/phase2-output.txt) - EOF - "$DROID_BIN" exec \ -m "$DROID_MODEL" \ "$(cat .factory/prompts/docs-automation/phase3-analyze.md) @@ -129,9 +103,20 @@ jobs: - name: "Phase 4: Plan Documentation Impact" id: phase4 run: | + CHANGED_FILES=$(tr '\n' ' ' < /tmp/changed_files.txt) + PHASE3_OUTPUT=$(cat /tmp/phase3-output.md) + "$DROID_BIN" exec \ -m "$DROID_MODEL" \ - -f .factory/prompts/docs-automation/phase4-plan.md \ + "$(cat .factory/prompts/docs-automation/phase4-plan.md) + + ## Context from Phase 3 + + ### Changed Files + $CHANGED_FILES + + ### Phase 3 Analysis + $PHASE3_OUTPUT" \ > /tmp/phase4-plan.md 2>&1 || true echo "Documentation plan complete" cat /tmp/phase4-plan.md @@ -148,10 +133,15 @@ jobs: id: phase5 if: steps.phase4.outputs.updates_required == 'true' run: | + PHASE4_PLAN=$(cat /tmp/phase4-plan.md) + "$DROID_BIN" exec \ -m "$DROID_MODEL" \ --auto medium \ - -f .factory/prompts/docs-automation/phase5-apply.md \ + "$(cat .factory/prompts/docs-automation/phase5-apply.md) + + ## Documentation Plan from Phase 4 + $PHASE4_PLAN" \ > /tmp/phase5-report.md 2>&1 || true echo "Documentation updates applied" cat /tmp/phase5-report.md @@ -176,10 +166,23 @@ jobs: run: | # Get git diff of docs git diff docs/src/ > /tmp/docs-diff.txt || true + + PHASE5_REPORT=$(cat /tmp/phase5-report.md) + DOCS_DIFF=$(cat /tmp/docs-diff.txt) "$DROID_BIN" exec \ -m "$DROID_MODEL" \ - -f .factory/prompts/docs-automation/phase6-summarize.md \ + "$(cat .factory/prompts/docs-automation/phase6-summarize.md) + + ## Context + + ### Phase 5 Report + $PHASE5_REPORT + + ### Documentation Diff + \`\`\`diff + $DOCS_DIFF + \`\`\`" \ > /tmp/phase6-summary.md 2>&1 || true echo "Summary generated" cat /tmp/phase6-summary.md @@ -202,6 +205,21 @@ jobs: # Daily batch branch - one branch per day, multiple commits accumulate BRANCH_NAME="docs/auto-update-$(date +%Y-%m-%d)" + # Get source PR info for attribution + SOURCE_PR_INFO="" + if [ "${{ steps.changed.outputs.source }}" == "pr" ]; then + PR_NUM="${{ steps.changed.outputs.ref }}" + PR_DETAILS=$(gh pr view "$PR_NUM" --json title,author,url 2>/dev/null || echo "{}") + SOURCE_TITLE=$(echo "$PR_DETAILS" | jq -r '.title // "Unknown"') + SOURCE_AUTHOR=$(echo "$PR_DETAILS" | jq -r '.author.login // "Unknown"') + SOURCE_URL=$(echo "$PR_DETAILS" | jq -r '.url // ""') + SOURCE_PR_INFO=" + --- + **Source**: [#$PR_NUM]($SOURCE_URL) - $SOURCE_TITLE + **Author**: @$SOURCE_AUTHOR + " + fi + # Stash local changes from phase 5 git stash push -m "docs-automation-changes" -- docs/src/ @@ -232,16 +250,37 @@ jobs: # Push git push -u origin "$BRANCH_NAME" - # Check if PR already exists for this branch - EXISTING_PR=$(gh pr list --head "$BRANCH_NAME" --json number --jq '.[0].number' || echo "") + # Build the PR body section for this update + PR_BODY_SECTION="## Update from $(date '+%Y-%m-%d %H:%M') + $SOURCE_PR_INFO + $(cat /tmp/phase6-summary.md) + " - if [ -n "$EXISTING_PR" ]; then - echo "PR #$EXISTING_PR already exists for branch $BRANCH_NAME, updated with new commit" + # Check if PR already exists for this branch + EXISTING_PR=$(gh pr list --head "$BRANCH_NAME" --json number,url,body --jq '.[0]' || echo "") + + if [ -n "$EXISTING_PR" ] && [ "$EXISTING_PR" != "null" ]; then + PR_NUM=$(echo "$EXISTING_PR" | jq -r '.number') + PR_URL=$(echo "$EXISTING_PR" | jq -r '.url') + EXISTING_BODY=$(echo "$EXISTING_PR" | jq -r '.body // ""') + + # Append new summary to existing PR body + NEW_BODY="${EXISTING_BODY} + + --- + + ${PR_BODY_SECTION}" + + echo "$NEW_BODY" > /tmp/updated-pr-body.md + gh pr edit "$PR_NUM" --body-file /tmp/updated-pr-body.md + + echo "PR #$PR_NUM updated: $PR_URL" else # Create new PR + echo "$PR_BODY_SECTION" > /tmp/new-pr-body.md gh pr create \ --title "docs: automated documentation update ($(date +%Y-%m-%d))" \ - --body-file /tmp/phase6-summary.md \ + --body-file /tmp/new-pr-body.md \ --base main || true echo "PR created on branch: $BRANCH_NAME" fi diff --git a/docs/AGENTS.md b/docs/AGENTS.md index fdd61ff6aeaf8cd09ae0b017c5199e7033fba964..e1743eb9745288fec54c252c54d5795a6d808317 100644 --- a/docs/AGENTS.md +++ b/docs/AGENTS.md @@ -2,6 +2,10 @@ This file governs automated documentation updates triggered by code changes. All automation phases must comply with these rules. +## Repository Context + +This is the **Zed code editor** repository, a Rust-based application using the custom **GPUI** UI framework. The project is a large monorepo with ~200 crates organized under `crates/`. Documentation is built with **mdBook** and uses a custom preprocessor (`docs_preprocessor`) that handles special syntax like `{#kb action::Name}` for keybindings. The documentation source is in `docs/src/` with a table of contents in `SUMMARY.md`, and all docs must pass Prettier formatting (80 char line width). The style guide (`docs/.rules`) and agent guidelines (`docs/AGENTS.md`) provide specific conventions for documentation writing. + ## Documentation System This documentation uses **mdBook** (https://rust-lang.github.io/mdBook/). diff --git a/script/test-docs-automation b/script/test-docs-automation new file mode 100755 index 0000000000000000000000000000000000000000..b0701378f5eb8ed68a7b8e5183a8c80d89b4c121 --- /dev/null +++ b/script/test-docs-automation @@ -0,0 +1,588 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +PROMPTS_DIR="$REPO_ROOT/.factory/prompts/docs-automation" +OUTPUT_DIR="${TMPDIR:-/tmp}/docs-automation-test" + +# Default values +BASE_BRANCH="main" +DROID_MODEL="${DROID_MODEL:-claude-opus-4-5-20251101}" +DRY_RUN=false +VERBOSE=false +PR_NUMBER="" +SOURCE_BRANCH="" + +usage() { + cat << EOF +Usage: $(basename "$0") [OPTIONS] + +Test the documentation automation workflow locally. + +OPTIONS: + -p, --pr NUMBER PR number to analyze (uses gh pr diff) + -r, --branch BRANCH Remote branch to compare (e.g., origin/feature-branch) + -b, --base BRANCH Base branch to compare against (default: main) + -m, --model MODEL Droid model to use (default: $DROID_MODEL) + -d, --dry-run Run phases 2-4 only (no file modifications) + -s, --skip-apply Alias for --dry-run + -v, --verbose Show full output from each phase + -o, --output DIR Output directory for phase artifacts (default: $OUTPUT_DIR) + -h, --help Show this help message + +EXAMPLES: + # Analyze a PR (most common use case) + $(basename "$0") --pr 12345 + + # Analyze a PR with dry run (no file changes) + $(basename "$0") --pr 12345 --dry-run + + # Analyze a remote branch against main + $(basename "$0") --branch origin/feature-branch + + # Test current branch against main + $(basename "$0") + + # Use a different model + $(basename "$0") --pr 12345 --model claude-sonnet-4-20250514 + +ENVIRONMENT: + FACTORY_API_KEY Required: Your Factory API key + DROID_MODEL Override default model + GH_TOKEN Required for --pr option (or gh auth login) + +EOF + exit 0 +} + +while [[ $# -gt 0 ]]; do + case $1 in + -p|--pr) + PR_NUMBER="$2" + shift 2 + ;; + -r|--branch) + SOURCE_BRANCH="$2" + shift 2 + ;; + -b|--base) + BASE_BRANCH="$2" + shift 2 + ;; + -m|--model) + DROID_MODEL="$2" + shift 2 + ;; + -d|--dry-run|-s|--skip-apply) + DRY_RUN=true + shift + ;; + -v|--verbose) + VERBOSE=true + shift + ;; + -o|--output) + OUTPUT_DIR="$2" + shift 2 + ;; + -h|--help) + usage + ;; + *) + echo "Unknown option: $1" + usage + ;; + esac +done + +# Cleanup function for restoring original branch +cleanup_on_exit() { + if [[ -f "$OUTPUT_DIR/original-branch.txt" ]]; then + ORIGINAL_BRANCH=$(cat "$OUTPUT_DIR/original-branch.txt") + CURRENT=$(git -C "$REPO_ROOT" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "") + if [[ "$CURRENT" != "$ORIGINAL_BRANCH" && -n "$ORIGINAL_BRANCH" ]]; then + echo "" + echo "Restoring original branch: $ORIGINAL_BRANCH" + git -C "$REPO_ROOT" checkout "$ORIGINAL_BRANCH" 2>/dev/null || true + if [[ "$CURRENT" == temp-analysis-* ]]; then + git -C "$REPO_ROOT" branch -D "$CURRENT" 2>/dev/null || true + fi + fi + fi +} +trap cleanup_on_exit EXIT + +# Check for required tools +if ! command -v droid &> /dev/null; then + echo "Error: droid CLI not found. Install from https://app.factory.ai/cli" + exit 1 +fi + +if [[ -z "${FACTORY_API_KEY:-}" ]]; then + echo "Error: FACTORY_API_KEY environment variable is not set" + exit 1 +fi + +# Check gh CLI if PR mode +if [[ -n "$PR_NUMBER" ]]; then + if ! command -v gh &> /dev/null; then + echo "Error: gh CLI not found. Install from https://cli.github.com/" + echo "Required for --pr option" + exit 1 + fi +fi + +# Create output directory +mkdir -p "$OUTPUT_DIR" +echo "Output directory: $OUTPUT_DIR" +echo "Model: $DROID_MODEL" +echo "" + +cd "$REPO_ROOT" + +# Copy prompts to output directory BEFORE any branch checkout +# This ensures we have access to prompts even if PR branch doesn't have them +if [[ -d "$PROMPTS_DIR" ]]; then + cp -r "$PROMPTS_DIR" "$OUTPUT_DIR/prompts" + PROMPTS_DIR="$OUTPUT_DIR/prompts" + echo "Prompts copied to: $PROMPTS_DIR" +else + echo "Error: Prompts directory not found: $PROMPTS_DIR" + exit 1 +fi +echo "" + +# Get changed files based on mode +echo "=== Getting changed files ===" + +if [[ -n "$PR_NUMBER" ]]; then + # PR mode: use gh pr diff like the workflow does + echo "Analyzing PR #$PR_NUMBER" + + # Get PR info for context + echo "Fetching PR details..." + gh pr view "$PR_NUMBER" --json title,headRefName,baseRefName,state > "$OUTPUT_DIR/pr-info.json" 2>/dev/null || true + if [[ -f "$OUTPUT_DIR/pr-info.json" ]]; then + PR_TITLE=$(jq -r '.title // "Unknown"' "$OUTPUT_DIR/pr-info.json") + PR_HEAD=$(jq -r '.headRefName // "Unknown"' "$OUTPUT_DIR/pr-info.json") + PR_BASE=$(jq -r '.baseRefName // "Unknown"' "$OUTPUT_DIR/pr-info.json") + PR_STATE=$(jq -r '.state // "Unknown"' "$OUTPUT_DIR/pr-info.json") + echo " Title: $PR_TITLE" + echo " Branch: $PR_HEAD -> $PR_BASE" + echo " State: $PR_STATE" + fi + echo "" + + # Get the list of changed files + gh pr diff "$PR_NUMBER" --name-only > "$OUTPUT_DIR/changed_files.txt" + + # Also save the full diff for analysis + gh pr diff "$PR_NUMBER" > "$OUTPUT_DIR/pr-diff.patch" 2>/dev/null || true + + # Checkout the PR branch to have the code available for analysis + echo "Checking out PR branch for analysis..." + ORIGINAL_BRANCH=$(git rev-parse --abbrev-ref HEAD) + echo "$ORIGINAL_BRANCH" > "$OUTPUT_DIR/original-branch.txt" + + gh pr checkout "$PR_NUMBER" --force 2>/dev/null || { + echo "Warning: Could not checkout PR branch. Analysis will use current branch state." + } + +elif [[ -n "$SOURCE_BRANCH" ]]; then + # Remote branch mode + echo "Analyzing branch: $SOURCE_BRANCH" + echo "Base branch: $BASE_BRANCH" + + # Fetch the branches + git fetch origin 2>/dev/null || true + + # Resolve branch refs + SOURCE_REF="$SOURCE_BRANCH" + BASE_REF="origin/$BASE_BRANCH" + + # Get merge base + MERGE_BASE=$(git merge-base "$BASE_REF" "$SOURCE_REF" 2>/dev/null) || { + echo "Error: Could not find merge base between $BASE_REF and $SOURCE_REF" + exit 1 + } + echo "Merge base: $MERGE_BASE" + + # Get changed files + git diff --name-only "$MERGE_BASE" "$SOURCE_REF" > "$OUTPUT_DIR/changed_files.txt" + + # Checkout the source branch for analysis + echo "Checking out $SOURCE_BRANCH for analysis..." + ORIGINAL_BRANCH=$(git rev-parse --abbrev-ref HEAD) + echo "$ORIGINAL_BRANCH" > "$OUTPUT_DIR/original-branch.txt" + + git checkout "$SOURCE_BRANCH" 2>/dev/null || git checkout -b "temp-analysis-$$" "$SOURCE_REF" || { + echo "Warning: Could not checkout branch. Analysis will use current branch state." + } + +else + # Current branch mode (original behavior) + CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) + echo "Analyzing current branch: $CURRENT_BRANCH" + echo "Base branch: $BASE_BRANCH" + + # Fetch the base branch + git fetch origin "$BASE_BRANCH" 2>/dev/null || true + + # Get merge base + MERGE_BASE=$(git merge-base "origin/$BASE_BRANCH" HEAD 2>/dev/null || git merge-base "$BASE_BRANCH" HEAD) + echo "Merge base: $MERGE_BASE" + + git diff --name-only "$MERGE_BASE" HEAD > "$OUTPUT_DIR/changed_files.txt" +fi + +if [[ ! -s "$OUTPUT_DIR/changed_files.txt" ]]; then + echo "No changed files found." + exit 0 +fi + +echo "" +echo "Changed files ($(wc -l < "$OUTPUT_DIR/changed_files.txt" | tr -d ' ') files):" +cat "$OUTPUT_DIR/changed_files.txt" +echo "" + +# Phase 3: Analyze Changes +echo "=== Phase 3: Analyze Changes ===" +CHANGED_FILES=$(tr '\n' ' ' < "$OUTPUT_DIR/changed_files.txt") + +droid exec \ + -m "$DROID_MODEL" \ + --auto low \ + "$(cat "$PROMPTS_DIR/phase3-analyze.md") + + Changed files: $CHANGED_FILES" \ + > "$OUTPUT_DIR/phase3-output.md" 2>&1 || true + +if [[ "$VERBOSE" == "true" ]]; then + cat "$OUTPUT_DIR/phase3-output.md" +else + echo "Output saved to: $OUTPUT_DIR/phase3-output.md" +fi +echo "" + +# Phase 4: Plan Documentation Impact +echo "=== Phase 4: Plan Documentation Impact ===" +PHASE3_OUTPUT=$(cat "$OUTPUT_DIR/phase3-output.md") + +droid exec \ + -m "$DROID_MODEL" \ + --auto low \ + "$(cat "$PROMPTS_DIR/phase4-plan.md") + +## Context from Phase 3 + +### Changed Files +$CHANGED_FILES + +### Phase 3 Analysis +$PHASE3_OUTPUT" \ + > "$OUTPUT_DIR/phase4-plan.md" 2>&1 || true + +if [[ "$VERBOSE" == "true" ]]; then + cat "$OUTPUT_DIR/phase4-plan.md" +else + echo "Output saved to: $OUTPUT_DIR/phase4-plan.md" +fi +echo "" + +# Check if updates are required +if grep -q "NO_UPDATES_REQUIRED" "$OUTPUT_DIR/phase4-plan.md" || \ + grep -qi "Documentation Updates Required: No" "$OUTPUT_DIR/phase4-plan.md"; then + echo "=== No documentation updates required ===" + echo "Phase 4 determined no documentation changes are needed." + exit 0 +fi + +if [[ "$DRY_RUN" == "true" ]]; then + echo "=== Phase 5 (Preview): Generate Proposed Changes ===" + PHASE4_PLAN=$(cat "$OUTPUT_DIR/phase4-plan.md") + + droid exec \ + -m "$DROID_MODEL" \ + --auto low \ + "CRITICAL INSTRUCTION: You MUST output the ACTUAL markdown content, not a summary. + +Your task: Generate a preview showing EXACTLY what documentation changes would be made. + +REQUIRED STEPS: +1. Read the file docs/src/ai/edit-prediction.md using the Read tool +2. Find the Codestral section (### Codestral {#codestral}) +3. Output the EXACT current text and your EXACT proposed replacement + +YOUR OUTPUT MUST FOLLOW THIS EXACT FORMAT (no deviations, no summaries): + +--- +## File: docs/src/ai/edit-prediction.md + +### CURRENT CONTENT (copy exactly from file): +\`\`\`markdown +### Codestral {#codestral} + +[PASTE THE EXACT CURRENT CONTENT OF THIS SECTION HERE - EVERY LINE] +\`\`\` + +### PROPOSED CONTENT (your changes): +\`\`\`markdown +### Codestral {#codestral} + +[WRITE YOUR COMPLETE REPLACEMENT FOR THIS SECTION HERE - EVERY LINE] +\`\`\` + +### UNIFIED DIFF: +\`\`\`diff +[Generate a unified diff showing - lines removed and + lines added] +\`\`\` + +### Why this change: +[One sentence explanation] +--- + +DO NOT: +- Summarize the changes +- Skip reading the actual file +- Provide abbreviated content +- Say 'the section that...' - show the ACTUAL text + +Context for what changed in the codebase: +$PHASE3_OUTPUT + +Documentation plan: +$PHASE4_PLAN" \ + > "$OUTPUT_DIR/phase5-preview.md" 2>&1 || true + + echo "Preview saved to: $OUTPUT_DIR/phase5-preview.md" + echo "" + echo "=== Preview Content ===" + cat "$OUTPUT_DIR/phase5-preview.md" + + echo "" + echo "=== Dry run complete ===" + echo "To apply changes for real, run without --dry-run flag." + echo "" + echo "All outputs saved to: $OUTPUT_DIR/" + exit 0 +fi + +# Phase 5: Apply Documentation Plan +echo "=== Phase 5: Apply Documentation Plan ===" +PHASE4_PLAN=$(cat "$OUTPUT_DIR/phase4-plan.md") + +droid exec \ + -m "$DROID_MODEL" \ + --auto medium \ + "$(cat "$PROMPTS_DIR/phase5-apply.md") + +## Documentation Plan from Phase 4 +$PHASE4_PLAN" \ + > "$OUTPUT_DIR/phase5-report.md" 2>&1 || true + +if [[ "$VERBOSE" == "true" ]]; then + cat "$OUTPUT_DIR/phase5-report.md" +else + echo "Output saved to: $OUTPUT_DIR/phase5-report.md" +fi +echo "" + +# Phase 5b: Format with Prettier (only changed files) +echo "=== Phase 5b: Format with Prettier ===" +cd "$REPO_ROOT" + +# Get list of changed doc files (relative to docs/ directory) +CHANGED_DOCS=$(git diff --name-only docs/src/ 2>/dev/null | sed 's|^docs/||' | tr '\n' ' ') + +if [[ -n "$CHANGED_DOCS" ]]; then + echo "Formatting changed files: $CHANGED_DOCS" + # Use pnpm dlx like the project's prettier script does + if command -v pnpm &> /dev/null; then + (cd docs && pnpm dlx prettier@3.5.0 $CHANGED_DOCS --write) 2>/dev/null || true + elif command -v prettier &> /dev/null; then + (cd docs && prettier --write $CHANGED_DOCS) 2>/dev/null || true + else + echo "Warning: neither pnpm nor prettier found, skipping formatting" + fi + echo "Prettier formatting applied" +else + echo "No changed docs files to format" +fi +echo "" + +# Phase 6: Summarize Changes +echo "=== Phase 6: Summarize Changes ===" +git -C "$REPO_ROOT" diff docs/src/ > "$OUTPUT_DIR/docs-diff.txt" 2>/dev/null || true + +PHASE5_REPORT=$(cat "$OUTPUT_DIR/phase5-report.md") +DOCS_DIFF=$(cat "$OUTPUT_DIR/docs-diff.txt") + +droid exec \ + -m "$DROID_MODEL" \ + --auto low \ + "$(cat "$PROMPTS_DIR/phase6-summarize.md") + +## Context + +### Phase 5 Report +$PHASE5_REPORT + +### Documentation Diff +\`\`\`diff +$DOCS_DIFF +\`\`\`" \ + > "$OUTPUT_DIR/phase6-summary.md" 2>&1 || true + +if [[ "$VERBOSE" == "true" ]]; then + cat "$OUTPUT_DIR/phase6-summary.md" +else + echo "Output saved to: $OUTPUT_DIR/phase6-summary.md" +fi +echo "" + +# Phase 7: Create Branch and PR +echo "=== Phase 7: Create Branch and PR ===" + +# Check if there are actual changes +if git -C "$REPO_ROOT" diff --quiet docs/src/; then + echo "No documentation changes detected after Phase 5" + echo "" + echo "=== Test Complete (no changes to commit) ===" + exit 0 +fi + +# Check if gh CLI is available +if ! command -v gh &> /dev/null; then + echo "Warning: gh CLI not found. Skipping PR creation." + echo "Install from https://cli.github.com/ to enable automatic PR creation." + echo "" + echo "Documentation changes (git status):" + git -C "$REPO_ROOT" status --short docs/src/ + echo "" + echo "To review the diff:" + echo " git diff docs/src/" + echo "" + echo "To discard changes:" + echo " git checkout docs/src/" + exit 0 +fi + +cd "$REPO_ROOT" + +# Daily batch branch - one branch per day, multiple commits accumulate +BRANCH_NAME="docs/auto-update-$(date +%Y-%m-%d)" + +# Stash local changes from phase 5 +echo "Stashing documentation changes..." +git stash push -m "docs-automation-changes" -- docs/src/ + +# Check if branch already exists on remote +if git ls-remote --exit-code --heads origin "$BRANCH_NAME" > /dev/null 2>&1; then + echo "Branch $BRANCH_NAME exists, checking out and updating..." + git fetch origin "$BRANCH_NAME" + git checkout -B "$BRANCH_NAME" "origin/$BRANCH_NAME" +else + echo "Creating new branch $BRANCH_NAME from main..." + git fetch origin main + git checkout -B "$BRANCH_NAME" origin/main +fi + +# Apply stashed changes +echo "Applying documentation changes..." +git stash pop || true + +# Stage and commit +git add docs/src/ + +# Get source PR info for attribution +SOURCE_PR_INFO="" +TRIGGER_INFO="" +if [[ -n "$PR_NUMBER" ]]; then + # Fetch PR details: title, author, url + PR_DETAILS=$(gh pr view "$PR_NUMBER" --json title,author,url 2>/dev/null || echo "{}") + SOURCE_TITLE=$(echo "$PR_DETAILS" | jq -r '.title // "Unknown"') + SOURCE_AUTHOR=$(echo "$PR_DETAILS" | jq -r '.author.login // "Unknown"') + SOURCE_URL=$(echo "$PR_DETAILS" | jq -r '.url // ""') + + TRIGGER_INFO="Triggered by: PR #$PR_NUMBER" + SOURCE_PR_INFO=" +--- +**Source**: [#$PR_NUMBER]($SOURCE_URL) - $SOURCE_TITLE +**Author**: @$SOURCE_AUTHOR +" +elif [[ -n "$SOURCE_BRANCH" ]]; then + TRIGGER_INFO="Triggered by: branch $SOURCE_BRANCH" + SOURCE_PR_INFO=" +--- +**Source**: Branch \`$SOURCE_BRANCH\` +" +fi + +# Build commit message +SUMMARY=$(head -50 < "$OUTPUT_DIR/phase6-summary.md" 2>/dev/null || echo "Automated documentation update") + +git commit -m "docs: auto-update documentation + +${SUMMARY} + +${TRIGGER_INFO} + +Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>" || { + echo "Nothing to commit" + exit 0 +} + +# Push +echo "Pushing to origin/$BRANCH_NAME..." +git push -u origin "$BRANCH_NAME" + +# Build the PR body section for this update +PR_BODY_SECTION="## Update from $(date '+%Y-%m-%d %H:%M') +$SOURCE_PR_INFO +$(cat "$OUTPUT_DIR/phase6-summary.md") +" + +# Check if PR already exists for this branch +EXISTING_PR=$(gh pr list --head "$BRANCH_NAME" --json number,url,body --jq '.[0]' 2>/dev/null || echo "") + +if [[ -n "$EXISTING_PR" && "$EXISTING_PR" != "null" ]]; then + PR_NUM=$(echo "$EXISTING_PR" | jq -r '.number') + PR_URL=$(echo "$EXISTING_PR" | jq -r '.url') + EXISTING_BODY=$(echo "$EXISTING_PR" | jq -r '.body // ""') + + # Append new summary to existing PR body + echo "Updating PR body with new summary..." + NEW_BODY="${EXISTING_BODY} + +--- + +${PR_BODY_SECTION}" + + echo "$NEW_BODY" > "$OUTPUT_DIR/updated-pr-body.md" + gh pr edit "$PR_NUM" --body-file "$OUTPUT_DIR/updated-pr-body.md" + + echo "" + echo "=== Updated existing PR ===" + echo "PR #$PR_NUM: $PR_URL" + echo "New commit added and PR description updated." +else + # Create new PR with full body + echo "Creating new PR..." + echo "$PR_BODY_SECTION" > "$OUTPUT_DIR/new-pr-body.md" + + PR_URL=$(gh pr create \ + --title "docs: automated documentation update ($(date +%Y-%m-%d))" \ + --body-file "$OUTPUT_DIR/new-pr-body.md" \ + --base main 2>&1) || { + echo "Failed to create PR: $PR_URL" + exit 1 + } + echo "" + echo "=== PR Created ===" + echo "$PR_URL" +fi + +echo "" +echo "=== Test Complete ===" +echo "All phase outputs saved to: $OUTPUT_DIR/"