Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
3e94548
chore(preact): scaffold @scrolloop/preact package
zaewc Mar 30, 2026
6218ff4
feat(preact): add VirtualList component
zaewc Mar 30, 2026
ede66b8
feat(preact): add useInfinitePages hook
zaewc Mar 30, 2026
3cae4e9
feat(preact): add InfiniteList component
zaewc Mar 30, 2026
0611fb0
feat(preact): export public API
zaewc Mar 30, 2026
e036941
chore: update lockfile for @scrolloop/preact
zaewc Mar 30, 2026
d0bdd3c
perf(preact): use total+pages instead of allItems in InfiniteList
zaewc Mar 30, 2026
0d3c464
style(preact): extract inline styles to CSS classes in InfiniteList
zaewc Mar 30, 2026
45e0224
Merge pull request #37 from zaewc/feat/preact-adapter
zaewc May 19, 2026
30c82f7
feat(core): add getMaxElementSize runtime probe
zaewc May 19, 2026
993766f
feat(core): clamp FixedLayoutStrategy size to browser max with virtua…
zaewc May 19, 2026
a147b03
chore(core): export getMaxElementSize from package root
zaewc May 19, 2026
a54d342
fix: resync pnpm-lock to match installed tsup variant
zaewc May 19, 2026
b594538
fix(core): use Math.floor instead of |0 for virtual offset truncation
zaewc May 19, 2026
4a8d437
fix(core): guard probe against null document.body
zaewc May 19, 2026
b8797d5
Merge pull request #45 from zaewc/fix/missing-tsup-builds
zaewc May 19, 2026
3d789f5
Merge branch 'develop' of https://github.com/zaewc/scrolloop into fea…
zaewc May 19, 2026
139799a
refactor(core): keep FixedLayoutStrategy stateless, move render trans…
zaewc May 19, 2026
3a6fec1
refactor(core): extract mapToVirtualOffset and avoid intermediate ove…
zaewc May 19, 2026
e58aad4
Merge pull request #44 from zaewc/feat/browser-max-element-size
zaewc May 19, 2026
ae621dd
docs: update README and documentation for multi-framework support and…
zaewc May 19, 2026
4da73fa
fix: correct script tag formatting in InfiniteList.vue
zaewc May 15, 2026
ba1cc16
docs: add AI development pipeline design
zaewc May 20, 2026
858c6c5
docs: add reusable Claude prompt template for AI dev workflow
zaewc May 20, 2026
bf5d185
ci: add ai-dev workflow for AI-assisted PR generation
zaewc May 20, 2026
ff6d990
ci(ai-dev): harden workflow with input validation, runtime-file exclu…
zaewc May 20, 2026
1cdb80e
docs(ai-dev): add prompt-injection security boundary to template
zaewc May 20, 2026
9f03d0c
docs(ai-dev): narrow protected-file patterns and drop frozen-lockfile…
zaewc May 20, 2026
c913ada
docs(ai-pipeline): sync protected-paths list with prompt template rule 7
zaewc May 20, 2026
5295c8f
ci(ai-dev): make verify step fail-fast without continue-on-error or s…
zaewc May 20, 2026
20d9a59
Update docs/ai-pipeline.md
zaewc May 20, 2026
78841c2
Update docs/ai-dev-prompt-template.md
zaewc May 20, 2026
a213418
chore: ignore n8n deployment secrets (.env, Caddyfile)
zaewc May 20, 2026
3b3cf60
infra(n8n): add docker compose stack with SQLite and optional Caddy
zaewc May 20, 2026
4bbf4d0
infra(n8n): add idempotent host setup script
zaewc May 20, 2026
5c43591
docs(n8n): add deployment README for the orchestrator stack
zaewc May 20, 2026
95910f8
fix(n8n/setup): use sudo for docker before group activation takes effect
zaewc May 20, 2026
b8901cb
Merge pull request #46 from zaewc/chore/n8n
zaewc May 20, 2026
d1f58a7
ci(ai-dev): capture claude stderr and exit code for diagnostics
zaewc May 20, 2026
c5b87b4
ci(ai-dev): switch from Claude Code to Gemini CLI (free-tier-friendly)
zaewc May 20, 2026
ce075be
docs: align AI pipeline docs with Gemini CLI swap
zaewc May 20, 2026
3470032
docs(n8n): replace remaining Anthropic ref in CI failure flow
zaewc May 20, 2026
e5ca5ff
ci(ai-dev): set GEMINI_CLI_TRUST_WORKSPACE for headless CI run
zaewc May 20, 2026
6ef7416
fix(ai-dev): use --yolo + revert for plan mode so stdout is captured
zaewc May 21, 2026
38dbbab
fix(n8n): pin docker bridge MTU to 1280 to avoid timeouts on lower-MT…
zaewc May 21, 2026
3e95e08
feat(ai-dev): add model fallback chain + REST API fallback for plan mode
zaewc May 21, 2026
e04e7a9
ci: bump actions to Node 24-compatible versions (checkout v5, setup-n…
zaewc May 21, 2026
e9a9b33
ci: bump actions/cache to v5 and pnpm/action-setup to v6
zaewc May 21, 2026
1ccbb77
feat(ai-dev): add head_branch input + idempotent branch checkout for …
zaewc May 21, 2026
efdf724
feat(ai-dev): refactor to 3-job harness (Planner / Generator / Evalua…
zaewc May 21, 2026
5b633d9
docs(ai-pipeline): describe 3-agent harness architecture
zaewc May 21, 2026
a34945d
docs: add portfolio case study for AI dev harness pipeline
zaewc May 21, 2026
e8f9f90
docs(portfolio): expand deep dive with n8n workflow screenshots + roo…
zaewc May 26, 2026
f09ae86
docs(portfolio): swap ASCII architecture diagram for Mermaid (flowcha…
zaewc May 26, 2026
9d0585f
docs(portfolio): rewrite deep dive with references, concept callouts,…
zaewc May 26, 2026
85e741d
docs(portfolio-entry): 포트폴리오 항목 문서 삭제
zaewc May 26, 2026
34ad407
fix(ai-dev): reset working tree between Gemini fallback attempts for …
zaewc May 27, 2026
d335a33
docs(llms): 새 문서 추가 - scrolloop의 가이드 및 구성 요소 설명
zaewc Jun 18, 2026
16f72aa
feat(docs): add full documentation generation and update guide links …
zaewc Jun 18, 2026
5c6cb27
docs: Preact, Vue, and Svelte 예제 추가 및 수정
zaewc Jun 16, 2026
2362d52
fix(vite.config): update external dependencies to use regex for Svelte
zaewc Jun 19, 2026
cdc268a
feat(InfiniteList): findMissingPages 모듈 추가
zaewc Jun 19, 2026
a903ec8
refactor(shared): React 의존 분리, useInfinitePages를 어댑터로 이동
zaewc Jun 19, 2026
7b2c49d
build(deps): 하네스 도구 추가 + core/shared 내부 전용 처리
zaewc Jun 19, 2026
c9397e2
build: tsup/vite → tsdown 전환 (svelte 제외 6개 패키지)
zaewc Jun 19, 2026
8f3bc23
build(deps): tsup/terser/bundlesize 및 vue/svelte vite 도구 제거
zaewc Jun 19, 2026
a2e3655
feat(lint): ESLint 10 flat config + oxlint 도입
zaewc Jun 19, 2026
6b7e16a
feat(quality): knip(데드코드) + publint/attw(패키지 정합성) 도입
zaewc Jun 20, 2026
7c248e2
feat(size): size-limit 예산 도입 + turbo 튜닝 + CSS export
zaewc Jun 21, 2026
a832a6e
chore(pkg): engines.node 명시 + .nvmrc 추가
zaewc Jun 21, 2026
1741fbd
ci: CI 워크플로 현대화 + 품질 게이트 확장
zaewc Jun 21, 2026
2a1cfa5
refactor(core): @scrolloop/shared를 @scrolloop/core로 통합
zaewc Jun 21, 2026
d98e955
build: 스코프 발행 준비 — core 공개화, 어댑터가 core에 의존
zaewc Jun 21, 2026
43213ff
feat(quality): publint/attw를 발행 패키지별 게이트로 + svelte ESM-only
zaewc Jun 21, 2026
eefbc6d
build(release): Changesets 도입
zaewc Jun 21, 2026
6d03a0a
ci: 발행 잡을 Changesets 기반 release로 교체
zaewc Jun 21, 2026
2f95be7
docs: 릴리스 절차 + scrolloop→@scrolloop/react 이전 안내
zaewc Jun 21, 2026
1c007cd
refactor!: scrolloop을 헤드리스 코어로 (ESLint식 배포)
zaewc Jun 21, 2026
1088783
docs(releasing): NPM_TOKEN은 기존 시크릿 재사용 — 스코프 권한만 확인
zaewc Jun 21, 2026
a0d53cf
fix: 불필요한 코드 제거
zaewc Jun 21, 2026
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
8 changes: 8 additions & 0 deletions .changeset/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Changesets

Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets).

We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md).
11 changes: 11 additions & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "https://unpkg.com/@changesets/config@3.1.4/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "master",
"updateInternalDependencies": "patch",
"ignore": []
}
154 changes: 154 additions & 0 deletions .github/actions/gemini/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
name: 'Run Gemini with fallback'
description: 'Run gemini-cli against a prompt file, with CLI model fallback and optional direct REST API fallback for plan-style read-only tasks.'

