Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 171 additions & 0 deletions .github/workflows/bento-board-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
name: Bento Board Preview Deploy

on:
pull_request:
types:
- opened
- reopened
- synchronize
- closed
paths:
- "bento-board/**"
- ".github/workflows/bento-board-preview.yml"
push:
branches:
- main
paths:
- "bento-board/**"
- ".github/workflows/bento-board-preview.yml"

permissions:
contents: write
pull-requests: write

concurrency:
group: bento-board-preview-${{ github.event.pull_request.number || github.ref_name }}
cancel-in-progress: true

jobs:
deploy-preview:
if: github.event_name == 'pull_request' && github.event.action != 'closed' && github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
env:
PREVIEW_DIR: previews/bento-board/pr-${{ github.event.pull_request.number }}
PREVIEW_URL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/previews/bento-board/pr-${{ github.event.pull_request.number }}/
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22

- name: Verify Bento Board
working-directory: bento-board
run: npm run verify

- name: Deploy preview to gh-pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_branch: gh-pages
publish_dir: ./bento-board
destination_dir: ${{ env.PREVIEW_DIR }}
keep_files: true
enable_jekyll: false

- name: Comment preview URL on pull request
uses: actions/github-script@v7
env:
PREVIEW_DIR: ${{ env.PREVIEW_DIR }}
PREVIEW_URL: ${{ env.PREVIEW_URL }}
with:
script: |
const marker = "<!-- bento-board-preview -->";
const headSha = context.payload.pull_request.head.sha.slice(0, 7);
const body = `${marker}
Bento Board preview deployed.

URL: ${process.env.PREVIEW_URL}
Commit: ${headSha}
Path: \`${process.env.PREVIEW_DIR}/\`

If this is the first deployment, enable GitHub Pages once in repository settings and point it at the \`gh-pages\` branch.`;

const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number
});

const existing = comments.find(
(comment) => comment.user.type === "Bot" && comment.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
});
}
Comment on lines +76 to +100
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Marker comment can be missed on long-lived PRs.

github.rest.issues.listComments({...}) returns only the first 30 comments by default. On a long-running PR (review threads, CI bots, etc.), the marker comment may sit beyond page 1 and existing will be undefined, causing a duplicate preview comment to be posted on every redeploy. Use paginate (or a higher per_page) so the marker is reliably found.

🐛 Proposed fix
-            const { data: comments } = await github.rest.issues.listComments({
+            const comments = await github.paginate(github.rest.issues.listComments, {
               owner: context.repo.owner,
               repo: context.repo.repo,
-              issue_number: context.issue.number
+              issue_number: context.issue.number,
+              per_page: 100
             });

             const existing = comments.find(
-              (comment) => comment.user.type === "Bot" && comment.body.includes(marker)
+              (comment) => comment.user?.type === "Bot" && comment.body?.includes(marker)
             );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number
});
const existing = comments.find(
(comment) => comment.user.type === "Bot" && comment.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
});
}
const comments = await github.paginate(github.rest.issues.listComments, {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
per_page: 100
});
const existing = comments.find(
(comment) => comment.user?.type === "Bot" && comment.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
});
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/bento-board-preview.yml around lines 76 - 100, The
marker-search currently only inspects the first page because
github.rest.issues.listComments(...) defaults to 30 items, so update the logic
that finds `existing` to fetch all comments (e.g., use `github.paginate` or call
`github.rest.issues.listComments` with `per_page: 100` and paginate) and then
search for the comment whose `user.type === "Bot"` and `body.includes(marker)`
before deciding to call `github.rest.issues.updateComment` or
`github.rest.issues.createComment`; ensure you replace the single-page
`comments` result used when constructing `existing` so duplicate preview
comments are not created on long-lived PRs.


cleanup-preview:
if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
env:
PREVIEW_DIR: previews/bento-board/pr-${{ github.event.pull_request.number }}
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Remove preview directory from gh-pages
run: |
if ! git ls-remote --exit-code --heads origin gh-pages >/dev/null 2>&1; then
echo "gh-pages branch does not exist yet."
exit 0
fi

git fetch origin gh-pages:gh-pages
git switch gh-pages

if [ ! -d "${PREVIEW_DIR}" ]; then
echo "Preview directory already removed."
exit 0
fi

rm -rf "${PREVIEW_DIR}"

if [ -z "$(git status --short)" ]; then
echo "No cleanup changes to commit."
exit 0
fi

git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add -A
git commit -m "Remove Bento Board preview for PR #${{ github.event.pull_request.number }}"
git push origin gh-pages

