Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
ee1cb0a
Correct the branch control note
greenshootbot Jul 29, 2026
6832535
Add the Phase 3 assets design
greenshootbot Jul 30, 2026
0881079
Add the Phase 3 assets implementation plan
greenshootbot Jul 30, 2026
058d1b6
Extract card cover targets alongside the count
greenshootbot Jul 30, 2026
ee449fc
Add asset naming and treatment planning
greenshootbot Jul 30, 2026
7b0f85c
Validate bytes in planAsset's GIF branch to prevent silent misrouting
greenshootbot Jul 30, 2026
06c49e8
Extract the asset copy set from source
greenshootbot Jul 30, 2026
7db5eaa
Document the ATTR/file-block coupling in asset-refs
greenshootbot Jul 30, 2026
2996f08
Add the asset script, copying verbatim
greenshootbot Jul 30, 2026
2a07425
Correct the assets.mjs docstring to match this task's behaviour
greenshootbot Jul 30, 2026
5d3b5eb
Emit asset references from the asset map
greenshootbot Jul 30, 2026
6f5242b
Fix review findings on asset-map reference emission
greenshootbot Jul 30, 2026
2b30e06
Encode images to meet the size gate
greenshootbot Jul 30, 2026
fbc63d1
Key the asset sweep on destination and slug, not slug alone
greenshootbot Jul 30, 2026
182fa78
Re-encode the oversized GIF to MP4
greenshootbot Jul 30, 2026
a2eb034
Record Phase 3 asset findings
greenshootbot Jul 30, 2026
e9fcae1
Correct public/ size figure and ffmpeg attribution in Phase 3 gate notes
greenshootbot Jul 30, 2026
c93edc2
Close final review findings on the asset pipeline
greenshootbot Jul 30, 2026
61b5874
Add the Phase 4 continuation prompt
greenshootbot Jul 30, 2026
22cf3dd
Serve Poppins and IBM Plex Mono, the docs site's own faces
greenshootbot Jul 30, 2026
efa6b55
Match GitBook's site title and centre the page shell
greenshootbot Jul 30, 2026
c80c2b8
Carry GitBook's header links across and ship light-only
greenshootbot Jul 30, 2026
4f2b76c
Add the section breadcrumb and match GitBook's heading scale
greenshootbot Jul 30, 2026
0058298
Collapse the sidebar and make parent pages one clickable row
greenshootbot Jul 30, 2026
3d693e5
Restore Starlight's cascade layer order, centring the search dialog
greenshootbot Jul 30, 2026
d84588b
Carry GitBook's image widths through, and pair captions into figures
greenshootbot Jul 30, 2026
b6f8e86
Render GitBook's emoji shortcodes
greenshootbot Jul 30, 2026
a1a812b
Emit video embeds as raw HTML, returning 28 pages to .md
greenshootbot Jul 30, 2026
a23c063
Restore card cover images
greenshootbot Jul 30, 2026
7c9fc34
Record the Phase 4 gate
greenshootbot Jul 30, 2026
45bc64e
Rewrite relative page links inside raw HTML anchors
greenshootbot Jul 30, 2026
6d1e64f
Add the Phase 5 continuation prompt
greenshootbot Jul 31, 2026
3ce3e61
Record the Phase 5 design
greenshootbot Jul 31, 2026
bf7872a
Add the Phase 5 implementation plan
greenshootbot Jul 31, 2026
4467f6a
Bump sharp to 0.35.3 and re-encode every asset
greenshootbot Jul 31, 2026
bed18fa
Serve the light theme to readers without JavaScript
greenshootbot Jul 31, 2026
8ee9c4b
Commit the internal link and anchor check
greenshootbot Jul 31, 2026
d983f84
Commit the live URL check
greenshootbot Jul 31, 2026
dfb58cf
Check built images and publish the alt-text work list
greenshootbot Jul 31, 2026
04a0f73
Add PR preview workflow via Cloudflare Worker versions
stu-greenshoots Aug 25, 2026
77dff4d
Merge origin/main into phase-4/look-and-feel
greenshootbot Aug 27, 2026
0f5f4ae
Retire the conversion pipeline and author content directly
greenshootbot Aug 27, 2026
18f61f2
Bring the Phase 5 handover docs in line with the retired pipeline
greenshootbot Aug 27, 2026
ea09a00
Audit alt text against the pages we author, not the frozen snapshot
greenshootbot Aug 28, 2026
9ea473e
Record how the alt-text audit was fixed
greenshootbot Aug 28, 2026
fbc9b9b
Remove the build scaffolding from docs/
greenshootbot Aug 28, 2026
f1d8338
Merge pull request #21 from opendialogai/ci/pr-preview-workflow
patshone-gsl Aug 28, 2026
b1c2ccb
Merge phase-4/look-and-feel into docs/branch-control-correction
greenshootbot Aug 28, 2026
f5fe120
Restore the @emnapi entries npm 11.6 pruned from the lockfile
greenshootbot Aug 28, 2026
6fc9074
Merge pull request #16 from opendialogai/docs/branch-control-correction
patshone-gsl Aug 28, 2026
0857f86
Pin the preview upload to wrangler 4
greenshootbot Aug 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
100 changes: 100 additions & 0 deletions .github/workflows/pr-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Builds every PR and uploads the result to Cloudflare as a Worker *version* —
# a preview that leaves production untouched — then comments the preview URL on
# the PR. Complements Workers Builds, which deploys `main` to production but
# reports nothing back to GitHub.
#
# Requires two repository secrets:
# CLOUDFLARE_API_TOKEN — API token with Workers Scripts: Edit on the account
# CLOUDFLARE_ACCOUNT_ID — the Cloudflare account id
# Until they are set (and on fork/Dependabot PRs, which cannot read secrets),
# the build still runs as a check and the preview upload is skipped with a note.
name: PR preview