inputs:
api_key:
description: 'Gemini API key (secret).'
required: true
prompt_file:
description: 'Path to a file containing the prompt to send.'
required: true
output_file:
description: 'Path to write Gemini stdout to.'
required: true
models:
description: 'Comma-separated fallback chain (CLI --model values).'
required: true
yolo:
description: 'If "true", pass --yolo so tool calls (file edits) auto-accept. Set "false" for analysis-only callers that should also fail-safe via prompt instruction.'
default: 'true'
allow_rest_fallback:
description: 'If "true", also try a direct Gemini REST API call when every CLI attempt fails. Useful for plan/eval phases that only need text output; pointless for phases that must edit files.'
default: 'false'
reset_between_attempts:
description: 'If "true", run `git reset --hard` + `git clean -fd -e .ai -e .harness` between CLI fallback attempts. Required for agentic (file-editing) callers so a partially-modified tree from a failed attempt does not leak into the next model''s context.'
default: 'false'

outputs:
used_model:
description: 'The model that produced output, or empty if all attempts failed.'
value: ${{ steps.run.outputs.used_model }}
used_rest:
description: 'true if the REST fallback produced the output, false if CLI did.'
value: ${{ steps.run.outputs.used_rest }}

runs:
using: composite
steps:
- name: Install gemini-cli
shell: bash
run: |
if ! command -v gemini >/dev/null 2>&1; then
npm install -g @google/gemini-cli
fi
echo "::group::gemini version"
gemini --version || true
echo "::endgroup::"

