7.6 KiB
Impl: Worktree go abre o opencode com pré-seleções (DeepSeek V4 Flash, auto-approve, skill inicial)
Status: aprovado Atualizado em: 2026-08-10 Issue: #571 Intenção: docs/plans/worktree-go-abre-opencode-com-presets.md Appetite restante: ~0,5–1 dia eng (herdado; cabe folgado)
Leitura da intenção
- Outcome:
worktree nextno terminal termina com o TUI do opencode aberto no worktree (modelodeepseek/deepseek-v4-flash,--auto,/work-issueenviado);worktree planabre com os mesmos presets e sem prompt (fallback acordado:/plan-+ autocomplete; pre-fill sem submit quando o CLI do opencode ganhar a flag); sem marcador de terminal → nenhum launch (sócd);--staysuprime cd e launch; presets são constantes no script. - O que NÃO negociar: sem TUI aninhado (
/worktreedo opencode não lança); sem alterar provisionamento; sem presets por-worktree via config commitada; launch semexec(sair do TUI volta ao shell no worktree); sem auto-killao sair. - O que reavaliar: a hipótese de "env/flag que só a função shell passa" — validada como marcador de env (aceite #3 exige que o script distinga a superfície); a localização das constantes (script vs função shell) — aceite #6 exige script.
Abordagem recomendada
flowchart LR
S[worktree.sh função worktree] -->|TEQO_WORKTREE_TERMINAL=1 + args| N[node scripts/worktree.mjs]
N -->|print| CD["launch opencode <dir> --model … --auto [--prompt /work-issue]<br/>cd <dir>"]
S -->|sed 's/^launch //p'| L[executa launch sem exec<br/>foreground, TUI assume o terminal]
S -->|sed 's/^cd //p'| D[cd <dir> primeiro]
C[.opencode/commands/worktree.md] -->|sem marcador| N2[node scripts/worktree.mjs]
N2 -->|print| CD2["cd <dir> (sem launch — superfície nunca lança TUI)"]
C -->|aplica| D2[cd <dir>]
Opções consideradas: A (marcador de env TEQO_WORKTREE_TERMINAL=1 — linha launch só quando marcado) | B (script sempre imprime launch; cada chamador decide o que executar) | C (flag --launch no argv)
Recomendação: A — o aceite #3 exige que o launch não aconteça quando o script roda sem marcador (o /worktree do opencode, automação): o marcador é o que separa as duas superfícies; a superfície opencode nunca recebe a linha, então seu texto não precisa ensinar a ignorá-la.
Rejeitadas: B — inverte o aceite (a linha sairia para o /worktree também; o comando precisaria aprender a descartá-la, e automação futura ingênua executaria TUI aninhado); C — o shell repassa "$@" intacto; uma flag extra exigiria strip antes do repasse e poderia vazar para a superfície opencode.
Componentes / mudanças
opencodeLaunchDirective(scripts/lib/worktree.mjs): função pura({ dir, purpose, terminal }) → string | null— devolvenullsem marcador; linhalaunch opencode <dir> --model <model> --auto+--prompt /work-issuesó parapurpose: 'next'(plan sem prompt — fallback acordado). Constantes exportadas no lib (fonte única, unit-testável):OPENCODE_PRESET_MODEL = 'deepseek/deepseek-v4-flash',OPENCODE_SKILL_COMMAND_BY_PURPOSE = { next: '/work-issue', plan: null },WORKTREE_TERMINAL_ENV = 'TEQO_WORKTREE_TERMINAL'. Invariante documentada: dir é sempre<root sem espaço>/<branch slugificado>— sem espaços, word-splitting seguro.scripts/worktree.mjs: lêprocess.env[WORKTREE_TERMINAL_ENV] === '1'; emcmdNext/cmdPlan, no bloco!stay, imprime a linhalaunch …antes docd <dir>(a linhacdcontinua sendo a última — contrato OPS24 preservado para todos os consumidores). Header do script + bloco de uso ganham uma linha sobre o launch..agents/shell/worktree.sh: chamaTEQO_WORKTREE_TERMINAL=1 node …; depois do cd aplicado, extrai a última linhalaunch …(mesmo padrão sed do cd) e executa word-split ($launch, semeval— formato fixo gerado pelo script, sem globs) semexec(aceite #5: ao sair do TUI, volta ao shell no worktree); falha do launch (ex.:opencodeausente) imprime aviso e o worktree segue utilizável.- Migration: sem migration (nenhuma mudança de schema/dados).
- Access / Consent: N/A (CLI de dev).
- UI: Impeccable A — N/A (sem UI de produto; TUI de terceiros).
Ordem das linhas na saída
… (bloco "Ambiente isolado") …
launch opencode /home/<user>/.cursor/worktrees/teqo/OPS26-x --model deepseek/deepseek-v4-flash --auto --prompt /work-issue
cd /home/<user>/.cursor/worktrees/teqo/OPS26-x
cd continua última linha (contrato documentado em AGENTS.md/skill/comando intacto); a função shell aplica cd primeiro e só então executa o launch (foreground).
Fases verificáveis
- Derivação pura — lib (
opencodeLaunchDirective+ constantes) + unit tests novos emtests/unit/worktree.unit.spec.ts(next → prompt presente; plan → sem prompt; terminal=false → null; constantes pinadas). Quota: pequena. - Script + shell —
cmdNext/cmdPlanimprimem a diretiva; função shell aplica marcador, cd e launch; textos (header/uso do script, header do .sh). Verificação manual:TEQO_WORKTREE_TERMINAL=1 node scripts/worktree.mjs …(output shape) e simulação do parse sed com saída sintética (sem criar worktree/DBs reais). - Docs — AGENTS.md (parágrafo Per-worktree),
.opencode/commands/worktree.md(nota: comando nunca lança TUI),.agents/skills/worktree-next-issue/SKILL.md(linha default-go),docs/CHANGELOG-AGENTS.md(entrada única, padrão das entregas). - Gates —
pnpm gate:fastna iteração;pnpm pushna entrega (gate:ci + push).
Rabbit holes / Não escopo (engenharia)
opencode.jsonpor worktree / config global~/.config/opencode(presets são flags por invocação — rabbit hole cortado na intenção).- Flag de pre-fill sem submit no CLI do opencode (gap registrado em
~/Code/propositions/opencode/prefill-prompt-sem-submit.md; se ganhar a flag,planpassa a preencher — gatilho documentado na intenção). - Modelo dinâmico por Issue (
model:da Issue claimada vs constante) — constante fixa, fora de escopo da intenção. worktree new(OPS27, herda launch sem skill inicial) — item próprio.- Execução via
evalna função shell — desnecessária; word-splitting de formato fixo basta. - Testes da função shell (bats etc.) — repo não tem suíte de shell; verificação via simulação do parse.
Riscos e mitigação
- TUI aninhado por engano (marcador esquecido em automação futura): o default é sem launch — falha segura no sentido bom (nenhum TUI surpresa). Aceite #3 cobre.
- Launch falho (
opencodefora do PATH, TUI com erro): cd já aplicado; aviso + worktree utilizável — nada destrutivo. - Word-splitting da linha launch quebra se dir tiver espaços: impossível hoje (root fixo sem espaço + branch slugificado); invariante documentada no lib e na função shell.
- Contrato "cd última linha" quebrado por engano: diretiva impressa antes do cd; unit test do lib não cobre a ordem — coberto pela verificação manual de fase 2 e pelo texto do header.
- Doc drift (AGENTS.md/skill dizendo "cd última linha por padrão"): atualizações na fase 3 no MESMO PR (padrão do repo: docs e código juntos).
Aceite de engenharia
- Aceite de produto da intenção ainda coberto (6 critérios: next envia
/work-issue; plan sem prompt; sem marcador → sem launch;--staysuprime; semexec+ sem auto-kill; constantes no script) - Invariantes AGENTS/engineering-standards (nenhuma mudança em src/, migrations, access, Consent, transações)
- Testes de domínio previstos (unit da derivação pura; sem int/e2e — nenhum caminho de escrita/access muda)