Compare commits
No commits in common. "master" and "claude/determined-wright-14cfbf" have entirely different histories.
master
...
claude/det
8 changed files with 41 additions and 102 deletions
34
.env.example
34
.env.example
|
|
@ -22,29 +22,27 @@ CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-vervang-mij
|
||||||
# Als deze ge-revoked wordt: rebuild + redeploy (zie README).
|
# Als deze ge-revoked wordt: rebuild + redeploy (zie README).
|
||||||
SCRUM4ME_TOKEN=vervang-mij
|
SCRUM4ME_TOKEN=vervang-mij
|
||||||
|
|
||||||
# ----- Forgejo credentials (PBI-86 hybride model) -----------
|
# ----- GitHub credentials -----------------------------------
|
||||||
# Personal Access Token van je Forgejo-account met scope read+write
|
# Personal Access Token (fine-grained) met:
|
||||||
# op de Scrum4Me-repos. Variabele heet historisch nog `GH_TOKEN`;
|
# - Repository access op madhura68/Scrum4Me + madhura68/scrum4me-mcp
|
||||||
# in het hybride model bevat 'ie een Forgejo-PAT.
|
# - Permissions: Contents (read/write), Pull requests (read/write),
|
||||||
|
# Metadata (read)
|
||||||
#
|
#
|
||||||
# Gebruikt voor:
|
# Gebruikt voor:
|
||||||
# 1. Pre-clone van de repos in /home/agent/Projects/<name>/ bij
|
# 1. Pre-clone van de repos in /home/agent/Projects/<name>/ bij
|
||||||
# container-start (entrypoint.sh)
|
# 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);
|
# Genereer op github.com → Settings → Developer settings →
|
||||||
# de GitHub-PR ontstaat via de handmatig getriggerde promote-Action
|
# Personal access tokens → Fine-grained tokens.
|
||||||
# in Forgejo.
|
GH_TOKEN=ghp_vervang-mij
|
||||||
#
|
|
||||||
# Genereer in Forgejo: avatar → Settings → Applications →
|
|
||||||
# Generate New Token; scope minimaal `write:repository`.
|
|
||||||
GH_TOKEN=vervang-mij
|
|
||||||
|
|
||||||
# Lijst (komma-gescheiden) van repos om vooraf te clonen naar
|
# Lijst (komma-gescheiden) van repos om vooraf te clonen naar
|
||||||
# ~agent/Projects/<name>. resolveRepoRoot in scrum4me-mcp valt
|
# ~agent/Projects/<name>. resolveRepoRoot in scrum4me-mcp valt
|
||||||
# automatisch terug op die conventie. `<owner>/<repo>` zoals 'ie op
|
# automatisch terug op die conventie. Voeg meer toe als je nieuwe
|
||||||
# Forgejo staat. Voeg meer toe als je nieuwe producten/repos toevoegt.
|
# producten/repos toevoegt aan Scrum4Me.
|
||||||
GH_PRECLONE_REPOS=janpeter/Scrum4Me,janpeter/scrum4me-mcp
|
GH_PRECLONE_REPOS=madhura68/Scrum4Me,madhura68/scrum4me-mcp
|
||||||
|
|
||||||
# ----- Git commit-author -------------------------------------
|
# ----- Git commit-author -------------------------------------
|
||||||
# Verplicht — Vercel weigert deploys waarvan de commit-author email
|
# Verplicht — Vercel weigert deploys waarvan de commit-author email
|
||||||
|
|
@ -110,9 +108,3 @@ AGENT_BACKOFF_MAX=300
|
||||||
AGENT_LOG_GZIP_AFTER_HOURS=24
|
AGENT_LOG_GZIP_AFTER_HOURS=24
|
||||||
# Hoeveel dagen ge-gzipte logs bewaren voor we ze verwijderen.
|
# Hoeveel dagen ge-gzipte logs bewaren voor we ze verwijderen.
|
||||||
AGENT_LOG_DELETE_AFTER_DAYS=30
|
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
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
# Clone zonder submodules — de Prisma-schema zit al gecommit in het repo.
|
||||||
# De vendor/scrum4me submodule is alleen nodig om het schema te updaten,
|
# De vendor/scrum4me submodule is alleen nodig om het schema te updaten,
|
||||||
# niet om te builden. Pin via build-arg; default = main.
|
# 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
|
ARG MCP_GIT_REF=main
|
||||||
# Cache-bust voor de clone-laag: hetzelfde MCP_GIT_REF kan tussen rebuilds
|
# 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
|
# een ander commit aanwijzen (bv. main na een merge). Geef als build-arg
|
||||||
|
|
|
||||||
30
README.md
30
README.md
|
|
@ -66,7 +66,7 @@ fouten.
|
||||||
`/share/Agent → /share/CACHEDEV1_DATA/Agent`.
|
`/share/Agent → /share/CACHEDEV1_DATA/Agent`.
|
||||||
- Drie subdirs onder die share: `/share/Agent/cache`, `/share/Agent/logs`,
|
- Drie subdirs onder die share: `/share/Agent/cache`, `/share/Agent/logs`,
|
||||||
`/share/Agent/state`. Aanmaken via File Station of via SSH na share-creatie.
|
`/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:
|
> **Verifieer** vóór je deployt dat `/share/Agent` echt op disk staat:
|
||||||
> ```bash
|
> ```bash
|
||||||
|
|
@ -85,21 +85,18 @@ fouten.
|
||||||
# b. SCRUM4ME_TOKEN → log in als de dedicated agent-user in
|
# b. SCRUM4ME_TOKEN → log in als de dedicated agent-user in
|
||||||
# Scrum4Me, /settings/tokens, label "NAS-runner"
|
# Scrum4Me, /settings/tokens, label "NAS-runner"
|
||||||
# c. DATABASE_URL/DIRECT_URL → Neon dashboard
|
# c. DATABASE_URL/DIRECT_URL → Neon dashboard
|
||||||
# d. GH_TOKEN → Forgejo → avatar → Settings →
|
# d. GH_TOKEN → github.com → Settings → Developer settings →
|
||||||
# Applications → Generate New Token; scope
|
# Personal access tokens → Fine-grained.
|
||||||
# minimaal `write:repository` op de twee
|
# Repository access op madhura68/Scrum4Me +
|
||||||
# repos (janpeter/Scrum4Me + janpeter/
|
# madhura68/scrum4me-mcp; Permissions:
|
||||||
# scrum4me-mcp). Wordt gebruikt voor clone
|
# Contents (RW), Pull requests (RW),
|
||||||
# en push naar Forgejo. PBI-86 (hybride
|
# Metadata (R). Wordt gebruikt voor clone,
|
||||||
# model): `gh pr create` is uit de
|
# push en `gh pr create` (auto_pr).
|
||||||
# worker-flow verwijderd — de GitHub-PR
|
|
||||||
# komt via de handmatige promote-Action
|
|
||||||
# in Forgejo.
|
|
||||||
|
|
||||||
# 2. Repo op de NAS plaatsen
|
# 2. Repo op de NAS plaatsen
|
||||||
ssh admin@nas
|
ssh admin@nas
|
||||||
cd /share/Agent
|
cd /share/Agent
|
||||||
git clone https://git.jp-visser.nl/<jij>/scrum4me-agent-runner.git
|
git clone https://github.com/<jij>/scrum4me-agent-runner.git
|
||||||
cd scrum4me-agent-runner
|
cd scrum4me-agent-runner
|
||||||
|
|
||||||
# 3. Env aanmaken
|
# 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:
|
`agent`-user, ná drop-privileges) en zet zo'n setup neer:
|
||||||
|
|
||||||
1. Configureert git's credential-helper met `GH_TOKEN` zodat
|
1. Configureert git's credential-helper met `GH_TOKEN` zodat
|
||||||
`git clone`/`push` naar `https://git.jp-visser.nl/...` (Forgejo) zonder
|
`git clone`/`push` naar `https://github.com/...` zonder prompt werkt.
|
||||||
prompt werkt.
|
|
||||||
2. Voor elke repo in `GH_PRECLONE_REPOS` (komma-gescheiden owner/name):
|
2. Voor elke repo in `GH_PRECLONE_REPOS` (komma-gescheiden owner/name):
|
||||||
- Bestaat `~/Projects/<name>/.git` al? → `git fetch origin --prune`
|
- Bestaat `~/Projects/<name>/.git` al? → `git fetch origin --prune`
|
||||||
- Anders → fresh `git clone`
|
- Anders → fresh `git clone`
|
||||||
|
|
@ -341,10 +337,8 @@ voor jobs landen vervolgens onder `~/.scrum4me-agent-worktrees/<jobId>/`
|
||||||
zodat de hoofd-clone niet wordt aangeraakt.
|
zodat de hoofd-clone niet wordt aangeraakt.
|
||||||
|
|
||||||
Push gaat over dezelfde token: `git push -u origin feat/story-<id>`
|
Push gaat over dezelfde token: `git push -u origin feat/story-<id>`
|
||||||
slaagt zonder prompt. **`gh pr create` is in PBI-86 (T-1005) verwijderd
|
slaagt zonder prompt. `gh pr create` (voor producten met `auto_pr=true`)
|
||||||
uit de worker-flow** — de GitHub-PR ontstaat via een handmatig
|
gebruikt dezelfde `GH_TOKEN` via de `gh` CLI's standaard env-detect.
|
||||||
getriggerde promote-Action in Forgejo (zie de Scrum4Me-repo
|
|
||||||
`docs/runbooks/forgejo-hybrid-flow.md`).
|
|
||||||
|
|
||||||
## Veelvoorkomende issues
|
## Veelvoorkomende issues
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ if [[ -z "$JOB_ID" || -z "$REPO_URL" ]]; then
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
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" \
|
SLUG=$(echo "$REPO_URL" \
|
||||||
| sed -E 's#^.*[:/]([^/]+/[^/]+?)(\.git)?/?$#\1#' \
|
| sed -E 's#^.*[:/]([^/]+/[^/]+?)(\.git)?/?$#\1#' \
|
||||||
| tr '/' '_')
|
| tr '/' '_')
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,4 @@ find "${AGENT_LOG_DIR}" -type f \
|
||||||
\( -name '*.log' -o -name '*.log.gz' -o -name '*.txt' -o -name '*.json' \) \
|
\( -name '*.log' -o -name '*.log.gz' -o -name '*.txt' -o -name '*.json' \) \
|
||||||
-mtime "+${AGENT_LOG_HARD_DELETE_DAYS}" -delete 2>/dev/null || true
|
-mtime "+${AGENT_LOG_HARD_DELETE_DAYS}" -delete 2>/dev/null || true
|
||||||
|
|
||||||
# Prune dangling per-job symlinks: jobs/<job_id>.log -> runs/<ts>.log waarvan
|
|
||||||
# het doel door rotatie is gegzipt of verwijderd. De -type f hierboven raakt
|
|
||||||
# symlinks niet, dus broken links worden hier expliciet opgeruimd (-xtype l).
|
|
||||||
find "${AGENT_LOG_DIR}/jobs" -maxdepth 1 -xtype l -delete 2>/dev/null || true
|
|
||||||
|
|
||||||
find "${AGENT_LOG_DIR}/jobs" -mindepth 1 -type d -empty -delete 2>/dev/null || true
|
find "${AGENT_LOG_DIR}/jobs" -mindepth 1 -type d -empty -delete 2>/dev/null || true
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,8 @@ fi
|
||||||
mkdir -p "$HOME"
|
mkdir -p "$HOME"
|
||||||
git config --global credential.helper store
|
git config --global credential.helper store
|
||||||
CREDS_FILE="$HOME/.git-credentials"
|
CREDS_FILE="$HOME/.git-credentials"
|
||||||
if [[ ! -f "$CREDS_FILE" ]] || ! grep -q "oauth2:${GH_TOKEN}@git.jp-visser.nl" "$CREDS_FILE" 2>/dev/null; then
|
if [[ ! -f "$CREDS_FILE" ]] || ! grep -q "oauth2:${GH_TOKEN}@github.com" "$CREDS_FILE" 2>/dev/null; then
|
||||||
printf 'https://oauth2:%s@git.jp-visser.nl\n' "$GH_TOKEN" > "$CREDS_FILE"
|
printf 'https://oauth2:%s@github.com\n' "$GH_TOKEN" > "$CREDS_FILE"
|
||||||
chmod 600 "$CREDS_FILE"
|
chmod 600 "$CREDS_FILE"
|
||||||
log "git credentials helper configured at ${CREDS_FILE}"
|
log "git credentials helper configured at ${CREDS_FILE}"
|
||||||
fi
|
fi
|
||||||
|
|
@ -71,7 +71,7 @@ for repo in "${REPOS[@]}"; do
|
||||||
else
|
else
|
||||||
log "cloning ${repo} into ${target}"
|
log "cloning ${repo} into ${target}"
|
||||||
rm -rf "$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; }
|
|| { log "ERROR: clone failed for ${repo}"; continue; }
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
|
||||||
|
|
@ -68,9 +68,7 @@ while true; do
|
||||||
# claimt zelf via tryClaimJob, leest JobConfig (PBI-67), bouwt de
|
# claimt zelf via tryClaimJob, leest JobConfig (PBI-67), bouwt de
|
||||||
# juiste Claude CLI-args, spawnt 'claude', wacht, sluit af.
|
# juiste Claude CLI-args, spawnt 'claude', wacht, sluit af.
|
||||||
set +e
|
set +e
|
||||||
# RUN_LOG laat run-one-job.ts een jobs/<job_id>.log symlink leggen naar
|
tsx /opt/agent/bin/run-one-job.ts > "${run_log}" 2>&1
|
||||||
# dit run-log, zodat de output van een job op job-id vindbaar is.
|
|
||||||
RUN_LOG="${run_log}" tsx /opt/agent/bin/run-one-job.ts > "${run_log}" 2>&1
|
|
||||||
exit_code=$?
|
exit_code=$?
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
|
@ -80,12 +78,8 @@ while true; do
|
||||||
# Token-expiry detectie: run-one-job.ts retourneert exit 3 wanneer het
|
# 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
|
# 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-
|
# 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
|
# connection-error met OAuth-expired in error-body).
|
||||||
# niet-nul exit. Het run-log bevat de volledige stream-json output (incl.
|
if [[ "$exit_code" -eq 3 ]] || grep -qE '(invalid_api_key|authentication.*failed|401.*unauthor|OAuth.*expired)' "${run_log}"; then
|
||||||
# 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
|
|
||||||
log "AUTH FAILURE detected (exit=$exit_code or pattern in log) — marking TOKEN_EXPIRED"
|
log "AUTH FAILURE detected (exit=$exit_code or pattern in log) — marking TOKEN_EXPIRED"
|
||||||
touch "${AGENT_STATE_DIR}/TOKEN_EXPIRED"
|
touch "${AGENT_STATE_DIR}/TOKEN_EXPIRED"
|
||||||
write_state "$(jq -n \
|
write_state "$(jq -n \
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,7 @@
|
||||||
// 3 = TOKEN_EXPIRED detected → run-agent.sh schrijft TOKEN_EXPIRED marker
|
// 3 = TOKEN_EXPIRED detected → run-agent.sh schrijft TOKEN_EXPIRED marker
|
||||||
|
|
||||||
import { spawn, spawnSync } from 'node:child_process'
|
import { spawn, spawnSync } from 'node:child_process'
|
||||||
import { mkdirSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'
|
import { mkdirSync, rmSync, writeFileSync } from 'node:fs'
|
||||||
import { basename, join } from 'node:path'
|
|
||||||
|
|
||||||
import { Client as PgClient } from 'pg'
|
import { Client as PgClient } from 'pg'
|
||||||
|
|
||||||
|
|
@ -197,25 +196,6 @@ async function main(): Promise<number> {
|
||||||
|
|
||||||
log(`claimed job_id=${jobId}`)
|
log(`claimed job_id=${jobId}`)
|
||||||
|
|
||||||
// Per-job log: symlink jobs/<jobId>.log -> the runs/<timestamp>.log of
|
|
||||||
// this iteration. runs/ files are timestamp-named, so without this a job's
|
|
||||||
// output is only findable by grepping. run-agent.sh passes the run-log
|
|
||||||
// path via RUN_LOG. Relative target so it survives the host bind-mount.
|
|
||||||
// Best-effort — never fail the job over a log convenience. Dangling links
|
|
||||||
// (after the runs/ file is gzipped/deleted) are pruned by log-cleanup.sh.
|
|
||||||
const runLog = process.env.RUN_LOG
|
|
||||||
if (runLog) {
|
|
||||||
try {
|
|
||||||
const jobsDir = join(process.env.AGENT_LOG_DIR ?? '/var/log/agent', 'jobs')
|
|
||||||
mkdirSync(jobsDir, { recursive: true })
|
|
||||||
const linkPath = join(jobsDir, `${jobId}.log`)
|
|
||||||
rmSync(linkPath, { force: true })
|
|
||||||
symlinkSync(join('..', 'runs', basename(runLog)), linkPath)
|
|
||||||
} catch (err) {
|
|
||||||
log(`per-job log symlink skipped for ${jobId}: ${(err as Error).message}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Resolve full context.
|
// 3. Resolve full context.
|
||||||
let ctx: Awaited<ReturnType<typeof getFullJobContext>> = null
|
let ctx: Awaited<ReturnType<typeof getFullJobContext>> = null
|
||||||
try {
|
try {
|
||||||
|
|
@ -292,13 +272,6 @@ async function main(): Promise<number> {
|
||||||
|
|
||||||
// 7. Build CLI args.
|
// 7. Build CLI args.
|
||||||
const promptText = getKindPromptText(ctx.kind).replace('$PAYLOAD_PATH', payloadPath)
|
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[] = [
|
const args: string[] = [
|
||||||
'-p',
|
'-p',
|
||||||
promptText,
|
promptText,
|
||||||
|
|
@ -313,9 +286,8 @@ async function main(): Promise<number> {
|
||||||
'--add-dir',
|
'--add-dir',
|
||||||
'/opt/agent',
|
'/opt/agent',
|
||||||
'--output-format',
|
'--output-format',
|
||||||
outputFormat,
|
'text',
|
||||||
]
|
]
|
||||||
if (outputFormat === 'stream-json') args.push('--verbose')
|
|
||||||
if (effort) args.push('--effort', effort)
|
if (effort) args.push('--effort', effort)
|
||||||
|
|
||||||
const cwd = worktreePath ?? '/opt/agent'
|
const cwd = worktreePath ?? '/opt/agent'
|
||||||
|
|
@ -383,21 +355,13 @@ async function main(): Promise<number> {
|
||||||
`duration_ms=${durationMs} wall_clock_seconds=${Math.round(durationMs / 1000)}`,
|
`duration_ms=${durationMs} wall_clock_seconds=${Math.round(durationMs / 1000)}`,
|
||||||
)
|
)
|
||||||
|
|
||||||
// 10. Token-expiry detection — alleen als Claude zelf non-zero eindigde.
|
// 10. Token-expiry detection.
|
||||||
// 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).
|
|
||||||
let tokenExpired = false
|
let tokenExpired = false
|
||||||
if (exitCode !== 0) {
|
for (const pat of TOKEN_EXPIRY_PATTERNS) {
|
||||||
for (const pat of TOKEN_EXPIRY_PATTERNS) {
|
if (pat.test(stdoutBuf)) {
|
||||||
if (pat.test(stdoutBuf)) {
|
tokenExpired = true
|
||||||
tokenExpired = true
|
log(`TOKEN_EXPIRED detected pattern="${pat.source}" exiting code=3`)
|
||||||
log(`TOKEN_EXPIRED detected pattern="${pat.source}" exiting code=3`)
|
break
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue