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
182Before making edits, read and follow these rule files:
183- `.rules`
184- `docs/.rules`
185
186## Required behavior
187
1881. Apply concrete documentation edits (not suggestion text) to the appropriate files.
1892. Edit only docs content files under `docs/src/` unless a suggestion explicitly requires another docs path.
1903. For every docs file you modify, run a full-file brand voice pass (entire file, not only edited sections).
1914. Enforce the brand rubric exactly; final file content must score 4+ on every criterion:
192 - Technical Grounding
193 - Natural Syntax
194 - Quiet Confidence
195 - Developer Respect
196 - Information Priority
197 - Specificity
198 - Voice Consistency
199 - Earned Claims
2005. Keep SEO/frontmatter/linking requirements from the suggestions where applicable.
2016. Keep preview callout semantics correct:
202 - Additive features: `> **Preview:** ...`
203 - Behavior modifications: `> **Changed in Preview (vX.XXX).** ...`
2047. If a suggestion is too ambiguous to apply safely, skip it and explain why in the summary.
205
206## Output format (after making edits)
207
208Return markdown with:
209
210- `## Applied Suggestions`
211- `## Skipped Suggestions`
212- `## Files Updated`
213- `## Brand Voice Verification` (one line per updated file confirming full-file pass)
214
215Do not include a patch in the response; apply edits directly to files.
216
217## Queued Suggestions
218
219EOF
220
221cat "$SUGGESTIONS_FILE" >> "$APPLY_PROMPT_FILE"
222
223log "Running Droid auto-apply with model: $MODEL"
224droid exec -m "$MODEL" -f "$APPLY_PROMPT_FILE" > "$APPLY_SUMMARY_FILE"
225
226if [[ -n "$(git status --porcelain | grep -vE '^.. docs/' || true)" ]]; then
227 error "Auto-apply modified non-doc files. Revert and re-run."
228fi
229
230if [[ -z "$(git status --porcelain docs/ | grep '^.. docs/src/' || true)" ]]; then
231 error "Auto-apply produced no docs/src changes."
232fi
233
234log "Running docs formatter"
235./script/prettier
236
237if [[ -z "$(git status --porcelain docs/ | grep '^.. docs/src/' || true)" ]]; then
238 error "No docs/src changes remain after formatting; aborting PR creation."
239fi
240
241# Build PR body from suggestions
242PR_BODY_FILE="$TMPDIR/pr-body.md"
243cat > "$PR_BODY_FILE" << 'EOF'
244# Documentation Updates for Preview Release
245
246This draft PR auto-applies queued documentation suggestions collected from
247recently merged PRs.
248
249## How to Use This PR
250
2511. Review the applied changes file-by-file.
2522. Verify brand voice on each touched file as a full-file pass.
2533. Ensure docs use the correct callout type:
254 - Additive features: Preview callout
255 - Behavior modifications: Changed in Preview callout
2564. Merge when ready.
257
258## Auto-Apply Summary
259
260EOF
261
262cat "$APPLY_SUMMARY_FILE" >> "$PR_BODY_FILE"
263
264cat >> "$PR_BODY_FILE" << 'EOF'
265
266## Preview Callouts
267
268Use the Preview callout for new/additive features:
269
270```markdown
271> **Preview:** This feature is available in Zed Preview. It will be included in the next Stable release.
272```
273
274Use this callout for behavior modifications to existing functionality:
275
276```markdown
277> **Changed in Preview (v0.XXX).** See [release notes](/releases#0.XXX).
278```
279
280---
281
282## Pending Suggestions
283
284EOF
285
286# Append each suggestion to PR body
287for file in $(echo "$MANIFEST" | jq -r '.suggestions[].file'); do
288 log "Adding $file to PR body..."
289 echo "" >> "$PR_BODY_FILE"
290 git show "origin/$SUGGESTIONS_BRANCH:$file" >> "$PR_BODY_FILE" 2>/dev/null || true
291 echo "" >> "$PR_BODY_FILE"
292 echo "---" >> "$PR_BODY_FILE"
293done
294
295# Add tracking info
296cat >> "$PR_BODY_FILE" << EOF
297
298## PRs Included
299
300EOF
301
302echo "$MANIFEST" | jq -r '.suggestions[] | "- [PR #\(.pr)](\(.file)): \(.title)"' >> "$PR_BODY_FILE"
303
304cat >> "$PR_BODY_FILE" << 'EOF'
305
306Release Notes:
307
308- N/A
309EOF
310
311git add docs/
312git commit -m "docs: auto-apply preview release suggestions
313
314Auto-applied queued documentation suggestions from:
315$(echo "$MANIFEST" | jq -r '.suggestions[] | "- PR #\(.pr)"')
316
317Generated with script/docs-suggest-publish for human review in draft PR."
318
319# Push and create PR
320log "Pushing branch..."
321git push -u origin "$DOCS_BRANCH"
322
323log "Creating PR..."
324PR_URL=$(gh pr create \
325 --draft \
326 --title "docs: auto-apply preview release suggestions" \
327 --body-file "$PR_BODY_FILE" \
328 --label "documentation")
329
330echo ""
331echo -e "${GREEN}PR created:${NC} $PR_URL"
332
333# Reset suggestions branch if not keeping
334if [[ "$KEEP_QUEUE" != "true" ]]; then
335 echo ""
336 echo "Resetting suggestions queue..."
337
338 git checkout --orphan "${SUGGESTIONS_BRANCH}-reset"
339 git rm -rf . > /dev/null 2>&1 || true
340
341 cat > README.md << 'EOF'
342# Documentation Suggestions Queue
343
344This branch contains batched documentation suggestions for the next Preview release.
345
346Each file represents suggestions from a merged PR. At preview branch cut time,
347run `script/docs-suggest-publish` to create a documentation PR from these suggestions.
348
349## Structure
350
351- `suggestions/PR-XXXXX.md` - Suggestions for PR #XXXXX
352- `manifest.json` - Index of all pending suggestions
353
354## Workflow
355
3561. PRs merged to main trigger documentation analysis
3572. Suggestions are committed here as individual files
3583. At preview release, suggestions are collected into a docs PR
3594. After docs PR is created, this branch is reset
360EOF
361
362 mkdir -p suggestions
363 echo '{"suggestions":[]}' > manifest.json
364 git add README.md suggestions manifest.json
365 git commit -m "Reset documentation suggestions queue
366
367Previous suggestions published in: $PR_URL"
368
369 git push -f origin "${SUGGESTIONS_BRANCH}-reset:$SUGGESTIONS_BRANCH"
370 git checkout "$ORIGINAL_BRANCH"
371 git branch -D "${SUGGESTIONS_BRANCH}-reset"
372
373 echo "Suggestions queue reset."
374else
375 git checkout "$ORIGINAL_BRANCH"
376 echo ""
377 echo "Suggestions queue kept (--keep-queue). Remember to reset manually after PR is merged."
378fi
379
380# Cleanup
381
382
383echo ""
384echo -e "${GREEN}Done!${NC}"
385echo ""
386echo "Next steps:"
387echo "1. Review the draft PR and verify all auto-applied docs changes"
388echo "2. Confirm full-file brand voice pass for each touched docs file"
389echo "3. Mark ready for review and merge"