deploy-stable:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
env:
STABLE_DIR: bento-board
STABLE_URL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/bento-board/
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22

- name: Verify Bento Board
working-directory: bento-board
run: npm run verify

- name: Deploy stable build to gh-pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_branch: gh-pages
publish_dir: ./bento-board
destination_dir: ${{ env.STABLE_DIR }}
keep_files: true
enable_jekyll: false

- name: Print stable URL
run: echo "Stable Bento Board build deployed to ${STABLE_URL}"
45 changes: 45 additions & 0 deletions bento-board/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Bento Board

Standalone first-playable vertical slice for the Bento Board puzzle brief.

## Run

Open `index.html` in a browser, or serve the directory with any static file server.
Comment on lines +5 to +7
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

file:// will not load ES modules in most browsers.

bento-board/src/app.js uses ES module imports (import { ... } from "./daily.js") and is loaded via <script type="module">. Most browsers refuse to load ES modules over file:// due to CORS, so "Open index.html in a browser" will fail with a console error for the typical case. Recommend leading with the static-server option (or removing the file:// suggestion altogether).

📝 Proposed wording fix
-Open `index.html` in a browser, or serve the directory with any static file server.
+Serve the directory with any static file server (for example `npx http-server bento-board` or `python3 -m http.server -d bento-board`). Opening `index.html` directly via `file://` will not work because `src/app.js` is loaded as an ES module.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## Run
Open `index.html` in a browser, or serve the directory with any static file server.
## Run
Serve the directory with any static file server (for example `npx http-server bento-board` or `python3 -m http.server -d bento-board`). Opening `index.html` directly via `file://` will not work because `src/app.js` is loaded as an ES module.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bento-board/README.md` around lines 5 - 7, The README's "Open `index.html` in
a browser" suggestion is incorrect because bento-board/src/app.js uses ES module
imports (import ... from "./daily.js") loaded via <script type="module"> which
will usually fail over file://; update the Run section to remove or de-emphasize
the file:// option and lead with instructions to serve the directory with a
static file server (or only describe using a static server), and mention that ES
modules require HTTP(S) so browsers will block module loading via file:// when
loading index.html that references app.js.


## Test

```bash
npm test
```

## Verify

```bash
npm run verify
```

## Deployment

- Pull requests that change `bento-board/**` or `.github/workflows/bento-board-preview.yml` publish a preview build to `https://<owner>.github.io/<repo>/previews/bento-board/pr-<number>/`.
- Pushes to `main` that change the same paths publish the stable build to `https://<owner>.github.io/<repo>/bento-board/`.
- Both deploy jobs verify the slice first with `npm run verify`.

## Rollback And First Checks

- Preview cleanup is automatic when the pull request closes; the workflow removes `previews/bento-board/pr-<number>/` from `gh-pages`.
- Stable rollback is a normal git revert on `main`; the next stable deploy republishes the reverted `bento-board/` contents to `gh-pages`.
- First post-deploy QA should cover a narrow-phone viewport pass, daily unlock after level `6`, UTC date rollover for the daily special, and jam / overflow recovery through `Undo`, `Restart`, and `Hint`.

## Included

- Data-driven menu packs, handcrafted levels, tutorial callouts, rewards, and daily special generation
- Fastener-first input only: picks, bands, and dividers trigger auto-slide resolution
- Undo, hint, restart, fail, win, and a simple journal wrapper
- Portrait mobile-first UI that keeps the lunchbox, recipe ribbon, and stack field readable on a phone viewport

## Implementation Notes

- Readability gets fragile once multiple fasteners crowd the same lane, so the authoring validator keeps the silhouette count and early exposed moves conservative.
- Fastener hit targets are separated by type and offset in the UI, but any future denser layouts should keep the 56px / 60px / 64px target sizes intact.
- The solver is intentionally lightweight and monotonic; if later content adds branching destinations, moving blockers, or non-monotonic stack rules, the validator will need a deeper search model.
- Overflow is supported by the engine, but the handcrafted campaign stays mostly exact-count so the slice remains readable and solvable without hidden routing.
13 changes: 13 additions & 0 deletions bento-board/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Bento Board</title>
<link rel="stylesheet" href="./styles.css" />
</head>
<body>
<div id="app"></div>
<script type="module" src="./src/app.js"></script>
</body>
</html>
11 changes: 11 additions & 0 deletions bento-board/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "bento-board",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"test": "node --test",
"check:app": "node --check src/app.js",
"verify": "npm test && npm run check:app"
}
}
Loading
Loading