Commit graph

35 commits

Author SHA1 Message Date
openhands
54ce91e09e fix: fix: create_labels creates duplicate labels on re-run — no idempotency check (#683)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 15:35:31 +00:00
openhands
26df57da18 fix: skip push when local repo has no commits (empty clone)
The smoke test clones from an empty Forgejo repo, so there are no
refs to push. Skip the push and verification gracefully when HEAD
does not resolve.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 15:23:02 +00:00
openhands
f8c8769af3 fix: fix: disinto init does not push repo to local Forgejo — repo stays empty (#682)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 15:20:53 +00:00
openhands
07616df8a5 fix: fix: Dendrite crash-loops — missing dendrite.yaml config file (#681)
Remove Dendrite from the default docker-compose.yml generated by
`disinto init`. Most deployments don't need Matrix, so Dendrite is now
opt-in via the `--matrix` flag.

When `--matrix` is passed:
- A minimal dendrite.yaml is generated at docker/dendrite/dendrite.yaml
- The Dendrite service is appended to docker-compose.yml with the
  config file bind-mounted
- setup_matrix() provisions the bot user and coordination room

Without `--matrix`, no Dendrite container is started and fresh inits
no longer crash-loop.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 15:08:55 +00:00
openhands
0908ddb521 fix: fix: Woodpecker image uses :latest tag which no longer exists — container crash-loops (#680)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 14:55:00 +00:00
openhands
a414bc8b24 fix: disinto init should activate dev, reviewer, and gardener agents by default (#671)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 14:20:09 +00:00
openhands
8b8e29e071 fix: feat: add Woodpecker agent to docker-compose stack — enable CI pipeline execution (#670)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 14:07:27 +00:00
openhands
e411eb224c fix: Forgejo 11.x ignores --must-change-password=false — token creation fails with password change required (#665)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:50:08 +00:00
openhands
c643cf16dc fix: use basic auth for bot token creation — Forgejo rejects token auth (#668)
POST /api/v1/users/{username}/tokens requires basic auth (reqBasicOrRevProxyAuth)
in Forgejo 11.x. The previous code used admin token auth which returns 401.

Fix: authenticate as the bot user with -u "${bot_user}:${bot_pass}" instead of
-H "Authorization: token ${admin_token}". The bot_pass is available in scope
from the user creation step.

Bug caught by the new smoke-init end-to-end test.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:06:01 +00:00
openhands
c02a0b29d2 fix: fix: Woodpecker CI not wired during disinto init — OAuth2 app never created, no CI runs (#661)
Split setup_woodpecker() into create_woodpecker_oauth() (pre-compose) and
activate_woodpecker_repo() (post-compose) so OAuth2 creds are in .env before
Woodpecker starts, and repo activation happens after the stack is up.

- Add ports: ["8000:8000"] to Woodpecker service in generate_compose()
- Fix .env var names: WP_FORGEJO_CLIENT/SECRET to match compose references
- Reorder disinto_init(): OAuth2 creation before compose up, repo activation after
- activate_woodpecker_repo() polls Woodpecker readiness with retry loop

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 07:43:59 +00:00
openhands
b361eba2bb fix: setup_forge silently fails to create users and tokens — .env has no FORGE_TOKEN after init (#658)
Add database readiness check (retry loop on `forgejo admin user list`) after
API becomes reachable to avoid the race where HTTP is up but SQLite isn't
accepting writes yet.

Remove `2>/dev/null || true` from user creation commands so failures are
logged with the actual error message. Verify each user exists via API after
creation. Fail init with a clear error if admin token, bot user creation,
or bot token creation fails — instead of silently writing an incomplete .env.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 06:51:47 +00:00
johba
632508e18e fix: bind-mount host Claude credentials instead of empty Docker volume
Replace the claude-auth named Docker volume with bind mounts to the host
user's ~/.claude/ and ~/.claude.json. The named volume creates an empty
directory, so the agents container cannot authenticate with Claude CLI.

Bind-mounting from ${HOME} ensures the container picks up existing
credentials without manual intervention.

Closes codeberg.org/johba/disinto/issues/633

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 05:42:50 +00:00
openhands
a0cdf87a21 fix: move setup_matrix after compose up, use Python for .env writes
- Critical: setup_matrix now runs after docker compose up -d so Dendrite
  is actually running when provisioning is attempted
- Minor: replace sed with Python for .env credential writes to avoid
  delimiter collisions with opaque Matrix access tokens
- Info: update matrix_listener.sh header to mention container mode

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 00:35:20 +00:00
openhands
b86edd7e5d fix: Add Dendrite to docker-compose stack (#619)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 00:28:04 +00:00
openhands
bc2df1a2c7 fix: disinto init fails on minimal Debian — crontab command not found (#638)
In compose mode, skip host cron installation entirely since the agents
container runs cron internally via entrypoint.sh. In bare mode, check
for crontab before attempting to install entries and produce a clear
error with install instructions if missing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 22:40:35 +00:00
openhands
7844b29a37 fix: agents Dockerfile fails to build — cli.anthropic.com DNS does not resolve (#637)
- Remove curl|sh Claude CLI download from Dockerfile (no internet needed)
- Mount host Claude CLI binary into container via docker-compose volume
- generate_compose() resolves host claude path at init time
- entrypoint.sh fails fast with clear error if claude CLI is missing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 22:26:26 +00:00
openhands
f30c56769a fix: setup_forge runs forgejo admin commands as root — Forgejo refuses to execute (#636)
Add -u git to docker exec and docker compose exec calls in _forgejo_exec()
so Forgejo admin commands run as the git user instead of root.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 22:15:00 +00:00
openhands
0b54f5e9e9 fix: Docker-in-LXD — su-exec spins at 100% CPU due to AppArmor blocking setuid (#635)
Add security_opt: [apparmor=unconfined] to all three compose services
(forgejo, woodpecker, agents) in generate_compose(). This prevents
su-exec from entering an infinite CPU loop when Docker runs inside an
LXD container whose default AppArmor profile blocks setuid/execve.
Harmless on bare-metal Docker hosts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 22:05:14 +00:00
openhands
5a9ceee1ad fix: Forgejo compose template missing INSTALL_LOCK — API returns 404 until manual install (#634)
Add FORGEJO__security__INSTALL_LOCK: "true" to the forgejo service
environment in generate_compose(). Without this, Forgejo starts in
install-wizard mode and the API returns 404 for all endpoints.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 21:55:02 +00:00
openhands
d3896043d6 fix: docker-compose uses forgejo/forgejo:latest which does not exist on any registry (#633)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 21:45:17 +00:00
openhands
4f99a7a26a fix: Clean up decrypted secrets on failure, verify Claude CLI install (#618)
Add EXIT trap in disinto_up() so the plaintext .env is removed even if
docker compose up fails.  Previously set -euo pipefail would abort
before the cleanup block, leaving secrets on disk.

Replace the silent || true in the Dockerfile with an explicit
claude --version check so the build fails visibly if the CLI cannot
be installed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 20:36:55 +00:00
openhands
0aa3890fb8 fix: Start cron daemon in agent container entrypoint (#618)
The entrypoint installed a crontab but never started a cron daemon,
leaving the container idle.  Fix by running as root in the entrypoint
(cron requires it), installing the crontab for the agent user via
`crontab -u agent`, and starting cron in the foreground with `cron -f`.
Remove `USER agent` from the Dockerfile and `user: "1000:1000"` from
the compose template accordingly — cron jobs still execute as UID 1000.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 20:30:44 +00:00
openhands
e38866ab61 fix: Containerize full stack with docker-compose (#618)
Add docker-compose.yml generation, agent Dockerfile, and new CLI
commands (up/down/logs/shell) so the full stack runs containerized.
The --bare flag preserves the current bare-metal setup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 18:53:55 +00:00
openhands
7bc74caa63 fix: Push to public mirrors after merge (#614)
Add fire-and-forget mirror push support so merges to the primary branch
are automatically pushed to configured public mirrors (GitHub, Codeberg,
etc.). Mirror failures are logged but never block the pipeline.

- lib/mirrors.sh: new shared mirror_push() helper
- lib/load-project.sh: parse [mirrors] TOML section into MIRROR_* env vars
- dev/phase-handler.sh: call mirror_push after do_merge() success
- dev/dev-poll.sh: call mirror_push after try_direct_merge() success
- gardener/gardener-run.sh: call mirror_push after _gardener_merge() success
- bin/disinto: set up mirror remotes during init, add commented mirrors to
  generated TOML
- projects/*.toml.example: show [mirrors] section (commented out)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 19:19:16 +00:00
openhands
3e2f8f9623 fix: Address review feedback on SOPS integration (#613)
- Warn on stderr when .env.enc decryption fails instead of silent || true
- Guard ensure_age_key() against empty age-keygen -y output
- Fix stale comment on write_secrets_encrypted()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 19:04:58 +00:00
openhands
5ccf09b28d fix: Encrypt secrets at rest with SOPS + age (#613)
- lib/env.sh: Two-tier secret loader (SOPS .env.enc > plaintext .env),
  remove ~/.netrc fallback
- bin/disinto: Add age key generation and SOPS encryption during init,
  remove write_netrc(), add `disinto secrets` subcommand (edit/show/migrate),
  add sops+age to preflight warnings
- .env.example: Annotate vars as [SECRET] or [CONFIG]
- .gitignore: Allow .env.enc and .sops.yaml to be committed
- BOOTSTRAP.md: Document SOPS + age setup, key backup, secret management
- AGENTS.md: Update AD-005 and coding conventions for .env.enc

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 18:58:33 +00:00
openhands
50dff34b89 fix: Wire Woodpecker CI to local Forgejo (#612)
Add ci_commit_status() and ci_pipeline_number() helpers to
lib/ci-helpers.sh that query Woodpecker directly with a forge API
fallback. Replace all 12 inline forge commit status calls across 6
files with the new helpers.

Add setup_woodpecker() to bin/disinto init that creates a Forgejo
OAuth2 app for Woodpecker and activates the repo.

Document manual Woodpecker+Forgejo setup in BOOTSTRAP.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 17:19:01 +00:00
openhands
a66bd91721 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>
2026-03-23 16:57:12 +00:00
openhands
1265fa2d3b fix: preflight API check uses /user endpoint which requires read:user scope (#569)
Replace /api/v1/user with /api/v1/repos/{owner}/{repo} in three places:
- preflight_check() auth verification
- setup_codeberg_auth() --token flag verification
- setup_codeberg_auth() interactive flow verification

The repo endpoint only requires repo-level access, which matches the
scopes disinto actually needs (write:issue, write:repository). Tokens
without read:user scope now pass verification correctly.

Also use generic "token" as netrc login since the username is no longer
retrieved from the API (git operations authenticate via the token, not
the login field).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 20:07:20 +00:00
openhands
5796516a1d fix: feat: disinto init should interactively set up Codeberg auth with guided token creation (#566)
Add interactive Codeberg auth setup to `disinto init`:
- Guide user through token creation with URL and required scopes
- Save token to ~/.netrc with correct permissions (600)
- Verify token via API call before proceeding
- Support --token flag for non-interactive use
- Backwards compatible: existing CODEBERG_TOKEN / .netrc still work

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 19:32:13 +00:00
openhands
140a857319 fix: address review — netrc curl flag and claude auth error handling
- Add --netrc flag to curl when CODEBERG_TOKEN is unset so ~/.netrc
  auth users don't get false-positive API failures
- Check claude auth status exit code separately; only skip the check
  when the subcommand is unrecognized (old claude version), otherwise
  treat failures as auth errors

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 19:23:22 +00:00
openhands
01d780303f fix: disinto init needs a system requirements preflight check (#564)
Replace validate_env() with preflight_check() that verifies all factory
requirements before init proceeds:

- Required tools: claude, tmux, git, jq, python3, curl (hard errors)
- Claude Code authentication via claude auth status
- Codeberg auth: CODEBERG_TOKEN or ~/.netrc, verified with API call
- Codeberg SSH access: verified with ssh -T git@codeberg.org
- Optional: docker (warn only)
- Clear error messages with install hints for each missing tool

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 17:45:38 +00:00
openhands
a03c277f8d fix: address review — auto-update TOML in --yes mode, use python3 for safe write
- When --yes is passed with a differing --repo-root, auto-apply the TOML
  update instead of silently skipping. Prevents stale repo_root in TOML.
- Replace sed with python3+re for updating repo_root to avoid delimiter
  injection from user-supplied paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 15:54:35 +00:00
openhands
f92efd2fcf fix: fix: disinto init fails when projects/<name>.toml already exists in repo (#559)
When projects/<name>.toml already exists (e.g. committed from another box),
skip TOML generation and continue with remaining setup steps (clone repo,
create labels, install cron). Reads repo_root and branch from the existing
TOML. If --repo-root flag differs from TOML value, prompts to update it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 15:40:49 +00:00
openhands
6dfd2946ef fix: feat: disinto init — one-command project bootstrap (#393)
Add bin/disinto CLI entry point with two subcommands:

- `disinto init <repo-url>`: bootstraps a new project by cloning the
  repo, generating a projects/*.toml config, creating Codeberg labels
  (backlog, in-progress, blocked, tech-debt, underspecified, vision,
  action), generating a VISION.md template, and installing cron jobs
  for dev-poll, review-poll, and gardener.

- `disinto status`: shows active sessions, backlog depth, and open PR
  count for all configured projects.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 13:49:04 +00:00