on:
pull_request:
branches: [main]

concurrency:
group: pr-preview-${{ github.event.pull_request.number }}
cancel-in-progress: true

permissions:
contents: read
pull-requests: write

jobs:
preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version-file: .node-version
cache: npm

- run: npm ci

- run: npx astro build

- name: Check for Cloudflare credentials
id: creds
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: |
if [ -n "$CLOUDFLARE_API_TOKEN" ]; then
echo "available=true" >> "$GITHUB_OUTPUT"
else
echo "available=false" >> "$GITHUB_OUTPUT"
echo "CLOUDFLARE_API_TOKEN is not available (missing secret, fork PR, or Dependabot) — preview upload skipped." >> "$GITHUB_STEP_SUMMARY"
fi

- name: Upload preview version to Cloudflare
if: steps.creds.outputs.available == 'true'
id: upload
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
# wrangler is not a project dependency - it is invoked through npx - so the action
# cannot find one and falls back to its own default, 3.90.0. That version predates
# assets-only Workers and fails with "Missing entry-point", because wrangler.jsonc
# declares `assets` and no `main`. Pin the version the project actually uses.
wranglerVersion: "4.127.0"
command: versions upload

- name: Comment the preview URL on the PR
if: steps.creds.outputs.available == 'true'
uses: actions/github-script@v7
env:
WRANGLER_OUTPUT: ${{ steps.upload.outputs.command-output }}
with:
script: |
const match = (process.env.WRANGLER_OUTPUT || '').match(/https:\/\/\S+\.workers\.dev/);
const marker = '<!-- workers-preview-comment -->';
const sha = context.payload.pull_request.head.sha.slice(0, 7);
const body = match
? `${marker}\n### 🔍 Preview\n\n**${match[0]}**\n\nBuilt from \`${sha}\`. Uploaded as a Worker version — production is unaffected until merge.`
: `${marker}\n### 🔍 Preview\n\nThe preview version uploaded, but no preview URL appeared in the wrangler output — check that the worker's Preview URLs setting is enabled. Built from \`${sha}\`.`;
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
per_page: 100,
});
const existing = comments.find((c) => c.body && c.body.includes(marker));
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ dist/
.wrangler/
screenshots/
.playwright-mcp/
.DS_Store
22 changes: 11 additions & 11 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ Migrating OpenDialog's product docs off GitBook onto Astro Starlight, deployed t
## Hard rules

1. **`documentation` branch is read-only.** GitBook syncs to it bidirectionally. Writing to it corrupts the live site. Work on a feature branch.
2. **Never hand-edit files in `src/content/docs/`.** They are generated. Found a bug? Fix `scripts/convert.mjs` and re-run. A manual edit is silently destroyed on the next run and creates a bug that reappears at cutover.
3. **Scripts must be idempotent.** `convert.mjs` and `assets.mjs` run repeatedly, right up to cutover day, against fresh GitBook syncs. Same input must give byte-identical output.
2. **`src/content/docs/` is hand-authored and is the source of truth.** Author pages in Starlight dialect: `.md`/`.mdx`, site-absolute internal links (`/core-concepts/…`), and `~/assets/…` image paths so `astro:assets` optimises them. The GitBook conversion was a one-time process and it is complete — never regenerate this directory to change content.
3. **Never run `npm run convert` or `scripts/convert.mjs`.** `convert.mjs` deletes `src/content/docs/` wholesale and rewrites it from the frozen `source/` snapshot, discarding every page authored since the migration. The pipeline is retired; it and its tests are kept as the record of how the corpus was produced. `assets.mjs` and `routes.mjs` remain safe to run on their own, and must stay idempotent — same input, byte-identical output.
4. **`source/` is pristine and git-ignored.** All scripts read from `source/`, write to `src/`. Never mutate `source/` in place.
5. **URLs do not change.** Not the ugly ones either. Every path in the live `sitemap.xml` must resolve. This is the acceptance test.
6. **Do not edit documentation prose.** Not to fix typos, not to improve clarity. Log it in `MIGRATION-NOTES.md`.
Expand All @@ -19,11 +19,11 @@ Migrating OpenDialog's product docs off GitBook onto Astro Starlight, deployed t
## Gotchas that will bite

