1#!/usr/bin/env bash
2#
3# Create a draft documentation PR by auto-applying batched suggestions.
4#
5# Usage:
6# script/docs-suggest-publish [--dry-run] [--model MODEL]
7#
8# This script:
9# 1. Reads pending suggestions from the docs/suggestions-pending branch
10# 2. Uses Droid to apply all suggestions directly to docs files
11# 3. Runs docs formatting
12# 4. Creates a draft PR for human review/merge
13# 5. Optionally resets the suggestions branch after successful PR creation
14#
15# Options:
16# --dry-run Show what would be done without creating PR
17# --keep-queue Don't reset the suggestions branch after PR creation
18# --model MODEL Override Droid model used for auto-apply
19# --verbose Show detailed progress
20#
21# Run this as part of the preview release workflow.
22
23set -euo pipefail
24
25DRY_RUN=false
26KEEP_QUEUE=false
27VERBOSE=false
28MODEL="${DROID_MODEL:-claude-sonnet-4-5-20250929}"
29
30SUGGESTIONS_BRANCH="docs/suggestions-pending"
31
32# Colors
33RED='\033[0;31m'
34GREEN='\033[0;32m'
35YELLOW='\033[0;33m'
36BLUE='\033[0;34m'
37NC='\033[0m'
38
39log() {
40 if [[ "$VERBOSE" == "true" ]]; then
41 echo -e "${BLUE}[docs-publish]${NC} $*" >&2
42 fi
43}
44
45error() {
46 echo -e "${RED}Error:${NC} $*" >&2
47 exit 1
48}
49
50# Parse arguments
51while [[ $# -gt 0 ]]; do
52 case $1 in
53 --dry-run)
54 DRY_RUN=true
55 shift
56 ;;
57 --keep-queue)
58 KEEP_QUEUE=true
59 shift
60 ;;
61 --verbose)
62 VERBOSE=true
63 shift
64 ;;
65 --model)
66 MODEL="$2"
67 shift 2
68 ;;
69 -h|--help)
70 head -26 "$0" | tail -24
71 exit 0
72 ;;
73 *)
74 error "Unknown option: $1"
75 ;;
76 esac
77done
78
79# Get repo root
80REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
81cd "$REPO_ROOT"
82
83# Check if suggestions branch exists
84log "Checking for suggestions branch..."
85if ! git ls-remote --exit-code --heads origin "$SUGGESTIONS_BRANCH" > /dev/null 2>&1; then
86 echo "No pending suggestions found (branch $SUGGESTIONS_BRANCH doesn't exist)."
87 echo "Suggestions are queued automatically when PRs are merged to main."
88 exit 0
89fi
90
91# Fetch the suggestions branch
92log "Fetching suggestions branch..."
93git fetch origin "$SUGGESTIONS_BRANCH"
94
95# Check for manifest
96if ! git show "origin/$SUGGESTIONS_BRANCH:manifest.json" > /dev/null 2>&1; then
97 echo "No manifest found on suggestions branch."
98 exit 0
99fi
100
101# Read manifest
102MANIFEST=$(git show "origin/$SUGGESTIONS_BRANCH:manifest.json")
103SUGGESTION_COUNT=$(echo "$MANIFEST" | jq '.suggestions | length')
104
105if [[ "$SUGGESTION_COUNT" -eq 0 ]]; then
106 echo "No pending suggestions in queue."
107 exit 0
108fi
109
110echo "Found $SUGGESTION_COUNT pending suggestion(s):"
111echo ""
112echo "$MANIFEST" | jq -r '.suggestions[] | " PR #\(.pr): \(.title)"'
113echo ""
114
115if [[ "$DRY_RUN" == "true" ]]; then
116 echo -e "${YELLOW}=== DRY RUN ===${NC}"
117 echo ""
118 echo "Would auto-apply suggestions to docs via Droid and create a draft PR."
119 echo "Model: $MODEL"
120 echo ""
121
122 # Show each suggestion file
123 for file in $(echo "$MANIFEST" | jq -r '.suggestions[].file'); do
124 echo "--- $file ---"
125 git show "origin/$SUGGESTIONS_BRANCH:$file" 2>/dev/null || echo "(file not found)"
126 echo ""
127 done
128
129 echo -e "${YELLOW}=== END DRY RUN ===${NC}"
130 echo ""
131 echo "Run without --dry-run to create the PR."
132 exit 0
133fi
134
135# Ensure clean working state
136if [[ -n "$(git status --porcelain)" ]]; then
137 error "Working directory has uncommitted changes. Please commit or stash first."
138fi
139
140for command in git gh jq droid; do
141 if ! command -v "$command" > /dev/null 2>&1; then
142 error "Required command not found: $command"
143 fi
144done
145
146# Remember current branch
147ORIGINAL_BRANCH=$(git branch --show-current)
148log "Current branch: $ORIGINAL_BRANCH"
149
150# Create new branch for docs PR from latest main
151git fetch origin main
152DOCS_BRANCH="docs/preview-auto-$(date +%Y-%m-%d-%H%M%S)"
153log "Creating docs branch: $DOCS_BRANCH"
154
155git checkout -b "$DOCS_BRANCH" origin/main
156
157TMPDIR=$(mktemp -d)
158trap 'rm -rf "$TMPDIR"' EXIT
159
160SUGGESTIONS_FILE="$TMPDIR/suggestions.md"
161APPLY_PROMPT_FILE="$TMPDIR/apply-prompt.md"
162APPLY_SUMMARY_FILE="$TMPDIR/apply-summary.md"
163
164# Combine queued suggestion files into one input
165for file in $(echo "$MANIFEST" | jq -r '.suggestions[].file'); do
166 {
167 echo "## Source: $file"
168 echo ""
169 git show "origin/$SUGGESTIONS_BRANCH:$file" 2>/dev/null || error "Suggestion file missing: $file"
170 echo ""
171 echo "---"
172 echo ""
173 } >> "$SUGGESTIONS_FILE"
174done
175
176# Build auto-apply prompt
177cat > "$APPLY_PROMPT_FILE" << 'EOF'
178# Documentation Auto-Apply Request (Preview Release)
179
180Apply all queued documentation suggestions below directly to docs files in this repository.
181
182## Required behavior
183
1841. Apply concrete documentation edits (not suggestion text) to the appropriate files.
1852. Edit only docs content files under `docs/src/` unless a suggestion explicitly requires another docs path.
1863. For every docs file you modify, run a full-file brand voice pass (entire file, not only edited sections).
1874. Enforce the brand rubric exactly; final file content must score 4+ on every criterion:
188 - Technical Grounding
189 - Natural Syntax
190 - Quiet Confidence
191 - Developer Respect
192 - Information Priority
193 - Specificity
194 - Voice Consistency
195 - Earned Claims
1965. Keep SEO/frontmatter/linking requirements from the suggestions where applicable.
1976. Keep preview callout semantics correct:
198 - Additive features: `> **Preview:** ...`
199 - Behavior modifications: `> **Changed in Preview (vX.XXX).** ...`
2007. If a suggestion is too ambiguous to apply safely, skip it and explain why in the summary.
201
202## Output format (after making edits)
203
204Return markdown with:
205
206- `## Applied Suggestions`
207- `## Skipped Suggestions`
208- `## Files Updated`
209- `## Brand Voice Verification` (one line per updated file confirming full-file pass)
210
211Do not include a patch in the response; apply edits directly to files.
212
213## Queued Suggestions
214
215EOF
216
217cat "$SUGGESTIONS_FILE" >> "$APPLY_PROMPT_FILE"
218
219log "Running Droid auto-apply with model: $MODEL"
220droid exec -m "$MODEL" -f "$APPLY_PROMPT_FILE" > "$APPLY_SUMMARY_FILE"
221
222if [[ -n "$(git status --porcelain | grep -vE '^.. docs/' || true)" ]]; then
223 error "Auto-apply modified non-doc files. Revert and re-run."
224fi
225
226if [[ -z "$(git status --porcelain docs/ | grep '^.. docs/src/' || true)" ]]; then
227 error "Auto-apply produced no docs/src changes."
228fi
229
230log "Running docs formatter"
231./script/prettier
232
233if [[ -z "$(git status --porcelain docs/ | grep '^.. docs/src/' || true)" ]]; then
234 error "No docs/src changes remain after formatting; aborting PR creation."
235fi
236
237# Build PR body from suggestions
238PR_BODY_FILE="$TMPDIR/pr-body.md"
239cat > "$PR_BODY_FILE" << 'EOF'
240# Documentation Updates for Preview Release
241
242This draft PR auto-applies queued documentation suggestions collected from
243recently merged PRs.
244
245## How to Use This PR
246
2471. Review the applied changes file-by-file.
2482. Verify brand voice on each touched file as a full-file pass.
2493. Ensure docs use the correct callout type:
250 - Additive features: Preview callout
251 - Behavior modifications: Changed in Preview callout
2524. Merge when ready.
253
254## Auto-Apply Summary
255
256EOF
257
258cat "$APPLY_SUMMARY_FILE" >> "$PR_BODY_FILE"
259
260cat >> "$PR_BODY_FILE" << 'EOF'
261
262## Preview Callouts
263
264Use the Preview callout for new/additive features:
265
266```markdown
267> **Preview:** This feature is available in Zed Preview. It will be included in the next Stable release.
268```
269
270Use this callout for behavior modifications to existing functionality:
271
272```markdown
273> **Changed in Preview (v0.XXX).** See [release notes](/releases#0.XXX).
274```
275
276---
277
278## Pending Suggestions
279
280EOF
281
282# Append each suggestion to PR body
283for file in $(echo "$MANIFEST" | jq -r '.suggestions[].file'); do
284 log "Adding $file to PR body..."
285 echo "" >> "$PR_BODY_FILE"
286 git show "origin/$SUGGESTIONS_BRANCH:$file" >> "$PR_BODY_FILE" 2>/dev/null || true
287 echo "" >> "$PR_BODY_FILE"
288 echo "---" >> "$PR_BODY_FILE"
289done
290
291# Add tracking info
292cat >> "$PR_BODY_FILE" << EOF
293
294## PRs Included
295
296EOF
297
298echo "$MANIFEST" | jq -r '.suggestions[] | "- [PR #\(.pr)](\(.file)): \(.title)"' >> "$PR_BODY_FILE"
299
300git add docs/
301git commit -m "docs: auto-apply preview release suggestions
302
303Auto-applied queued documentation suggestions from:
304$(echo "$MANIFEST" | jq -r '.suggestions[] | "- PR #\(.pr)"')
305
306Generated with script/docs-suggest-publish for human review in draft PR."
307
308# Push and create PR
309log "Pushing branch..."
310git push -u origin "$DOCS_BRANCH"
311
312log "Creating PR..."
313PR_URL=$(gh pr create \
314 --draft \
315 --title "docs: auto-apply preview release suggestions" \
316 --body-file "$PR_BODY_FILE" \
317 --label "documentation")
318
319echo ""
320echo -e "${GREEN}PR created:${NC} $PR_URL"
321
322# Reset suggestions branch if not keeping
323if [[ "$KEEP_QUEUE" != "true" ]]; then
324 echo ""
325 echo "Resetting suggestions queue..."
326
327 git checkout --orphan "${SUGGESTIONS_BRANCH}-reset"
328 git rm -rf . > /dev/null 2>&1 || true
329
330 cat > README.md << 'EOF'
331# Documentation Suggestions Queue
332
333This branch contains batched documentation suggestions for the next Preview release.
334
335Each file represents suggestions from a merged PR. At preview branch cut time,
336run `script/docs-suggest-publish` to create a documentation PR from these suggestions.
337
338## Structure
339
340- `suggestions/PR-XXXXX.md` - Suggestions for PR #XXXXX
341- `manifest.json` - Index of all pending suggestions
342
343## Workflow
344
3451. PRs merged to main trigger documentation analysis
3462. Suggestions are committed here as individual files
3473. At preview release, suggestions are collected into a docs PR
3484. After docs PR is created, this branch is reset
349EOF
350
351 mkdir -p suggestions
352 echo '{"suggestions":[]}' > manifest.json
353 git add README.md suggestions manifest.json
354 git commit -m "Reset documentation suggestions queue
355
356Previous suggestions published in: $PR_URL"
357
358 git push -f origin "${SUGGESTIONS_BRANCH}-reset:$SUGGESTIONS_BRANCH"
359 git checkout "$ORIGINAL_BRANCH"
360 git branch -D "${SUGGESTIONS_BRANCH}-reset"
361
362 echo "Suggestions queue reset."
363else
364 git checkout "$ORIGINAL_BRANCH"
365 echo ""
366 echo "Suggestions queue kept (--keep-queue). Remember to reset manually after PR is merged."
367fi
368
369# Cleanup
370
371
372echo ""
373echo -e "${GREEN}Done!${NC}"
374echo ""
375echo "Next steps:"
376echo "1. Review the draft PR and verify all auto-applied docs changes"
377echo "2. Confirm full-file brand voice pass for each touched docs file"
378echo "3. Mark ready for review and merge"