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
170 changes: 170 additions & 0 deletions .github/workflows/loom-rescue-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
name: Loom Rescue Preview Deploy

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

permissions:
contents: write
pull-requests: write

concurrency:
group: loom-rescue-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/pr-${{ github.event.pull_request.number }}
PREVIEW_URL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/previews/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 Loom Rescue
working-directory: loom-rescue
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: ./loom-rescue
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 = "<!-- loom-rescue-preview -->";
const body = `${marker}
Loom Rescue preview deployed.

URL: ${process.env.PREVIEW_URL}
Commit: ${context.sha.slice(0, 7)}
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.`;
Comment on lines +65 to +73
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

Build the PR comment body without leading indentation.

Those spaces are preserved inside the template literal, so the bot comment renders as an indented Markdown code block instead of normal prose/links.

📝 Suggested fix
-            const body = `${marker}
-            Loom Rescue preview deployed.
-
-            URL: ${process.env.PREVIEW_URL}
-            Commit: ${context.sha.slice(0, 7)}
-            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 body = [
+              marker,
+              "Loom Rescue preview deployed.",
+              "",
+              `URL: ${process.env.PREVIEW_URL}`,
+              `Commit: ${context.sha.slice(0, 7)}`,
+              `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."
+            ].join("\n");
📝 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 marker = "<!-- loom-rescue-preview -->";
const body = `${marker}
Loom Rescue preview deployed.
URL: ${process.env.PREVIEW_URL}
Commit: ${context.sha.slice(0, 7)}
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 marker = "<!-- loom-rescue-preview -->";
const body = [
marker,
"Loom Rescue preview deployed.",
"",
`URL: ${process.env.PREVIEW_URL}`,
`Commit: ${context.sha.slice(0, 7)}`,
`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."
].join("\n");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/loom-rescue-preview.yml around lines 65 - 73, The template
literal assigned to the body variable (with marker = "<!-- loom-rescue-preview
-->") contains leading indentation that gets preserved and causes the PR comment
to render as a code block; remove the extra leading spaces inside the template
literal so the text lines start at column 0 (or build the string using
concatenation/join on an array of unindented lines) so the comment renders as
normal prose and links rather than an indented Markdown block.


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
});
}

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/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 Loom Rescue 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: loom-rescue
STABLE_URL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/loom-rescue/
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 Loom Rescue
working-directory: loom-rescue
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: ./loom-rescue
destination_dir: ${{ env.STABLE_DIR }}
keep_files: true
enable_jekyll: false

- name: Print stable URL
run: echo "Stable Loom Rescue build deployed to ${STABLE_URL}"
41 changes: 41 additions & 0 deletions loom-rescue/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Loom Rescue

Standalone first-playable vertical slice for the Loom Rescue puzzle brief.

## Run

Open `index.html` in a browser, or serve the directory with any static file server.

## Test

```bash
npm test
```

## Verify

```bash
npm run verify
```

## What Is Included

- Data-driven rules for bundles, lock pins, static one-way guides, and two-layer crossings on a `6x8` portrait board
- Full FTUE path with `15` handcrafted levels plus a seeded daily template
- In-level flows for start, play, hint, undo, restart, fail, win, and postcard reveal
- Light reward wrapper with postcard progress and milestone stamps at levels `5`, `10`, `15`, and the daily
- Deadlock fail handling when no legal pulls or exposed pins remain
- Undo that only rewinds the last successful state change and does not refund knot loss from invalid pulls

## Implementation Notes

- The current validator proves solvability because the slice uses monotonic unlocks only. If the design later adds moving guides, true reverse-pull guide failures, partial pulls, or dynamic crossings, the authoring pipeline will need a deeper search-based solver.
- Readability risk rises sharply once multiple undeclared route corridors sit close together. The current prototype offsets thread rendering to keep the dense boards legible, but a production version should add stronger art treatment for top/bottom crossings and pin silhouettes.
- QA should focus on invalid pull reasons, deadlock fail messaging, two-knot daily failure tuning, daily unlock gating after level 15, and whether bundle labels remain readable on smaller mobile screens.

## Preview Deployment

- GitHub Actions workflow: `.github/workflows/loom-rescue-preview.yml`
- Pull requests deploy to `https://<owner>.github.io/<repo>/previews/pr-<number>/`
- `main` deploys the stable path to `https://<owner>.github.io/<repo>/loom-rescue/`
- The first deployment still requires enabling GitHub Pages for the `gh-pages` branch in repository settings
13 changes: 13 additions & 0 deletions loom-rescue/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>Loom Rescue</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 loom-rescue/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "loom-rescue",
"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