diff --git a/.env.example b/.env.example index d35bff2..3f3a523 100644 --- a/.env.example +++ b/.env.example @@ -22,29 +22,27 @@ CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-vervang-mij # Als deze ge-revoked wordt: rebuild + redeploy (zie README). SCRUM4ME_TOKEN=vervang-mij -# ----- Forgejo credentials (PBI-86 hybride model) ----------- -# Personal Access Token van je Forgejo-account met scope read+write -# op de Scrum4Me-repos. Variabele heet historisch nog `GH_TOKEN`; -# in het hybride model bevat 'ie een Forgejo-PAT. +# ----- GitHub credentials ----------------------------------- +# Personal Access Token (fine-grained) met: +# - Repository access op madhura68/Scrum4Me + madhura68/scrum4me-mcp +# - Permissions: Contents (read/write), Pull requests (read/write), +# Metadata (read) # # Gebruikt voor: # 1. Pre-clone van de repos in /home/agent/Projects// bij # container-start (entrypoint.sh) -# 2. `git push` van agent feature-branches naar Forgejo via HTTPS +# 2. `git push` van agent feature-branches via HTTPS +# 3. `gh pr create` (auto_pr=true) — gh CLI leest GH_TOKEN uit env # -# `gh pr create` is uit de worker-flow verwijderd (PBI-86, T-1005); -# de GitHub-PR ontstaat via de handmatig getriggerde promote-Action -# in Forgejo. -# -# Genereer in Forgejo: avatar → Settings → Applications → -# Generate New Token; scope minimaal `write:repository`. -GH_TOKEN=vervang-mij +# Genereer op github.com → Settings → Developer settings → +# Personal access tokens → Fine-grained tokens. +GH_TOKEN=ghp_vervang-mij # Lijst (komma-gescheiden) van repos om vooraf te clonen naar # ~agent/Projects/. resolveRepoRoot in scrum4me-mcp valt -# automatisch terug op die conventie. `/` zoals 'ie op -# Forgejo staat. Voeg meer toe als je nieuwe producten/repos toevoegt. -GH_PRECLONE_REPOS=janpeter/Scrum4Me,janpeter/scrum4me-mcp +# automatisch terug op die conventie. Voeg meer toe als je nieuwe +# producten/repos toevoegt aan Scrum4Me. +GH_PRECLONE_REPOS=madhura68/Scrum4Me,madhura68/scrum4me-mcp # ----- Git commit-author ------------------------------------- # Verplicht — Vercel weigert deploys waarvan de commit-author email @@ -110,9 +108,3 @@ AGENT_BACKOFF_MAX=300 AGENT_LOG_GZIP_AFTER_HOURS=24 # Hoeveel dagen ge-gzipte logs bewaren voor we ze verwijderen. AGENT_LOG_DELETE_AFTER_DAYS=30 - -# Claude CLI --output-format. Default 'stream-json' streamt de volledige -# event-stream (tool-calls, berichten) live naar de run-log; 'text' geeft -# alleen Claude's eind-samenvatting (terser, maar geen live-meekijken). -# stream-json maakt de run-log JSONL — gebruik jq of een viewer. -AGENT_CLAUDE_OUTPUT_FORMAT=stream-json diff --git a/Dockerfile b/Dockerfile index 683202d..98fe2b2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -53,7 +53,7 @@ RUN curl -fsSL https://claude.ai/install.sh | bash -s ${CLAUDE_CODE_VERSION} \ # Clone zonder submodules — de Prisma-schema zit al gecommit in het repo. # De vendor/scrum4me submodule is alleen nodig om het schema te updaten, # niet om te builden. Pin via build-arg; default = main. -ARG MCP_GIT_REPO=https://git.jp-visser.nl/janpeter/scrum4me-mcp.git +ARG MCP_GIT_REPO=https://github.com/madhura68/scrum4me-mcp.git ARG MCP_GIT_REF=main # Cache-bust voor de clone-laag: hetzelfde MCP_GIT_REF kan tussen rebuilds # een ander commit aanwijzen (bv. main na een merge). Geef als build-arg diff --git a/README.md b/README.md index 0f9cd3d..825abe7 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ fouten. `/share/Agent → /share/CACHEDEV1_DATA/Agent`. - Drie subdirs onder die share: `/share/Agent/cache`, `/share/Agent/logs`, `/share/Agent/state`. Aanmaken via File Station of via SSH na share-creatie. -- Internet-uitgang naar `api.anthropic.com`, `git.jp-visser.nl` (Forgejo HTTPS-clone/push), `cli.github.com` (build-time voor de gh CLI), je Neon-host, `registry.npmjs.org`. +- Internet-uitgang naar `api.anthropic.com`, `github.com`, je Neon-host, `registry.npmjs.org`. > **Verifieer** vóór je deployt dat `/share/Agent` echt op disk staat: > ```bash @@ -85,21 +85,18 @@ fouten. # b. SCRUM4ME_TOKEN → log in als de dedicated agent-user in # Scrum4Me, /settings/tokens, label "NAS-runner" # c. DATABASE_URL/DIRECT_URL → Neon dashboard -# d. GH_TOKEN → Forgejo → avatar → Settings → -# Applications → Generate New Token; scope -# minimaal `write:repository` op de twee -# repos (janpeter/Scrum4Me + janpeter/ -# scrum4me-mcp). Wordt gebruikt voor clone -# en push naar Forgejo. PBI-86 (hybride -# model): `gh pr create` is uit de -# worker-flow verwijderd — de GitHub-PR -# komt via de handmatige promote-Action -# in Forgejo. +# d. GH_TOKEN → github.com → Settings → Developer settings → +# Personal access tokens → Fine-grained. +# Repository access op madhura68/Scrum4Me + +# madhura68/scrum4me-mcp; Permissions: +# Contents (RW), Pull requests (RW), +# Metadata (R). Wordt gebruikt voor clone, +# push en `gh pr create` (auto_pr). # 2. Repo op de NAS plaatsen ssh admin@nas cd /share/Agent -git clone https://git.jp-visser.nl//scrum4me-agent-runner.git +git clone https://github.com//scrum4me-agent-runner.git cd scrum4me-agent-runner # 3. Env aanmaken @@ -329,8 +326,7 @@ Bij elke container-start runt `bin/repo-bootstrap.sh` (als de `agent`-user, ná drop-privileges) en zet zo'n setup neer: 1. Configureert git's credential-helper met `GH_TOKEN` zodat - `git clone`/`push` naar `https://git.jp-visser.nl/...` (Forgejo) zonder - prompt werkt. + `git clone`/`push` naar `https://github.com/...` zonder prompt werkt. 2. Voor elke repo in `GH_PRECLONE_REPOS` (komma-gescheiden owner/name): - Bestaat `~/Projects//.git` al? → `git fetch origin --prune` - Anders → fresh `git clone` @@ -341,10 +337,8 @@ voor jobs landen vervolgens onder `~/.scrum4me-agent-worktrees//` zodat de hoofd-clone niet wordt aangeraakt. Push gaat over dezelfde token: `git push -u origin feat/story-` -slaagt zonder prompt. **`gh pr create` is in PBI-86 (T-1005) verwijderd -uit de worker-flow** — de GitHub-PR ontstaat via een handmatig -getriggerde promote-Action in Forgejo (zie de Scrum4Me-repo -`docs/runbooks/forgejo-hybrid-flow.md`). +slaagt zonder prompt. `gh pr create` (voor producten met `auto_pr=true`) +gebruikt dezelfde `GH_TOKEN` via de `gh` CLI's standaard env-detect. ## Veelvoorkomende issues diff --git a/bin/job-prepare.sh b/bin/job-prepare.sh index f3ec175..96f54c4 100644 --- a/bin/job-prepare.sh +++ b/bin/job-prepare.sh @@ -28,7 +28,7 @@ if [[ -z "$JOB_ID" || -z "$REPO_URL" ]]; then exit 2 fi -# Slug uit repo_url voor de cache-naam: "git.jp-visser.nl/foo/bar.git" → "foo_bar" +# Slug uit repo_url voor de cache-naam: "github.com/foo/bar.git" → "foo_bar" SLUG=$(echo "$REPO_URL" \ | sed -E 's#^.*[:/]([^/]+/[^/]+?)(\.git)?/?$#\1#' \ | tr '/' '_') diff --git a/bin/repo-bootstrap.sh b/bin/repo-bootstrap.sh index 7f71c53..850c42f 100644 --- a/bin/repo-bootstrap.sh +++ b/bin/repo-bootstrap.sh @@ -32,8 +32,8 @@ fi mkdir -p "$HOME" git config --global credential.helper store CREDS_FILE="$HOME/.git-credentials" -if [[ ! -f "$CREDS_FILE" ]] || ! grep -q "oauth2:${GH_TOKEN}@git.jp-visser.nl" "$CREDS_FILE" 2>/dev/null; then - printf 'https://oauth2:%s@git.jp-visser.nl\n' "$GH_TOKEN" > "$CREDS_FILE" +if [[ ! -f "$CREDS_FILE" ]] || ! grep -q "oauth2:${GH_TOKEN}@github.com" "$CREDS_FILE" 2>/dev/null; then + printf 'https://oauth2:%s@github.com\n' "$GH_TOKEN" > "$CREDS_FILE" chmod 600 "$CREDS_FILE" log "git credentials helper configured at ${CREDS_FILE}" fi @@ -71,7 +71,7 @@ for repo in "${REPOS[@]}"; do else log "cloning ${repo} into ${target}" rm -rf "$target" - git clone --quiet "https://git.jp-visser.nl/${repo}.git" "$target" \ + git clone --quiet "https://github.com/${repo}.git" "$target" \ || { log "ERROR: clone failed for ${repo}"; continue; } fi done diff --git a/bin/run-agent.sh b/bin/run-agent.sh index 6b3dd32..52c6f49 100644 --- a/bin/run-agent.sh +++ b/bin/run-agent.sh @@ -80,12 +80,8 @@ while true; do # Token-expiry detectie: run-one-job.ts retourneert exit 3 wanneer het # bekende auth-error-strings in Claude's output ziet. We checken óók de # log-tekst voor het geval een ander pad het patroon raakt (bv. Prisma- - # connection-error met OAuth-expired in error-body) — maar alléén bij een - # niet-nul exit. Het run-log bevat de volledige stream-json output (incl. - # tool-results én run-one-job's eigen "TOKEN_EXPIRED detected"-logregel), - # dus een geslaagde job die toevallig "401 unauthorized" in z'n output - # heeft mag de grep-fallback niet triggeren. - if [[ "$exit_code" -eq 3 ]] || { [[ "$exit_code" -ne 0 ]] && grep -qE '(invalid_api_key|authentication.*failed|401.*unauthor|OAuth.*expired)' "${run_log}"; }; then + # connection-error met OAuth-expired in error-body). + if [[ "$exit_code" -eq 3 ]] || grep -qE '(invalid_api_key|authentication.*failed|401.*unauthor|OAuth.*expired)' "${run_log}"; then log "AUTH FAILURE detected (exit=$exit_code or pattern in log) — marking TOKEN_EXPIRED" touch "${AGENT_STATE_DIR}/TOKEN_EXPIRED" write_state "$(jq -n \ diff --git a/bin/run-one-job.ts b/bin/run-one-job.ts index f9cc879..cd0919c 100644 --- a/bin/run-one-job.ts +++ b/bin/run-one-job.ts @@ -292,13 +292,6 @@ async function main(): Promise { // 7. Build CLI args. const promptText = getKindPromptText(ctx.kind).replace('$PAYLOAD_PATH', payloadPath) - // --output-format is configureerbaar via env. Default 'stream-json' geeft - // de volledige event-stream (elke tool-call, elk bericht) live in de - // run-log, i.p.v. alleen Claude's eind-samenvatting. stream-json vereist - // --verbose in print-mode. Zet AGENT_CLAUDE_OUTPUT_FORMAT=text terug voor - // de oude terse output. TOKEN_EXPIRED-detectie werkt ongewijzigd: de - // auth-error-strings staan ook binnen de JSON-events. - const outputFormat = process.env.AGENT_CLAUDE_OUTPUT_FORMAT ?? 'stream-json' const args: string[] = [ '-p', promptText, @@ -313,9 +306,8 @@ async function main(): Promise { '--add-dir', '/opt/agent', '--output-format', - outputFormat, + 'text', ] - if (outputFormat === 'stream-json') args.push('--verbose') if (effort) args.push('--effort', effort) const cwd = worktreePath ?? '/opt/agent' @@ -383,21 +375,13 @@ async function main(): Promise { `duration_ms=${durationMs} wall_clock_seconds=${Math.round(durationMs / 1000)}`, ) - // 10. Token-expiry detection — alleen als Claude zelf non-zero eindigde. - // stdoutBuf bevat de volledige stream-json output incl. álle tool-results, - // dus de auth-error-strings kunnen ook agent-werk-content zijn (een doc - // over 401-handling gelezen, een endpoint getest). Een echte credential- - // fout laat 'claude' non-zero exiten; een geslaagde run (exit 0) is per - // definitie geen token-expiry. Zonder deze gate legt zulke content de - // worker onterecht plat (run-agent.sh → TOKEN_EXPIRED marker + sleep). + // 10. Token-expiry detection. let tokenExpired = false - if (exitCode !== 0) { - for (const pat of TOKEN_EXPIRY_PATTERNS) { - if (pat.test(stdoutBuf)) { - tokenExpired = true - log(`TOKEN_EXPIRED detected pattern="${pat.source}" exiting code=3`) - break - } + for (const pat of TOKEN_EXPIRY_PATTERNS) { + if (pat.test(stdoutBuf)) { + tokenExpired = true + log(`TOKEN_EXPIRED detected pattern="${pat.source}" exiting code=3`) + break } }