- **`{ attr | filter }` in prose breaks MDX builds.** OpenDialog's docs are full of this template syntax. In `.mdx` the braces parse as JSX expressions. Safe inside code fences, fatal outside them. Prefer `.md` — Starlight asides (`:::note`) work there. Only promote to `.mdx` when a Starlight component is genuinely required.
- **Images must live in `src/assets/`, never `public/`.** Files in `public/` bypass `astro:assets` entirely and ship unoptimised. With 541 MB of source images this is the whole performance story.
- **Images must live in `src/assets/`, never `public/`.** Files in `public/` bypass `astro:assets` entirely and ship unoptimised. With 541 MB of source images this is the whole performance story. Exception: video and downloadable files cannot pass through `astro:assets`, so the one MP4 lives in `public/media/` and the one CSV in `public/files/`.
- **Raw `<img>` in markdown is not optimised.** The source has 430 `<figure><img>` blocks. They must become markdown `![]()` syntax or the optimisation never happens. Highest-value transformation in the project.
- **1,317 asset filenames contain spaces or parentheses**, and GitBook wraps those paths in angle brackets: `![](<../.gitbook/assets/image (149).png>)`. Handle that form or you will silently drop images.
- **50 assets have no file extension.** Sniff magic bytes and rename, or they get served with the wrong MIME type.
- **One 28 MB GIF exceeds Cloudflare's 25 MiB per-file limit** and will fail deployment. Re-encode to MP4.
- **50 assets have no file extension**, and all 50 are orphans — referenced from nowhere in `source/` — so none is ever copied and no MIME type is ever served.
- **The GIF that ships, `Knowledge Base Demo.gif`, is 22.56 MiB** — under Cloudflare's 25 MiB per-file limit — and is re-encoded to a 1.12 MiB MP4 for weight, not to clear the cap. A separate 28 MB GIF that does exceed the cap is an orphan, referenced by nothing, and is never copied.
- **Do not set `run_worker_first`** in `wrangler.jsonc`. Static asset requests are free and unlimited; Worker invocations are metered at 100k/day on the free plan.
- **Never make DNS changes.** Pat repoints `docs.opendialog.ai` manually at cutover. Cloudflare API access is available for Workers and deployments only.
- **Pat owns the GitBook analytics export.** Do not attempt it.
Expand Down Expand Up @@ -55,16 +55,16 @@ URL set. Measured against the live sitemap: 204. Route parity is judged against
```bash
npm run dev # local dev server
npm run build # astro build -> dist/
npm run convert # source/ -> route-map.json -> src/content/docs/ -> sidebar
node scripts/assets.mjs # rename, re-encode, rewrite refs
npm run convert # source/ -> route-map.json -> asset-map.json -> src/content/docs/ -> sidebar
node scripts/assets.mjs # copy, encode, write asset-map.json
node scripts/routes.mjs # built routes vs live sitemap.xml, writes route-map.json
npx wrangler deploy # deploy to Cloudflare
```

`npm run convert` runs `routes.mjs`, `convert.mjs` and `sidebar.mjs` in that order. `convert.mjs`
reads `route-map.json` rather than `source/` directly, so running it on its own against a sync
that adds a page silently leaves the new page unconverted — always use `npm run convert`, never
`node scripts/convert.mjs` alone.
`npm run convert` runs `routes.mjs`, `assets.mjs`, `convert.mjs` and `sidebar.mjs` in that order.
`convert.mjs` reads `route-map.json` and `asset-map.json` rather than `source/` directly, so
running it on its own against a sync that adds a page or an image silently leaves the addition
unconverted — always use `npm run convert`, never `node scripts/convert.mjs` alone.

## Definition of done for any change

Expand Down
Loading
Loading