Detailed changes
@@ -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
@@ -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
@@ -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/).
@@ -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/"