← Files Pesquisa MirandasTechARCHIVED FILE

scripts/iniciar_projeto.py

14.4 KB · Oct 2, 2026 · 00:33 UTC

↓ Download file

#!/usr/bin/env python3
"""Cria (ou complementa) a pasta de um projeto de pesquisa conforme os manuais MirandasTech.

    python3 scripts/iniciar_projeto.py <pasta> --tema "..." [--metodo "..."] [--programa "..."] [--prazo AAAA-MM]

Cria a estrutura de pastas, copia os modelos, gera o PROGRESSO.md único (fases do Pesquisador +
checklists de Método, Uso de IA e Biblioteca) e inicializa o Git. Nunca sobrescreve o que já existe;
se a pasta veio de um dos manuais antigos (PROGRESSO_IA.md, PROGRESSO_METODOLOGIA.md), migra os
itens marcados para o PROGRESSO.md e mantém os arquivos antigos como histórico.
"""
import argparse, re, shutil, subprocess, sys
from datetime import date
from pathlib import Path
AQUI = Path(__file__).resolve().parent.parent; MODELOS = AQUI / "modelos"
ESQUEMA = 1  # versão da estrutura do PROGRESSO.md (fases + checklists M/I/B/L); suba ao mudar tabelas ou colunas
PASTAS = ["00_projeto", "00_protocolo", "01_revisao/fichas", "01_buscas", "02_instrumentos", "02_triagem", "03_etica", "03_extracao",
          "04_sintese", "05_analise", "06_texto", "07_banca", "tools", "dados_FORA_DO_GIT"]
