fix: Replace Codeberg dependency with local Forgejo instance (#611)
- Add setup_forge() to bin/disinto: provisions Forgejo via Docker, creates admin + bot users (dev-bot, review-bot), generates API tokens, creates repo, and pushes code — all automated - Rename env vars: CODEBERG_TOKEN→FORGE_TOKEN, REVIEW_BOT_TOKEN→ FORGE_REVIEW_TOKEN, CODEBERG_REPO→FORGE_REPO, CODEBERG_API→ FORGE_API, CODEBERG_WEB→FORGE_WEB, CODEBERG_BOT_USERNAMES→ FORGE_BOT_USERNAMES (with backwards-compat fallbacks) - Rename API helpers: codeberg_api()→forge_api(), codeberg_api_all() →forge_api_all() (with compat aliases) - Add forge_url field to project TOML; load-project.sh derives FORGE_API/FORGE_WEB from forge_url + repo - Update parse_repo_slug() to accept any host URL, not just codeberg - Forgejo data stored under ~/.disinto/forgejo/ (not in factory repo) - Update all 58 files: agent scripts, formulas, docs, site HTML Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
39d30faf45
commit
a66bd91721
58 changed files with 863 additions and 628 deletions
|
|
@ -2,7 +2,7 @@
|
|||
# =============================================================================
|
||||
# collect-metrics.sh — Collect factory metrics and write JSON for the dashboard
|
||||
#
|
||||
# Queries Codeberg API for PR/issue stats across all managed projects,
|
||||
# Queries forge API for PR/issue stats across all managed projects,
|
||||
# counts vault decisions, and checks CI pass rates. Writes a JSON snapshot
|
||||
# to the live site directory so the dashboard can fetch it.
|
||||
#
|
||||
|
|
@ -47,12 +47,15 @@ collect_project_metrics() {
|
|||
|
||||
repo=$(grep '^repo ' "$project_toml" | head -1 | sed 's/.*= *"//;s/"//')
|
||||
repo_name=$(grep '^name ' "$project_toml" | head -1 | sed 's/.*= *"//;s/"//')
|
||||
local api_base="https://codeberg.org/api/v1/repos/${repo}"
|
||||
local forge_url
|
||||
forge_url=$(grep '^forge_url ' "$project_toml" | head -1 | sed 's/.*= *"//;s/"//') 2>/dev/null || true
|
||||
forge_url="${forge_url:-${FORGE_URL:-http://localhost:3000}}"
|
||||
local api_base="${forge_url}/api/v1/repos/${repo}"
|
||||
|
||||
# PRs merged (all time via state=closed + merged marker)
|
||||
local prs_merged_week=0 prs_merged_month=0 prs_merged_total=0
|
||||
local closed_prs
|
||||
closed_prs=$(curl -sf -H "Authorization: token ${CODEBERG_TOKEN}" \
|
||||
closed_prs=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \
|
||||
"${api_base}/pulls?state=closed&sort=updated&limit=50" 2>/dev/null || echo "[]")
|
||||
|
||||
prs_merged_total=$(printf '%s' "$closed_prs" | jq '[.[] | select(.merged)] | length' 2>/dev/null || echo 0)
|
||||
|
|
@ -69,7 +72,7 @@ collect_project_metrics() {
|
|||
# Issues closed
|
||||
local issues_closed_week=0 issues_closed_month=0
|
||||
local closed_issues
|
||||
closed_issues=$(curl -sf -H "Authorization: token ${CODEBERG_TOKEN}" \
|
||||
closed_issues=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \
|
||||
"${api_base}/issues?state=closed&sort=updated&type=issues&limit=50" 2>/dev/null || echo "[]")
|
||||
|
||||
if [ -n "$WEEK_AGO" ]; then
|
||||
|
|
@ -82,19 +85,19 @@ collect_project_metrics() {
|
|||
fi
|
||||
|
||||
local total_closed_header
|
||||
total_closed_header=$(curl -sf -I -H "Authorization: token ${CODEBERG_TOKEN}" \
|
||||
total_closed_header=$(curl -sf -I -H "Authorization: token ${FORGE_TOKEN}" \
|
||||
"${api_base}/issues?state=closed&type=issues&limit=1" 2>/dev/null | grep -i 'x-total-count' | tr -d '\r' | awk '{print $2}' || echo "0")
|
||||
local issues_closed_total="${total_closed_header:-0}"
|
||||
|
||||
# Open issues by label
|
||||
local backlog_count in_progress_count blocked_count
|
||||
backlog_count=$(curl -sf -I -H "Authorization: token ${CODEBERG_TOKEN}" \
|
||||
backlog_count=$(curl -sf -I -H "Authorization: token ${FORGE_TOKEN}" \
|
||||
"${api_base}/issues?state=open&labels=backlog&type=issues&limit=1" 2>/dev/null | \
|
||||
grep -i 'x-total-count' | tr -d '\r' | awk '{print $2}' || echo "0")
|
||||
in_progress_count=$(curl -sf -H "Authorization: token ${CODEBERG_TOKEN}" \
|
||||
in_progress_count=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \
|
||||
"${api_base}/issues?state=open&labels=in-progress&type=issues&limit=50" 2>/dev/null | \
|
||||
jq 'length' 2>/dev/null || echo 0)
|
||||
blocked_count=$(curl -sf -H "Authorization: token ${CODEBERG_TOKEN}" \
|
||||
blocked_count=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \
|
||||
"${api_base}/issues?state=open&labels=blocked&type=issues&limit=50" 2>/dev/null | \
|
||||
jq 'length' 2>/dev/null || echo 0)
|
||||
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@
|
|||
<div class="footer">
|
||||
<div>Data refreshed every 6 hours by the metrics collector.</div>
|
||||
<div style="margin-top:0.5rem">
|
||||
<a href="https://codeberg.org/johba/disinto">source</a>
|
||||
<a href="http://localhost:3000/johba/disinto">source</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -421,7 +421,7 @@
|
|||
var card = el('div', 'project');
|
||||
var nameDiv = el('div', 'name');
|
||||
var nameLink = document.createElement('a');
|
||||
nameLink.href = 'https://codeberg.org/' + p.repo;
|
||||
nameLink.href = 'http://localhost:3000/' + p.repo;
|
||||
nameLink.textContent = p.name;
|
||||
nameDiv.appendChild(nameLink);
|
||||
card.appendChild(nameDiv);
|
||||
|
|
|
|||
|
|
@ -365,7 +365,7 @@
|
|||
<!-- Eight Agents -->
|
||||
<div class="section">
|
||||
<h2>Eight agents</h2>
|
||||
<p>Each agent has a single responsibility. They communicate through git, the Codeberg API, and the filesystem.</p>
|
||||
<p>Each agent has a single responsibility. They communicate through git, the forge API, and the filesystem.</p>
|
||||
<div class="agents-grid">
|
||||
<div class="agent-card">
|
||||
<div class="name">dev-agent</div>
|
||||
|
|
@ -480,7 +480,7 @@
|
|||
<p><strong>Bash scripts</strong> — every agent is a shell script. No compiled binaries, no runtimes to install.</p>
|
||||
<p><strong>Claude CLI</strong> — AI is invoked via <code>claude -p</code> (one-shot) or <code>claude</code> (persistent tmux sessions).</p>
|
||||
<p><strong>Cron</strong> — agents are triggered by cron jobs, not a daemon. Pull-based, not push-based.</p>
|
||||
<p><strong>Codeberg + Woodpecker</strong> — git hosting and CI. All state lives in git and the issue tracker. No external databases.</p>
|
||||
<p><strong>Forgejo + Woodpecker</strong> — git hosting and CI. All state lives in git and the issue tracker. No external databases.</p>
|
||||
<p><strong>Single VPS</strong> — runs on an 8 GB server. Flat cost, no scaling surprises.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -538,7 +538,7 @@ disinto/
|
|||
<div class="footer">
|
||||
<a href="/">← disinto.ai</a> ·
|
||||
<a href="/docs/quickstart">Quickstart</a> ·
|
||||
<a href="https://codeberg.org/johba/disinto">Source</a>
|
||||
<a href="http://localhost:3000/johba/disinto">Source</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -328,8 +328,8 @@
|
|||
<div class="label">Prerequisites</div>
|
||||
<ul>
|
||||
<li><strong>A VPS or server</strong> — 8 GB RAM minimum (Ubuntu/Debian recommended)</li>
|
||||
<li><strong>A Codeberg account</strong> — with a repo and at least one issue</li>
|
||||
<li><strong>A second Codeberg account</strong> — for the review bot (branch protection requires a different reviewer)</li>
|
||||
<li><strong>A forge instance</strong> — with a repo and at least one issue</li>
|
||||
<li><strong>A second forge instance</strong> — for the review bot (branch protection requires a different reviewer)</li>
|
||||
<li><strong>Woodpecker CI</strong> — running and connected to your repo</li>
|
||||
<li><strong>An Anthropic API key</strong> — with the <code>claude</code> CLI installed and authenticated</li>
|
||||
<li><strong>tmux</strong> — for persistent dev sessions</li>
|
||||
|
|
@ -343,13 +343,13 @@
|
|||
Clone the factory
|
||||
</div>
|
||||
<p>Clone disinto onto your server. This is the factory — the code that runs your agents.</p>
|
||||
<pre><code>git clone https://codeberg.org/johba/disinto.git ~/disinto
|
||||
<pre><code>git clone http://localhost:3000/johba/disinto.git ~/disinto
|
||||
cd ~/disinto
|
||||
cp .env.example .env</code></pre>
|
||||
<p>Edit <code>.env</code> with your tokens:</p>
|
||||
<pre><code><span class="comment"># Required</span>
|
||||
CODEBERG_TOKEN=your_codeberg_token
|
||||
REVIEW_BOT_TOKEN=your_review_bot_token
|
||||
FORGE_TOKEN=your_codeberg_token
|
||||
FORGE_REVIEW_TOKEN=your_review_bot_token
|
||||
|
||||
<span class="comment"># Woodpecker CI</span>
|
||||
WOODPECKER_TOKEN=your_woodpecker_token
|
||||
|
|
@ -365,14 +365,14 @@ CLAUDE_TIMEOUT=7200</code></pre>
|
|||
<span class="step-num">2</span>
|
||||
Initialize your project
|
||||
</div>
|
||||
<p><code>disinto init</code> sets up everything: clones the repo, creates the project config, adds Codeberg labels, and installs cron jobs.</p>
|
||||
<pre><code>bin/disinto init https://codeberg.org/you/your-project</code></pre>
|
||||
<p><code>disinto init</code> provisions a local Forgejo instance, clones the repo, creates the project config, adds labels, and installs cron jobs.</p>
|
||||
<pre><code>bin/disinto init http://localhost:3000/you/your-project</code></pre>
|
||||
<div class="expected">
|
||||
<div class="label">Expected output</div>
|
||||
<code>=== disinto init ===
|
||||
Project: you/your-project
|
||||
Name: your-project
|
||||
Cloning: https://codeberg.org/you/your-project.git -> /home/you/your-project
|
||||
Cloning: http://localhost:3000/you/your-project.git -> /home/you/your-project
|
||||
Branch: main
|
||||
Created: /home/you/disinto/projects/your-project.toml
|
||||
Creating labels on you/your-project...
|
||||
|
|
@ -406,7 +406,7 @@ Done. Project your-project is ready.</code>
|
|||
<ol>
|
||||
<li><strong>A CI pipeline</strong> — at least one <code>.woodpecker/*.yml</code> file. Agents wait for CI before reviewing or merging.</li>
|
||||
<li><strong>A CLAUDE.md</strong> — project context that agents read before every task. Describe your tech stack, how to build/test, coding conventions, and directory layout.</li>
|
||||
<li><strong>Branch protection</strong> — on Codeberg, require PR reviews and add the review bot as a write collaborator.</li>
|
||||
<li><strong>Branch protection</strong> — on Forgejo, require PR reviews and add the review bot as a write collaborator.</li>
|
||||
</ol>
|
||||
<pre><code><span class="comment"># Create CLAUDE.md in your project</span>
|
||||
cat > ~/your-project/CLAUDE.md <<'EOF'
|
||||
|
|
@ -434,7 +434,7 @@ git push</code></pre>
|
|||
<span class="step-num">4</span>
|
||||
File your first issue
|
||||
</div>
|
||||
<p>Create an issue on Codeberg with the <code>backlog</code> label. Be specific — the dev-agent works best with clear acceptance criteria.</p>
|
||||
<p>Create an issue on the forge with the <code>backlog</code> label. Be specific — the dev-agent works best with clear acceptance criteria.</p>
|
||||
<pre><code><span class="comment"># Title: Add health check endpoint</span>
|
||||
<span class="comment"># Label: backlog</span>
|
||||
<span class="comment"># Body:</span>
|
||||
|
|
@ -523,7 +523,7 @@ git log --oneline -5</code></pre>
|
|||
<div class="footer">
|
||||
<a href="/">← disinto.ai</a> ·
|
||||
<a href="/docs/architecture">Architecture</a> ·
|
||||
<a href="https://codeberg.org/johba/disinto">Source</a>
|
||||
<a href="http://localhost:3000/johba/disinto">Source</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -661,7 +661,7 @@
|
|||
<p>
|
||||
<strong>Bash scripts and Claude.</strong> No Kubernetes, no microservices,
|
||||
no SaaS dependencies. Runs on an 8GB VPS.
|
||||
Point it at a <strong>Codeberg repo</strong> with a
|
||||
Point it at a <strong>forge repo</strong> with a
|
||||
<strong>Woodpecker CI</strong> pipeline and it starts building.
|
||||
</p>
|
||||
<p>
|
||||
|
|
@ -691,8 +691,8 @@
|
|||
<div class="cta-links">
|
||||
<a href="/docs/quickstart">Quickstart</a>
|
||||
<a href="/docs/architecture">Architecture</a>
|
||||
<a href="https://codeberg.org/johba/disinto">Browse the source</a>
|
||||
<a href="https://codeberg.org/johba/disinto/issues">See active issues</a>
|
||||
<a href="http://localhost:3000/johba/disinto">Browse the source</a>
|
||||
<a href="http://localhost:3000/johba/disinto/issues">See active issues</a>
|
||||
<a href="/dashboard">Live dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -702,7 +702,7 @@
|
|||
<div class="links">
|
||||
<a href="/docs/quickstart">quickstart</a>
|
||||
<a href="/docs/architecture">architecture</a>
|
||||
<a href="https://codeberg.org/johba/disinto">source</a>
|
||||
<a href="http://localhost:3000/johba/disinto">source</a>
|
||||
<a href="/dashboard">dashboard</a>
|
||||
</div>
|
||||
<div class="under-hood">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue