dev flow
This commit is contained in:
@@ -32,6 +32,7 @@
|
|||||||
../../modules/home-manager/pi
|
../../modules/home-manager/pi
|
||||||
../../modules/home-manager/tmux
|
../../modules/home-manager/tmux
|
||||||
../../modules/home-manager/openspec
|
../../modules/home-manager/openspec
|
||||||
|
../../modules/home-manager/dev-orchestrator
|
||||||
../../modules/home-manager/power-profiles
|
../../modules/home-manager/power-profiles
|
||||||
../../modules/home-manager/ntfy-notify
|
../../modules/home-manager/ntfy-notify
|
||||||
../../modules/home-manager/pinentry
|
../../modules/home-manager/pinentry
|
||||||
@@ -97,6 +98,7 @@
|
|||||||
enable = true;
|
enable = true;
|
||||||
};
|
};
|
||||||
openspec.enable = true;
|
openspec.enable = true;
|
||||||
|
dev-orchestrator.enable = true;
|
||||||
power-profiles.enable = true;
|
power-profiles.enable = true;
|
||||||
ntfy-notify = {
|
ntfy-notify = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{ lib, config, pkgs, ... }:
|
||||||
|
{
|
||||||
|
options.custom = {
|
||||||
|
dev-orchestrator.enable = lib.mkEnableOption "enable dev-orchestrator — OpenSpec + OpenCode dev→QA loop with git worktrees";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.custom.dev-orchestrator.enable {
|
||||||
|
home.packages = [
|
||||||
|
(pkgs.writeShellApplication {
|
||||||
|
name = "dev-orchestrator";
|
||||||
|
runtimeInputs = with pkgs; [ git ];
|
||||||
|
text = builtins.readFile ../../../tooling/dev-orchestrator;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,233 @@
|
|||||||
|
# Dev Orchestrator — AI Workflow Guide
|
||||||
|
|
||||||
|
Toolchain de desenvolvimento com IA: **OpenCode** (agente) + **OpenSpec** (spec-driven dev) + **Dev Orchestrator** (loop dev→QA automático).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Ferramentas — Quando Usar Cada Uma
|
||||||
|
|
||||||
|
### OpenCode — O Agente
|
||||||
|
|
||||||
|
Executa tarefas de código. Use **diretamente** quando:
|
||||||
|
|
||||||
|
- Explorar uma codebase nova: `opencode` (TUI interativo)
|
||||||
|
- Fazer uma mudança pontual: `opencode run "corrige typo no header"`
|
||||||
|
- Debugar um erro específico: `opencode run "por que esse teste falha?" --thinking`
|
||||||
|
- Revisar um PR manualmente: `opencode pr 42`
|
||||||
|
|
||||||
|
Use via **orquestrador** quando:
|
||||||
|
- Implementar uma feature completa com spec (`dev-orchestrator build`)
|
||||||
|
- Precisar de QA automático depois do dev
|
||||||
|
- Quiser loop dev→QA sem babysitting
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Modos do OpenCode
|
||||||
|
opencode # TUI interativo (exploração)
|
||||||
|
opencode run "tarefa" # one-shot (automação)
|
||||||
|
opencode run "..." --thinking # vê o raciocínio do modelo
|
||||||
|
opencode run "..." -f arquivo.ts # anexa contexto
|
||||||
|
```
|
||||||
|
|
||||||
|
### OpenSpec — O Spec Engine
|
||||||
|
|
||||||
|
Gerencia specs como source of truth. Use **diretamente** quando:
|
||||||
|
|
||||||
|
- Criar spec manualmente: `openspec new change minha-feature`
|
||||||
|
- Validar um spec existente: `openspec validate minha-feature --strict`
|
||||||
|
- Ver status de todos os changes: `openspec list --json`
|
||||||
|
- Arquivar spec concluído: `openspec archive minha-feature --yes`
|
||||||
|
|
||||||
|
Use via **orquestrador** quando:
|
||||||
|
- Quiser que a IA preencha o spec automaticamente (`dev-orchestrator spec`)
|
||||||
|
- O archive deve acontecer automático pós-QA-pass (`dev-orchestrator build`)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Comandos OpenSpec que você mais usa
|
||||||
|
openspec list # o que está ativo?
|
||||||
|
openspec show minha-feature # ler um spec
|
||||||
|
openspec validate minha-feature # check pré-implementação
|
||||||
|
openspec status --change minha-feature # progresso dos artefatos
|
||||||
|
openspec instructions --change minha-feature # o que o agente deve fazer
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dev Orchestrator — O Script
|
||||||
|
|
||||||
|
Automatiza o loop completo. **Substitui** os comandos manuais acima no fluxo principal.
|
||||||
|
|
||||||
|
```
|
||||||
|
você tem ideia → spec → review → build → PR pronto
|
||||||
|
↑ ↑ ↑
|
||||||
|
orquestrador você automático
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pré-requisitos
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install -g opencode-ai@latest
|
||||||
|
npm install -g @fission-ai/openspec@latest
|
||||||
|
opencode auth login # configura provider (OpenRouter, Anthropic, etc.)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Comandos do Orquestrador
|
||||||
|
|
||||||
|
| Comando | O que faz |
|
||||||
|
|---|---|
|
||||||
|
| `dev-orchestrator init` | Configura repo (OpenSpec + .gitignore) — 1x por projeto |
|
||||||
|
| `dev-orchestrator spec <nome>` | Cria spec + worktree isolado + preenche spec via IA |
|
||||||
|
| `dev-orchestrator build <nome>` | Loop dev→QA (3 tentativas), merge automático se passar |
|
||||||
|
| `dev-orchestrator status` | Dashboard de features em andamento |
|
||||||
|
| `dev-orchestrator clean <nome>` | Remove worktree + branch (abortar feature) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Fluxo Completo
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────┐ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐
|
||||||
|
│ init │───→│ spec <nome> │───→│ [review] │───→│ build <nome> │
|
||||||
|
│ (1x/proj)│ │ (orquestrador│ │ (você aprova) │ │ (dev→QA loop)│
|
||||||
|
└──────────┘ │ preenche) │ └──────────────┘ └──────┬──────┘
|
||||||
|
└──────────────┘ │
|
||||||
|
┌────────────────────┘
|
||||||
|
│ QA PASS → merge + archive
|
||||||
|
│ QA FAIL → retry (3x max)
|
||||||
|
└────────────────────────
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1. Inicializar
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/projetos/meu-app
|
||||||
|
dev-orchestrator init
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Especificar feature
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dev-orchestrator spec add-oauth
|
||||||
|
```
|
||||||
|
|
||||||
|
O que acontece internamente:
|
||||||
|
1. `openspec new change add-oauth --json` → cria templates
|
||||||
|
2. `git worktree add -b dev-flow/add-oauth ../.worktrees/add-oauth/ HEAD`
|
||||||
|
3. `npm install` dentro do worktree
|
||||||
|
4. `opencode run "preenche os specs lendo a codebase"` → orquestrador preenche spec.md, design.md, tasks.md
|
||||||
|
|
||||||
|
### 3. Revisar os specs (MOMENTO CRÍTICO)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Ler o spec gerado
|
||||||
|
cat openspec/changes/add-oauth/spec.md
|
||||||
|
cat openspec/changes/add-oauth/design.md
|
||||||
|
|
||||||
|
# Validar
|
||||||
|
openspec validate add-oauth --strict
|
||||||
|
|
||||||
|
# Ajustar manualmente se quiser — edite os arquivos
|
||||||
|
vim openspec/changes/add-oauth/spec.md
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Você é o gatekeeper aqui.** Se o spec não está certo, o build vai sair errado.
|
||||||
|
> Gaste tempo revisando os specs — é o investimento mais rentável do fluxo.
|
||||||
|
|
||||||
|
### 4. Build (dev→QA loop)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dev-orchestrator build add-oauth
|
||||||
|
```
|
||||||
|
|
||||||
|
Loop:
|
||||||
|
```
|
||||||
|
Dev Phase ──→ OpenCode implementa + testa + commita
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
QA Phase ──→ OpenCode revisa: spec compliance, testes, regressões
|
||||||
|
│
|
||||||
|
├── PASS → merge no main, archive spec, remove worktree ✅
|
||||||
|
│
|
||||||
|
└── FAIL → volta pro Dev (até 3 tentativas)
|
||||||
|
falhou 3x → worktree mantido pra correção manual
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Status dashboard
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dev-orchestrator status
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quando Sair do Orquestrador
|
||||||
|
|
||||||
|
O script cobre 90% dos casos. Saia dele quando:
|
||||||
|
|
||||||
|
| Situação | O que fazer |
|
||||||
|
|---|---|
|
||||||
|
| Spec ficou ruim e quero reescrever do zero | `openspec new change X` manual, preenche na mão |
|
||||||
|
| QA rejeitou e quero corrigir eu mesmo | `cd ../.worktrees/feature/` → edita → commita → `dev-orchestrator build feature` |
|
||||||
|
| Feature complexa demais pra um spec só | `openspec new change feature-pt1`, `openspec new change feature-pt2` |
|
||||||
|
| Quero iterar rápido sem spec | `opencode` TUI direto (pula o orquestrador) |
|
||||||
|
| Bug fix trivial (1-2 linhas) | `opencode run "fix: ..."` direto, nem cria spec |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Paralelismo
|
||||||
|
|
||||||
|
Rode múltiplos features ao mesmo tempo:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Terminal 1
|
||||||
|
dev-orchestrator build feature-a
|
||||||
|
|
||||||
|
# Terminal 2
|
||||||
|
dev-orchestrator build feature-b
|
||||||
|
```
|
||||||
|
|
||||||
|
Cada um em seu worktree isolado. O merge no main serializa no final — se houver conflito, o script para e avisa.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Estrutura de Diretórios
|
||||||
|
|
||||||
|
```
|
||||||
|
~/projetos/meu-app/
|
||||||
|
├── src/
|
||||||
|
├── openspec/
|
||||||
|
│ ├── specs/ # specs arquivados
|
||||||
|
│ └── changes/ # specs ativos
|
||||||
|
│ └── add-oauth/
|
||||||
|
│ ├── spec.md
|
||||||
|
│ ├── design.md
|
||||||
|
│ └── tasks.md
|
||||||
|
├── .gitignore # inclui .worktrees/
|
||||||
|
└── ...
|
||||||
|
|
||||||
|
../.worktrees/
|
||||||
|
└── add-oauth/ # worktree isolado
|
||||||
|
├── .git # branch: dev-flow/add-oauth
|
||||||
|
├── src/
|
||||||
|
├── node_modules/
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Opcional: Swarm Tools + .hive
|
||||||
|
|
||||||
|
Kanban mais visual, sem servidor:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install -g opencode-swarm-plugin
|
||||||
|
swarm setup
|
||||||
|
```
|
||||||
|
|
||||||
|
Dentro do OpenCode:
|
||||||
|
- `/swarm "tarefa"` — decompõe e spawna workers paralelos
|
||||||
|
- `/hive` — quadro kanban das tasks
|
||||||
|
- `/inbox` — mensagens entre agentes
|
||||||
|
|
||||||
|
O `.hive/` é uma pasta git-tracked. Independe do `dev-orchestrator`.
|
||||||
Executable
+306
@@ -0,0 +1,306 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# dev-orchestrator — OpenSpec + OpenCode dev→QA loop with git worktrees
|
||||||
|
# Zero dependencies beyond git, opencode, openspec. No heavy binaries.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO="${DEV_FLOW_REPO:-$(pwd)}"
|
||||||
|
WORKTREE_ROOT="$REPO/../.worktrees"
|
||||||
|
|
||||||
|
# ── helpers ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
_wt_path() { echo "$WORKTREE_ROOT/$1"; }
|
||||||
|
_wt_branch(){ echo "dev-flow/$1"; }
|
||||||
|
|
||||||
|
_die() { echo "✗ $*" >&2; exit 1; }
|
||||||
|
_ok() { echo "✓ $*"; }
|
||||||
|
|
||||||
|
# Ensure we're inside a git repo with openspec
|
||||||
|
_guard() {
|
||||||
|
cd "$REPO"
|
||||||
|
git rev-parse --show-toplevel >/dev/null 2>&1 || _die "not a git repo: $REPO"
|
||||||
|
[ -d openspec ] || _die "openspec not initialized. Run: dev-orchestrator init"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── commands ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
cmd_init() {
|
||||||
|
cd "$REPO"
|
||||||
|
git rev-parse --show-toplevel >/dev/null 2>&1 || _die "not a git repo"
|
||||||
|
|
||||||
|
mkdir -p "$WORKTREE_ROOT"
|
||||||
|
if [ -d openspec ]; then
|
||||||
|
_ok "openspec already initialized"
|
||||||
|
else
|
||||||
|
openspec init --tools opencode --force
|
||||||
|
_ok "openspec initialized"
|
||||||
|
fi
|
||||||
|
|
||||||
|
grep -qxF '.worktrees/' .gitignore 2>/dev/null || {
|
||||||
|
echo '.worktrees/' >> .gitignore
|
||||||
|
_ok "added .worktrees/ to .gitignore"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Repo ready. Next: dev-orchestrator spec <feature-name>"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_spec() {
|
||||||
|
local name="$1"
|
||||||
|
_guard
|
||||||
|
|
||||||
|
# ── validate name (kebab-case) ──
|
||||||
|
[[ "$name" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]] || _die "name must be kebab-case: add-oauth, fix-login"
|
||||||
|
|
||||||
|
# ── create OpenSpec change ──
|
||||||
|
echo "── Creating OpenSpec change: $name ──"
|
||||||
|
openspec new change "$name" --json 2>/dev/null || {
|
||||||
|
_die "openspec new change failed. Already exists? Run: dev-orchestrator status"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── create worktree ──
|
||||||
|
local branch; branch="$(_wt_branch "$name")"
|
||||||
|
local wt; wt="$(_wt_path "$name")"
|
||||||
|
echo "── Creating worktree: $wt [$branch] ──"
|
||||||
|
git worktree add -b "$branch" "$wt" HEAD
|
||||||
|
|
||||||
|
# ── install deps in worktree (fully isolated, no symlinks) ──
|
||||||
|
if [ -f "$wt/package.json" ]; then
|
||||||
|
echo "── Installing dependencies ──"
|
||||||
|
(cd "$wt" && npm install --silent 2>&1 | tail -1) || true
|
||||||
|
fi
|
||||||
|
if [ -f "$wt/pyproject.toml" ] || [ -f "$wt/setup.py" ]; then
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
(cd "$wt" && [ -d .venv ] || python3 -m venv .venv && . .venv/bin/activate && pip install -e . -q 2>&1 | tail -1) || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
_ok "Spec '$name' scaffolded at openspec/changes/$name/"
|
||||||
|
echo " Worktree: $wt"
|
||||||
|
echo ""
|
||||||
|
echo " ── Next: explore in OpenCode ──"
|
||||||
|
echo " opencode"
|
||||||
|
echo " Then use OpenSpec native commands:"
|
||||||
|
echo " /opsx:explore — discuss the feature, refine requirements"
|
||||||
|
echo " /opsx:continue — fill spec artifacts one by one"
|
||||||
|
echo ""
|
||||||
|
echo " After specs are filled → dev-orchestrator build $name"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_fill() {
|
||||||
|
local name="$1"
|
||||||
|
_guard
|
||||||
|
|
||||||
|
local wt; wt="$(_wt_path "$name")"
|
||||||
|
[ -d "openspec/changes/$name" ] || _die "spec not found: openspec/changes/$name. Run: dev-orchestrator spec $name"
|
||||||
|
|
||||||
|
echo "── AI filling spec from conversation context ──"
|
||||||
|
opencode run \
|
||||||
|
"You are filling an OpenSpec change for feature: $name.
|
||||||
|
|
||||||
|
STEPS:
|
||||||
|
1. Read the codebase structure first (scan src/, lib/, or equivalent).
|
||||||
|
2. Read openspec/changes/$name/ — note the template files created.
|
||||||
|
3. Read openspec/specs/ for existing specs to avoid conflicts.
|
||||||
|
4. For each template file in the change directory, fill it with:
|
||||||
|
- Clear requirements and acceptance criteria
|
||||||
|
- Files that need to change
|
||||||
|
- Dependencies on other modules
|
||||||
|
- Test plan
|
||||||
|
5. Run: openspec validate $name --strict
|
||||||
|
6. Fix any validation errors, re-run until clean.
|
||||||
|
7. Output a summary: spec files created, key decisions, estimated scope." \
|
||||||
|
--workdir "$REPO"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
_ok "Spec '$name' filled at openspec/changes/$name/"
|
||||||
|
echo " Review the spec, then: dev-orchestrator build $name"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_build() {
|
||||||
|
local name="$1"
|
||||||
|
_guard
|
||||||
|
|
||||||
|
local wt; wt="$(_wt_path "$name")"
|
||||||
|
[ -d "$wt" ] || _die "worktree not found: $wt. Run: dev-orchestrator spec $name"
|
||||||
|
|
||||||
|
local branch; branch="$(_wt_branch "$name")"
|
||||||
|
local max_retries=3
|
||||||
|
|
||||||
|
for attempt in $(seq 1 $max_retries); do
|
||||||
|
echo ""
|
||||||
|
echo "══════════════════════════════════════════════════"
|
||||||
|
echo " $name — Dev Phase (attempt $attempt/$max_retries)"
|
||||||
|
echo "══════════════════════════════════════════════════"
|
||||||
|
|
||||||
|
opencode run \
|
||||||
|
"IMPLEMENT the spec at openspec/changes/$name/.
|
||||||
|
|
||||||
|
RULES:
|
||||||
|
- Read openspec instructions --change $name first
|
||||||
|
- Implement ALL requirements from the spec
|
||||||
|
- Write tests for every new code path
|
||||||
|
- Run the test suite and ensure it passes
|
||||||
|
- If tests fail, fix them before considering work done
|
||||||
|
- Commit with message: '$name: implement feature (attempt $attempt)'
|
||||||
|
- Do NOT modify openspec/ files — only source code and tests" \
|
||||||
|
--workdir "$wt" || {
|
||||||
|
echo "⚠ Dev phase had errors, proceeding to QA anyway..."
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── QA phase ──
|
||||||
|
echo ""
|
||||||
|
echo "──────────────────────────────────────────────────"
|
||||||
|
echo " $name — QA Review"
|
||||||
|
echo "──────────────────────────────────────────────────"
|
||||||
|
|
||||||
|
local qa_file="/tmp/dev-orchestrator-qa-$$.txt"
|
||||||
|
opencode run \
|
||||||
|
"QA REVIEW for $name.
|
||||||
|
|
||||||
|
CHECKLIST (answer each with PASS or FAIL):
|
||||||
|
1. SPEC COMPLIANCE — Does the code implement everything in openspec/changes/$name/?
|
||||||
|
2. TESTS — Do all tests pass? Run them now.
|
||||||
|
3. REGRESSIONS — Does any existing test break? Check git diff vs main.
|
||||||
|
4. EDGE CASES — Are errors handled? Null/empty inputs? Timeouts?
|
||||||
|
5. CODE QUALITY — Clear naming? No debug leftovers? No commented-out code?
|
||||||
|
|
||||||
|
OUTPUT FORMAT (exactly these 2 lines, nothing else):
|
||||||
|
VERDICT: PASS|FAIL
|
||||||
|
REASON: <one-sentence summary>" \
|
||||||
|
--workdir "$wt" > "$qa_file" 2>&1
|
||||||
|
|
||||||
|
local verdict
|
||||||
|
verdict=$(grep '^VERDICT:' "$qa_file" | head -1 | awk -F': ' '{print $2}')
|
||||||
|
local reason
|
||||||
|
reason=$(grep '^REASON:' "$qa_file" | head -1 | cut -d' ' -f2-)
|
||||||
|
|
||||||
|
if [ "$verdict" = "PASS" ]; then
|
||||||
|
echo ""
|
||||||
|
_ok "QA PASSED — $reason"
|
||||||
|
|
||||||
|
# ── archive + merge ──
|
||||||
|
cd "$REPO"
|
||||||
|
echo "── Archiving spec ──"
|
||||||
|
openspec archive "$name" --yes 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "── Merging to main ──"
|
||||||
|
git merge "$branch" -m "dev-flow: merge $name" 2>/dev/null || {
|
||||||
|
echo "⚠ Merge conflict. Resolve manually in $wt then run:"
|
||||||
|
echo " cd $wt && git checkout main && git merge $branch"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "── Cleaning up worktree ──"
|
||||||
|
git worktree remove "$wt" 2>/dev/null || true
|
||||||
|
git branch -d "$branch" 2>/dev/null || true
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
_ok "$name — BUILD COMPLETE ✓"
|
||||||
|
rm "$qa_file"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✗ QA FAILED — ${reason:-see $qa_file}"
|
||||||
|
rm "$qa_file"
|
||||||
|
|
||||||
|
if [ "$attempt" -eq "$max_retries" ]; then
|
||||||
|
_die "$name FAILED after $max_retries attempts. Worktree kept at $wt for manual fix."
|
||||||
|
fi
|
||||||
|
echo "↻ Sending back to dev with QA feedback..."
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_status() {
|
||||||
|
_guard 2>/dev/null || true
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
printf "%-4s %-30s %-10s %-10s %-15s\n" "#" "FEATURE" "COMMITS" "SPEC" "WORKTREE"
|
||||||
|
printf "%-4s %-30s %-10s %-10s %-15s\n" "───" "──────────────────────────────" "──────────" "──────────" "──────────────"
|
||||||
|
|
||||||
|
local n=0
|
||||||
|
for wt in "$WORKTREE_ROOT"/*/; do
|
||||||
|
[ -d "$wt" ] || continue
|
||||||
|
local name
|
||||||
|
name=$(basename "$wt")
|
||||||
|
local branch; branch="$(_wt_branch "$name")"
|
||||||
|
local commits="?"
|
||||||
|
[ -d "$wt/.git" ] && commits=$(cd "$wt" && git rev-list --count "$branch" -- 2>/dev/null || echo "?")
|
||||||
|
commits="${commits:-0}"
|
||||||
|
|
||||||
|
# spec status
|
||||||
|
local spec="?"
|
||||||
|
[ -d "$REPO/openspec/changes/$name" ] && {
|
||||||
|
spec=$(cd "$REPO" && openspec status --change "$name" --json 2>/dev/null | \
|
||||||
|
python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('artifacts_completed','?'),'/',d.get('artifacts_total','?'),sep='')" 2>/dev/null || echo "active")
|
||||||
|
}
|
||||||
|
|
||||||
|
n=$((n+1))
|
||||||
|
printf "%-4s %-30s %-10s %-10s %-15s\n" \
|
||||||
|
"$n." "$name" "$commits" "${spec:-active}" "$wt"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$n" -eq 0 ]; then
|
||||||
|
echo " (no active features)"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_clean() {
|
||||||
|
local name="$1"
|
||||||
|
cd "$REPO"
|
||||||
|
local wt; wt="$(_wt_path "$name")"
|
||||||
|
local branch; branch="$(_wt_branch "$name")"
|
||||||
|
|
||||||
|
git worktree remove "$wt" 2>/dev/null || true
|
||||||
|
git branch -D "$branch" 2>/dev/null || true
|
||||||
|
if [ ! -d "$wt" ]; then
|
||||||
|
_ok "cleaned $name"
|
||||||
|
else
|
||||||
|
_die "could not remove $wt"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── dispatch ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
init)
|
||||||
|
cmd_init
|
||||||
|
;;
|
||||||
|
spec)
|
||||||
|
[ $# -ge 2 ] || _die "usage: dev-orchestrator spec <feature-name>"
|
||||||
|
cmd_spec "$2"
|
||||||
|
;;
|
||||||
|
fill)
|
||||||
|
[ $# -ge 2 ] || _die "usage: dev-orchestrator fill <feature-name>"
|
||||||
|
cmd_fill "$2"
|
||||||
|
;;
|
||||||
|
build)
|
||||||
|
[ $# -ge 2 ] || _die "usage: dev-orchestrator build <feature-name>"
|
||||||
|
cmd_build "$2"
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
cmd_status
|
||||||
|
;;
|
||||||
|
clean)
|
||||||
|
[ $# -ge 2 ] || _die "usage: dev-orchestrator clean <feature-name>"
|
||||||
|
cmd_clean "$2"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "dev-orchestrator — OpenSpec + OpenCode dev→QA loop"
|
||||||
|
echo ""
|
||||||
|
echo "commands:"
|
||||||
|
echo " init Set up repo (run once per project)"
|
||||||
|
echo " spec <feature-name> Scaffold OpenSpec + worktree (no fill)"
|
||||||
|
echo " fill <feature-name> AI fills spec after exploration"
|
||||||
|
echo " build <feature-name> Dev→QA loop in isolated worktree"
|
||||||
|
echo " status Kanban view of features in flight"
|
||||||
|
echo " clean <feature-name> Remove worktree + branch"
|
||||||
|
echo ""
|
||||||
|
echo "flow: init → spec → [explore in OpenCode] → fill → build → [QA loop]"
|
||||||
|
echo ""
|
||||||
|
echo "worktrees live at: ../.worktrees/<feature>/"
|
||||||
|
echo "branches named: dev-flow/<feature>"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Reference in New Issue
Block a user