FASES = [
 ("0", "Diagnóstico", "Tema, prazo, programa, orientador e ferramentas registrados; pasta criada", "Pesquisador"),
 ("1", "Pergunta", "Tema delimitado → problema → pergunta com tabela vazia do resultado → objetivos", "Metodólogo"),
 ("2", "Método", "Classificação, desenho, amostra, instrumento, análise; o que a IA pode fazer aqui", "Metodólogo · Orientador"),
 ("3", "Projeto e ética", "Projeto NBR 15287:2025; parecer do CEP quando houver pessoas", "Metodólogo"),
 ("4", "Busca e biblioteca", "Bases, strings verbatim, coleção por base e data; auditoria da biblioteca", "Metodólogo · Bibliotecário"),
 ("5", "Triagem", "Deduplicação, triagem assistida com status preliminar, decisão do aluno, números do PRISMA", "Orientador · Bibliotecário"),
 ("6", "Leitura e síntese", "PDFs do Zotero → notebook; fichamento; matriz de síntese conferida célula a célula", "Leitura (Gemini Notebook)"),
 ("7", "Análise", "Coleta e análise conforme o método; IA só onde autorizada e registrada", "Metodólogo · Orientador"),
 ("8", "Escrita ABNT", "NBR 14724, 10520, 6023 via Zotero; verificação automática de citações e referências", "Bibliotecário · scripts"),
 ("9", "Pré-banca", "Cinco objeções mais fortes, perguntas prováveis, respostas com página", "Metodólogo · Leitura"),
 ("10", "Entrega", "Declaração de uso de IA, backup, versão congelada da biblioteca, checklist final", "Orientador · Bibliotecário"),
]
METODO = [
 ("Pergunta","Pergunta clara, delimitada, empírica e viável; tabela vazia do resultado","7"),("Objetivos","Objetivo geral = pergunta em ação; específicos geram resultado, não etapa","8"),
 ("Justificativa","Lacuna apontada com revisões; relevância; contribuição verificável","9"),("Revisão","Buscas registradas; matriz de síntese; fichas com página","10–11"),
 ("Classificação","Natureza, abordagem, objetivo e procedimento — uma resposta por eixo","12"),("Método","Frase «escolhi X porque…; descartei Y porque…» registrada","14"),
 ("Amostra","População, unidade, amostragem, n calculado e obtido","16"),("Instrumento","Tabela de operacionalização; juízes; pré-teste registrado","18"),
 ("Ética","Parecer do CEP com CAAE antes da coleta; TCLE arquivado; LGPD","6, 27"),("Análise","Técnica decidida antes; pressupostos; efeito com IC; categorias com trecho","21–22"),
 ("Reprodutibilidade","Dados, scripts, ambiente e decisões guardados; figura por script","24"),("Estrutura","NBR 14724:2024 / 15287:2025 e modelo do programa","25, 28"),
 ("Citações","NBR 10520:2023; diretas com página; sem paráfrase próxima","30"),("Referências","NBR 6023:2025 via gerenciador; DOI resolvido; texto ↔ lista","31"),
 ("Texto","Números batem com tabelas; conclusão por objetivo; limites explícitos","32"),("Defesa","Cinco objeções com resposta; ensaio; material à mão","34"),
]
IA = [
 ("Governança","Acordo com o orientador assinado; protocolo congelado e datado antes da primeira busca; procedimento de emenda escrito","6, 17"),
 ("Governança","Arquivo de regras do agente com proibições absolutas, gates humanos e critério de conclusão","37"),
 ("Dados","Dado licenciado e pessoal fora do repositório; treinamento desligado nas ferramentas; hash registrado","9, 11"),
 ("Busca","String de cada base salva verbatim do histórico, com data, filtros, total e SHA-256 do export","18, 22"),
 ("Busca","Teste com e sem truncamento registrado; conjunto-semente com regra de decisão prévia","19, 21"),
 ("Triagem","Codebook versionado; toda recomendação de IA com status preliminar; decisão humana por registro","23, 28"),
 ("Triagem","κ com intervalo de confiança; grau de cegamento declarado; regra de parada do aprendizado ativo escrita antes","26, 27"),
 ("Acesso","Os três números do texto completo medidos separadamente; E5 declarado com lista","31"),
 ("Extração","Cada codificação com página e seção; extração assistida conferida no PDF; dupla codificação em amostra","32, 33"),
 ("Figuras","Toda figura gerada por script que lê o dado; nenhum número digitado; nenhuma imagem gerada por IA","34"),
 ("Referências","Todo DOI resolvido na Crossref na versão final; referência sem DOI com prova alternativa","42"),
 ("Texto","Marcas de IA contadas e removidas; um trecho lido em voz alta; comparação linha a linha com a versão do modelo","40, 41"),
 ("Texto","Todo número do texto bate com a tabela de origem; somas fecham; resumo contado","44"),
 ("Equipe","Registro de uso compartilhado com a coluna «quem»; todos os coautores leram o texto inteiro e aprovaram a declaração","12, 13"),
 ("Declaração","Uso de IA declarado com ferramenta, fase, finalidade, validação e o que a IA não fez","43"),
 ("Entrega","Guia de relato conferido item a item; disponibilidade de dados verdadeira no momento da submissão","16"),
]
BIBLIO = [
 ("Instalação","Zotero instalado do site oficial; Connector no navegador; ícone testado numa página com DOI","6–9"),
 ("Conta","Sincronização automática ligada; decisão sobre arquivos (Storage/WebDAV/nenhum) registrada","10"),
 ("Configurações","Idioma pt-BR; PDF automático e acesso aberto; renomeação automática; pasta de dados fora de nuvem sincronizada","11"),
 ("Estilo","Estilo ABNT instalado e testado com artigo, livro e tese; idioma da citação pt-BR","30–31"),
 ("Editor","Aba/menu Zotero visível no editor; Preferências do documento com ABNT","32–33"),
 ("Estrutura","Coleções por etapa e convenção de etiquetas escritas em DECISOES.md","20–21"),
 ("Auditorias","Pesquisas salvas «sem DOI», «sem PDF», «página da web» criadas","22"),
 ("Auditoria","scripts/auditar_biblioteca.py sem pendências críticas","49"),
 ("Leitura","Convenção de cores das anotações definida; nota extraída com página testada","27–28"),
 ("Exportação","Better BibTeX se houver LaTeX/Obsidian; .bib com «Manter atualizado»","38"),
 ("Backup","Backup da pasta de dados feito com o Zotero fechado; rotina agendada","41"),
 ("Grupo","Se há coautores: grupo privado criado, permissões e dono definidos","44"),
]
LEITURA = [
 ("Conta","Conta pessoal ou institucional escolhida sabendo a diferença de privacidade","7, 43"),
 ("Fontes","PDFs nomeados «Autor - Ano - Título» (do Zotero); nenhuma URL de editora; nenhum PDF escaneado sem OCR","11–14"),
 ("Ingestão","Pergunta de inventário rodada; guia de cada fonte aberto; fontes vazias corrigidas","19"),
 ("Citações","Trecho aberto e lido para cada afirmação usada; frases sem número descartadas","21"),
 ("Matriz","Colunas definidas pelo protocolo; primeira versão pelo notebook; cada célula conferida na planilha","34"),
 ("Dados sensíveis","Nada identificável enviado; transcrições anonimizadas; feedback não enviado em conversas com dados","43–45"),
 ("Declaração","Uso do notebook na leitura declarado; nada do Estúdio citado no texto","45"),
]
def migra(prog_antigo, marcados):
    if prog_antigo.exists():
        for ln in prog_antigo.read_text(encoding="utf-8").splitlines():
            m = re.match(r"\|\s*\d+\s*\|\s*([^|]+)\|\s*([^|]+)\|[^|]*\|\s*\[x\]", ln, re.I)
            if m: marcados.add(m.group(2).strip()[:40])
