Workflow separado auto-unblock.yml (workflow_run no Deploy, push/main + job verify vermelho pela jobs API), launcher com flock próprio + Issue token auto-unblock como single-flight, e wrapper destacado que provisiona worktree fix/* via worktree.mjs fix --headless, aplica guard de banco local teqo_wt* fail-closed e roda opencode run --command bug-fix (cap 4h). deploy.yml/verify intocados; sem auto-retry e produção segue com approval humano.
- buildClaimQueue exclui Issues ready sem frontmatter id (não viram worktree
por construção) e withoutIdReadyIssues() expõe as puladas
- agent:claim / worktree next / pnpm issue next avisam com os números em vez
de morrer — uma Issue quebrada não trava mais a fila
- pin novo em agentPoolEligibility.unit.spec.ts
Closes#864
Mapa fixo commitado em scripts/lib/worktree.mjs (cheap=cheapestinference/deepseek-v4-flash, pro=opencode-go/qwen3.7-max, zen=opencode-go/ox-alpha-free, go=opencode-go/mimo-v2.5, alibaba=alibaba-token-plan/qwen3.7-max) com WORKTREE_VARIANT=max sempre; resolveWorktreeModel fail-high em múltiplas flags; opencodeLaunchDirective passa a emitir --model <map|preset> --variant max --auto; scripts/worktree.mjs valida at-most-one antes do claim e repassa modelo nos 3 propósitos (next/plan/new) com help/docblock atualizados; .agents/shell/worktree.sh, .opencode/commands/worktree.md, .agents/skills/worktree-next-issue/SKILL.md e local-database skill com contrato remapeado (--go deixa de ser no-op); tests/unit/worktree.unit.spec.ts pina as 5 flags, variant e guardrail.
Closes#859
Decisão (2026-08-21): o GitHub passa a ser a fonte única — main, branches,
PRs, CI via Actions E tracker de Issues. O Forgejo deixa de ser canal ativo
(git.e issue tracker congelados pós-convergência).
Data: 17 issues migradas do Forgejo para o GitHub (frontmatter id/depends/
serializes/priority/model preservados, labels mapeados, comment de origem
em cada uma; tabela Forgejo→GitHub registrada).
Tooling: github-api.mjs estendido com a camada de issues/labels/comments/
close/workflow-dispatch/contents (mesmo shape normalizado do forgejo-api);
18 scripts trocam o transporte forgejo-api → github-api; forgejo-api.mjs e
seu teste (961 linhas) removidos; teste githubApi.unit.spec.ts novo (7 casos);
issue-transition-on-merge.mjs renomeado e reapontado.
Flips pós-merge: issue-done e plan-issue-ready agora usam o GITHUB_TOKEN com
issues:write no repo (sem FORGEJO_API_TOKEN) e fecham/flipam Issues no GitHub.
Docs: AGENTS.md, AGENT-OPS.md e skills do fluxo vivo (work-issue, plan-issue,
project-status, capture-review-debts, worktree-next-issue, agent-work-issue)
apontam o tracker para github.com/fsolla/teqo/issues.
Gates: tsc/lint/format/knip/cycles/unit 2416 verdes.
Merge pull request #27 from fsolla/OPS52-migrar-a-media-de-producao-do-vercel-blob-para-o-garag
OPS52 — Migrar a media de produção do Vercel Blob para o Garage S3 (Closes#3)
- worktree.mjs: WORKTREES_ROOT = env ?? fallback (~/.cursor/worktrees/teqo)
- .forgejo/worktree.env novo: FORGEJO_REPOSITORY=fsolla/teqo + root atual
(migração para ~/.worktrees/teqo fica para quando as sessões opencode
ativas nos worktrees antigos fecharem — OPS52/OPS53/PUB5)
Roteador global (~/.config/shell/worktree.sh) exporta as chaves do arquivo
por projeto; iara-pwa já usa o mesmo mecanismo.
- payload.config.ts: vercelBlobStorage -> s3Storage (@payloadcms/storage-s3)
com endpoint Garage (forcePathStyle, region garage); bucket privado — o
staticHandler do plugin streama os objetos em /api/media/file/<filename>,
mantendo o contrato de URL relativa das 40 rows pré-existentes
- src/utilities/mediaStorage.ts: resolveS3StorageEnv fail-closed (S3_* parcial
-> throw no boot com a lista exata; nenhuma -> storage local dev/test)
- seed-posts: remove pre-delete do @vercel/blob (S3 sobrescreve nativamente)
- worktree-env.mjs: s3EnvCopiedLines all-or-nothing (unit-testada)
- envs S3_BUCKET/S3_ENDPOINT/S3_REGION/S3_ACCESS_KEY_ID/S3_SECRET_ACCESS_KEY
no .env.example/.env.test; cloud-setup.sh sem o sed morto do blob
- deps: -storage-vercel-blob -@vercel/blob +storage-s3; importMap regenerado
- docs: impl plan (revisão A->B: Garage v2 sem acesso anônimo na API S3),
AGENTS.md, changelog 2026-08-18-ops52
O opencode.json referencia .opencode/secrets/penpot-token via {file:...},
mas o arquivo é gitignored e git worktree não leva ignored files — o
launch do opencode no worktree morria com 'bad file reference'.
provision agora copia .opencode/secrets/* do worktree principal
(sem sobrescrever cópia manual).
Workflows nativos em .forgejo/workflows/ (ci, ci-pr, agent-pool,
automerge, issue-transition, plan-issue, vercel-promote, archive),
removendo .github/workflows e .github/actions. Runner Forgejo v13 com
services Postgres por porta + DB_HOST via gateway do bridge. Libs de
agente sobre o novo cliente forgejo-api.mjs (zero dependências,
GITHUB_SERVER_URL/FORGEJO_API_URL), helpers de workflow plain-Node.
pnpm issue corrigido (await em função sync) e validado ao vivo. Testes:
forgejoApi.unit.spec.ts novo, pin do matrix do ci.yml atualizado.
Closes#1 (parte 1 — docs/issues/pool seguem na parte 2)
Claim extraído para scripts/lib/agent-github.mjs (claimIssue/claimBriefLines/
claimQueueEntry/claimTargetVerdict), agent-claim.mjs vira CLI fino com mesma
saída; branch validada antes do claim (sem claim órfão); hint de falha
pós-claim; guard -B contra reset de commits de sessão; diretiva launch com
prompt citado + tokenização xargs no worktree.sh; --issue sem valor/posicional
morrem com motivo (sem misclaim); unit novos (directive com issueNumber,
claimQueueEntry, claimTargetVerdict); docs/textos (AGENTS.md, /worktree, skill
worktree-next-issue, AGENT-OPS, CHANGELOG).
- scripts/worktree.mjs: provision() aplica migrate + db:seed:minimal nos
bancos dev e test (paridade com a CI, que roda o par antes do e2e);
--no-migrate pula os dois (o seed depende do catálogo migrado); fallback
sem Docker também migra+seeda o teqo/teqo_test compartilhado (com warning
de sobrescrita dos pins).
- Guard de regressão tests/e2e/seedParity.setup.e2e.spec.ts no projeto setup:
falha cedo com mensagem clara se o banco de teste não estiver seedado;
evidência = users do seed (MINIMAL_CAMPAIGN_USERS), não os pins de priority
— o cleanup dos fixtures e2e reseta priority por round-robin persistente.
- scripts/lib/test-affected-core.mjs: scripts/worktree.mjs em HIGH_RISK_EXACT.
- Docs: AGENTS.md, skill local-database, CHANGELOG-AGENTS.md, impl plan.
Closes#584
next/plan imprimem 'cd <dir>' na última linha por padrão; --stay suprime;
--go segue aceito como no-op. kill imprime 'cd <main>' como última linha
(depois do drop dos bancos) e recusa --stay. Superfícies: worktree.sh
aplica o cd por padrão; comando /worktree do opencode idem. Docs
(AGENTS.md, skills, CHANGELOG) atualizadas.
provision() chamava runMigrate(dir, devUrl, ...) com variáveis nunca
definidas no escopo — 'devUrl is not defined' ao rodar pnpm worktree
next --go. Derivadas dos bancos do env (mesmo formato de
worktreeEnvFileContents).
O .env.test.local (que o playwright.config.ts lê) passa a carregar
PLAYWRIGHT_BASE_URL na porta do slot (3100+slot); antes só o .env.local
(que o config não lê) o tinha, então dois test:e2e em worktrees paralelos
subiam dev servers na porta 3000. Causa-raiz tratada: os dois blocos env
inline do provision viraram um builder puro único (worktreeEnvFileContents
em scripts/lib/worktree-env.mjs) que deriva NEXT_PUBLIC_SITE_URL +
PLAYWRIGHT_BASE_URL do mesmo devPort para ambos os arquivos — paridade
estrutural, drift impossível + unit tests de paridade. playwright.config.ts
intocado (a variável certa já existia).
Cada 'pnpm worktree plan' agora deriva um branch próprio: plans/plan-issue-<bag>
quando um bag é passado (sufixo -2/-3 em colisão) ou o próximo sequencial
plans/plan-issue-<n> quando não. O prefixo minúsculo plans/… nunca colide com o
branch <Code>-<slug> de 'next'. planBranchName (scripts/lib/worktree.mjs)
unit-testado; docs e shell/command atualizados.
Novo subcomando `pnpm worktree plan [--go] [--no-migrate]` cria/reutiliza o
worktree de planejamento no branch fixo `plans/plan-issue`
(`PLAN_WORKTREE_BRANCH`), sem vínculo com a fila de claim: um `next` posterior
da próxima Issue nunca colide em branch nem em slot (slot derivado por hash do
branch, bumpado entre worktrees vivos). Mesmo provisionamento isolado do
`next` — porta 3100+slot, bancos teqo_wt<slot>/teqo_wt<slot>_test, migrations.
- scripts/worktree.mjs: cmdPlan + provision() com purpose/issue opcionais
- scripts/lib/worktree.mjs: constante PLAN_WORKTREE_BRANCH
- tests/unit/worktree.unit.spec.ts: derivação de slot do plano
- docs: .opencode/commands/worktree.md, shell, skills, AGENTS.md, changelog
pnpm worktree next [--go] [--no-migrate] agora provisiona um ambiente
determinístico por worktree: slot = parte numérica do código da Issue
(C15→15; hash sem dígitos; bump em colisão entre worktrees vivos), dev
server em 3100+slot, bancos teqo_wt<slot> / teqo_wt<slot>_test no
container compartilhado (-p teqo) com a cadeia de migrations aplicada;
escreve .env.local + .env.test.local (gitignored, marcador gerado; envs
manuais nunca sobrescritos) e copia PAYLOAD_SECRET/Blob/VAPID do main.
kill remove o worktree e dropa os bancos gerados (WITH FORCE, best-effort).
Suites leem .env.test.local depois de .env.test (vitest.setup /
playwright / db-doctor / gate-ci espelham o layering) e
assertTestDatabase aceita teqo_test ou teqo_<worktree>_test em localhost
só (fail-closed preservado). db:start/db:stop fixam -p teqo (um
container de qualquer diretório); max_connections 200→400. Sem Docker
(Cursor Cloud): degrada ao compartilhado com aviso.
Derivação pura em scripts/lib/worktree-env.mjs (unit-tested); fluxo
validado end-to-end: provision → migrate → 598/598 int no banco do
worktree → kill sem resíduo.