- name: Run with fallback
id: run
shell: bash
env:
GEMINI_API_KEY: ${{ inputs.api_key }}
PROMPT_FILE: ${{ inputs.prompt_file }}
OUTPUT_FILE: ${{ inputs.output_file }}
MODELS_CSV: ${{ inputs.models }}
YOLO_FLAG: ${{ inputs.yolo == 'true' && '--yolo' || '' }}
ALLOW_REST: ${{ inputs.allow_rest_fallback }}
RESET_BETWEEN: ${{ inputs.reset_between_attempts }}
GEMINI_CLI_TRUST_WORKSPACE: 'true'
run: |
set -e
mkdir -p "$(dirname "$OUTPUT_FILE")" .ai

rc=1
used_model=""
used_rest="false"

# Snapshot the working tree state. Used to reset between fallback
# attempts when the caller is editing files (otherwise a quota-killed
# attempt leaves half-written files that confuse the next model).
initial_head=""
if [ "$RESET_BETWEEN" = "true" ]; then
initial_head=$(git rev-parse HEAD 2>/dev/null || echo "")
echo "::notice::reset_between_attempts=true (initial HEAD=$initial_head)"
fi

attempt=0
IFS=',' read -ra MODELS <<< "$MODELS_CSV"
for model in "${MODELS[@]}"; do
model="$(echo "$model" | xargs)"
[ -z "$model" ] && continue

# Before any retry (attempt > 0), restore the working tree to its
# pre-Gemini state so the next model starts from a clean slate.
if [ "$attempt" -gt 0 ] && [ -n "$initial_head" ]; then
echo "::notice::resetting working tree before retry"
git reset --hard "$initial_head" 2>/dev/null || true
git clean -fd -e .ai -e .harness 2>/dev/null || true
fi
attempt=$((attempt + 1))

echo "::group::CLI attempt: $model"
set +e
gemini --model "$model" $YOLO_FLAG --prompt "$(cat "$PROMPT_FILE")" \
> "$OUTPUT_FILE" 2> .ai/gemini.err
rc=$?
set -e
echo "exit: $rc"
tail -n 20 .ai/gemini.err 2>/dev/null || true
echo "::endgroup::"

if [ $rc -eq 0 ]; then
used_model="$model"
echo "CLI succeeded with $model"
break
fi
if grep -qE 'TerminalQuotaError|Quota exceeded|"code": ?429|status: ?429' .ai/gemini.err 2>/dev/null; then
echo "::notice::$model hit quota; trying next"
continue
fi
echo "::warning::$model failed with non-quota error; stop CLI loop"
break
done

if [ $rc -ne 0 ] && [ "$ALLOW_REST" = "true" ]; then
echo "::notice::falling back to direct Gemini REST API"
for model in "${MODELS[@]}"; do
model="$(echo "$model" | xargs)"
[ -z "$model" ] && continue
echo "::group::REST attempt: $model"
body=$(jq -n --rawfile p "$PROMPT_FILE" '{contents:[{parts:[{text:$p}]}]}')
http_code=$(curl -sS -o .ai/rest.json -w '%{http_code}' \
"https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-d "$body" || echo "000")
echo "HTTP $http_code"
if [ "$http_code" = "200" ]; then
text=$(jq -r '.candidates[0].content.parts[0].text // empty' .ai/rest.json)
if [ -n "$text" ]; then
printf '%s' "$text" > "$OUTPUT_FILE"
rc=0
used_model="$model"
used_rest="true"
echo "REST succeeded with $model"
echo "::endgroup::"
break
fi
fi
jq -r '.error.message // .' .ai/rest.json 2>/dev/null | head -3 || true
echo "::endgroup::"
done
fi

echo "used_model=$used_model" >> "$GITHUB_OUTPUT"
echo "used_rest=$used_rest" >> "$GITHUB_OUTPUT"

if [ $rc -ne 0 ]; then
echo "::error::all Gemini attempts (CLI${ALLOW_REST:+ + REST}) failed"
echo "::group::stdout tail"
tail -n 60 "$OUTPUT_FILE" 2>/dev/null || echo "(empty)"
echo "::endgroup::"
exit $rc
fi
Loading
Loading