def main():
    ap = argparse.ArgumentParser(); ap.add_argument("pasta"); ap.add_argument("--tema", default="(a definir)"); ap.add_argument("--metodo", default="(a definir)")
    ap.add_argument("--programa", default="(a definir)"); ap.add_argument("--prazo", default="(a definir)")
    a = ap.parse_args(); raiz = Path(a.pasta).resolve(); raiz.mkdir(parents=True, exist_ok=True)
    for p in PASTAS: (raiz / p).mkdir(parents=True, exist_ok=True)
    def copia(src, dst):
        if not dst.exists(): shutil.copy(src, dst); print("  +", dst.relative_to(raiz))
    for m in ["AGENTS.md", "DECISOES.md", "USO_DE_IA.csv", "ACORDO_ORIENTADOR.md"]: copia(MODELOS / m, raiz / m)
    copia(MODELOS / "registro_exportacoes.csv", raiz / "01_buscas/registro_exportacoes.csv"); copia(MODELOS / "buscas.csv", raiz / "01_buscas/buscas.csv")
    copia(MODELOS / "matriz_sintese.csv", raiz / "04_sintese/matriz_sintese.csv"); copia(MODELOS / "tabela_operacionalizacao.csv", raiz / "02_instrumentos/tabela_operacionalizacao.csv")
    copia(MODELOS / "livro_de_codigos.csv", raiz / "05_analise/livro_de_codigos.csv"); copia(MODELOS / "TCLE_modelo.md", raiz / "03_etica/TCLE.md"); copia(MODELOS / "cronograma.csv", raiz / "00_projeto/cronograma.csv")
    copia(MODELOS / "estrutura_colecoes.md", raiz / "tools/zotero_estrutura_colecoes.md"); copia(MODELOS / "convencao_etiquetas.md", raiz / "tools/zotero_convencao_etiquetas.md")
    copia(MODELOS / "prompts_gemini_notebook.md", raiz / "tools/prompts_gemini_notebook.md"); copia(MODELOS / "estrutura_notebooks.md", raiz / "tools/gemini_notebook_estrutura.md")
    copia(MODELOS / "CODEBOOK.md", raiz / "02_triagem/CODEBOOK.md"); copia(MODELOS / "CONTAGENS.md", raiz / "02_triagem/CONTAGENS.md"); copia(MODELOS / "BUSCA.md", raiz / "01_buscas/BUSCA.md")
    dm = raiz / "00_projeto/DECISOES_METODO.md"
    if not dm.exists(): dm.write_text(f"# Decisões de método — {a.tema}\n\nRegistro da entrevista de decisão com o Metodólogo (uma seção por pergunta, com data).\n\n## Tema delimitado\n\n## Problema e lacuna\n\n## Pergunta e tabela vazia do resultado\n\n## Objetivos\n\n## Hipóteses / pressupostos e variáveis\n\n## Justificativa e delimitação\n\n## Classificação (4 eixos)\n\n## Desenho — «escolhi … porque …; descartei … porque …»\n\n## População, amostra, n\n\n## Técnicas e instrumentos\n\n## Análise\n\n## Ética\n\n## Cronograma e orçamento\n", encoding="utf-8"); print("  +", dm.relative_to(raiz))
    proto = raiz / "00_protocolo/protocolo.md"
    if not proto.exists(): proto.write_text(f"# Protocolo — {a.tema}\n\n**Método:** {a.metodo}\n**Congelado em:** (preencher — depois disso, só por emenda)\n\n1. Pergunta e subperguntas\n2. Bases e justificativa\n3. Blocos conceituais e strings (verbatim)\n4. Janela, idiomas, tipos documentais\n5. Critérios de inclusão e códigos de exclusão\n6. Procedimento de triagem\n7. Conjunto-semente\n8. Campos de extração e codebook\n9. Avaliação de qualidade\n10. Plano de síntese\n11. Gates humanos\n12. Procedimento de emenda\n\n## Emendas\n(nenhuma)\n", encoding="utf-8"); print("  +", proto.relative_to(raiz))
    marcados = set(); migra(raiz / "PROGRESSO_IA.md", marcados); migra(raiz / "PROGRESSO_METODOLOGIA.md", marcados); migra(raiz / "PROGRESSO_ZOTERO.md", marcados)
    prog = raiz / "PROGRESSO.md"
    if prog.exists():
        m = re.search(r"<!-- esquema: (\d+)", prog.read_text(encoding="utf-8")); v = int(m.group(1)) if m else 0
        if v < ESQUEMA: print(f"  ! PROGRESSO.md está no esquema {v} (atual: {ESQUEMA}); nada foi alterado — migração manual: confira as tabelas contra um projeto novo")
        elif v > ESQUEMA: print(f"  ! PROGRESSO.md está no esquema {v}, mais novo que este plugin ({ESQUEMA}); atualize o plugin")
    if not prog.exists():
        L = [f"# Progresso — {a.tema}", f"<!-- esquema: {ESQUEMA} · gerado por iniciar_projeto.py do plugin Pesquisa MirandasTech -->", "", f"**Método provável:** {a.metodo} · **Programa:** {a.programa} · **Prazo:** {a.prazo} · **Início:** {date.today().isoformat()}",
             "Manuais: https://metodologia.mirandastech.com.br/ · https://manual.mirandastech.com.br/ · https://zotero.mirandastech.com.br/ · https://notebook.mirandastech.com.br/", "",
             "Regra: um item só é marcado `[x]` pelo agente responsável depois de conferir a evidência (arquivo, script, número). Anote data e evidência ao lado. O aluno decide; o agente formula e registra em DECISOES.md.", "",
             "## Fases (Pesquisador)", "", "| Fase | Nome | Porta de saída | Quem conduz | Estado | Data | Evidência |", "|---|---|---|---|---|---|---|"]
        for n, nome, porta, quem in FASES: L.append(f"| {n} | {nome} | {porta} | {quem} | [ ] | | |")
        for titulo, itens, pref, manual in [("Método (Metodólogo)", METODO, "M", "metodologia.mirandastech.com.br"), ("Uso de IA (Orientador)", IA, "I", "manual.mirandastech.com.br"),
                                             ("Biblioteca (Bibliotecário)", BIBLIO, "B", "zotero.mirandastech.com.br"), ("Leitura e síntese (Gemini Notebook)", LEITURA, "L", "notebook.mirandastech.com.br")]:
            L += ["", f"## {titulo} — slides em {manual}", "", "| # | Área | Item | Slides | Estado | Data | Evidência conferida |", "|---|---|---|---|---|---|---|"]
            for i, (ar, it, sl) in enumerate(itens, 1):
                est = "[x] (migrado)" if it[:40] in marcados else "[ ]"
                L.append(f"| {pref}{i} | {ar} | {it} | {sl} | {est} | | |")
        prog.write_text("\n".join(L) + "\n", encoding="utf-8"); print("  +", prog.relative_to(raiz), f"({len(marcados)} itens migrados)" if marcados else "")
    gi = raiz / ".gitignore"
    txt = gi.read_text(encoding="utf-8") if gi.exists() else ""
    for linha in ["dados_FORA_DO_GIT/", "dados_restritos_FORA_DO_GIT/", "04_dados_FORA_DO_GIT/", "*.xlsx", "*.xls", "*.pdf", "exports/", ".env"]:
        if linha not in txt: txt = txt.rstrip("\n") + ("\n" if txt else "") + linha + "\n"
    gi.write_text(txt, encoding="utf-8")
    if not (raiz / ".git").exists(): subprocess.run(["git", "init", "-q"], cwd=raiz, check=False)
    print(f"projeto pronto em {raiz}"); print('No Claude Code: "Pesquisador, onde paramos?"  ·  No Codex: /pesquisador onde paramos')
    return 0
if __name__ == "__main__": sys.exit(main())

SHA-256: 350291937e8f76673ee2d96df56a82150c752c891d7bfd8ce009bc95a5ac24c7