Communitygithub.com

d1-cli — Tiendas D1 a partir da linha de comando

Compre na Tiendas D1 (Colômbia, d1.com.co) pelo terminal — pesquise o catálogo, encontre a loja física mais próxima, calcule o preço de uma cesta com base no estoque real da sua loja e obtenha um orçamento de entrega. A D1 roda VTEX IO (conta `d1tiendas`), então isso utiliza sua API pública sem nenhuma chave de administrador.

O que é d1-cli — Tiendas D1 a partir da linha de comando?

Este skill fornece uma interface de linha de comando para a Tiendas D1, a maior rede de descontos da Colômbia. Ele explora a API pública do VTEX IO da D1 (conta `d1tiendas`) sem exigir credenciais de administrador — o catálogo e o carrinho funcionam anonimamente, e um código enviado por e-mail (uso único) desbloqueia o histórico de pedidos. O skill lida com duas armadilhas importantes: a disponibilidade é regionalizada (uma consulta sem região retorna o catálogo nacional, que ninguém pode realmente comprar) e os preços chegam em duas unidades diferentes (a pesquisa informa pesos inteiros, o checkout informa centésimos, uma diferença silenciosa de 100x). Ele permite construir e precificar cestas, mas deliberadamente não pode pagar — em vez disso, fornece uma URL de checkout para um humano finalizar. O skill é útil para encontrar produtos ou preços da D1, verificar se a D1 entrega em um local, montar ou calcular o custo de uma cesta de supermercado da D1, comparar itens da D1 ou revisar pedidos anteriores. Ele não deve ser usado para outros varejistas colombianos (Éxito, Jumbo, Ara, Alkosto) e não suporta pagamento.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/broomva/skills/tree/HEAD/skills/commerce/d1-cli

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

O que d1-cli — Tiendas D1 a partir da linha de comando faz?

D1 é a maior rede de descontos da Colômbia. Sua loja virtual funciona com VTEX IO (conta d1tiendas), o que significa que a própria API pública do site é a superfície de integração — sem scraping, sem credenciais de administrador.

Invocar

cd skills/commerce/d1-cli

# 1. Defina seu ponto de entrega PRIMEIRO — todo o resto depende disso
bun run src/cli.ts region --lat 4.6486 --lng=-74.0628

# 2. Depois pesquise: preços e estoque agora são da sua loja, não do país
bun run src/cli.ts search leche entera --count 5
bun run src/cli.ts search --facets category-1/lacteos-y-huevos --sort price:asc

# 3. Calcule o preço de uma cesta sem tocar no carrinho
bun run src/cli.ts quote 262:2 892:1

# 3b. Ou deixe um orçamento decidir o que entra — termos, não SKUs
bun run src/cli.ts basket --budget 30000 arroz leche aceite huevos

# 4. Ou monte uma cesta de verdade e depois passe para um humano pagar
bun run src/cli.ts cart add 262 --qty 2
bun run src/cli.ts cart deliver-to
bun run src/cli.ts cart checkout      # imprime uma URL; não efetua pagamento

Adicione --json a qualquer comando para obter saída legível por agentes. Os códigos de saída são um contrato, e esta lista é a única cópia dele:

códigosignificadorepetir?
0funcionou—
1D1 recusou ou estava inacessível — ponto não entregável, SKU indisponível ou desconhecido, falhasim, pode ajudar
2o comando foi chamado incorretamentenunca ajuda
3funcionou e a resposta é "nenhum" (substitute, basket)nunca ajuda

Um agente que não consegue separar esses casos ou repete um erro de digitação para sempre ou desiste de uma falha transitória. 3 existe porque uma categoria vazia não é nenhuma das opções.

Observe que cart add define a linha para --qty; não adiciona a ela. Essa é a semântica da própria D1, verificada ao vivo.

As duas coisas que tornam a automação ingênua da D1 errada

A disponibilidade é regionalizada. Consulte o catálogo sem região e a D1 responde com o catálogo nacional, relatando confortáveis 10.000 unidades contra o vendedor virtual 1. Coloque o mesmo SKU em uma simulação de checkout para um endereço real e ele retorna withoutStock, porque a loja física que o entregaria não o tem. Sempre use d1 region primeiro; a CLI avisa em texto simples sempre que está mostrando preços nacionais.

Resolver uma região também é a parte menos intuitiva da API: as coordenadas vão como geoCoordinates={lon};{lat} — separados por ponto e vírgula, longitude primeiro. Uma vírgula, que é o que os próprios corpos JSON da VTEX usam para o mesmo par, é rejeitada com CHK0119 ("endereços devem ter um código postal ou geocoordenadas") — uma mensagem que parece que o parâmetro está faltando em vez de malformado. test/region.test.ts fixa isso para que uma limpeza não possa desfazer.

Os preços chegam em duas unidades. Para o SKU 262 (Leche Entera Latti 900 ml, COP 3.500 na prateleira):

APICampoValorUnidade
intelligent-searchPrice3500pesos inteiros
catalog_systemPrice3500.0pesos inteiros
checkout orderFormsellingPrice350000centésimos

Nenhum deles rotula sua unidade. catalog.ts normaliza tudo para centésimos na fronteira para que o resto do código tenha exatamente uma unidade, e um teste afirma que um preço originado da pesquisa é renderizado de forma idêntica a um originado do checkout.

O que ele não fará

d1 constrói e precifica cestas. Ele não paga. d1 cart checkout imprime a URL onde um humano revisa o total e conclui o pagamento.

Essa fronteira é verificada em dois lugares a partir de uma lista (src/endpoints.ts): em tempo de execução, D1Client.request recusa qualquer requisição cuja URL resolvida não seja a própria origem da D1 mais um de 18 caminhos aprovados antes que a requisição saia do processo; estaticamente, test/safety.test.ts falha se qualquer literal /api/ em qualquer lugar em src/ não for aprovado. Adicionar um endpoint — de pagamento ou outro — falha até que ele seja listado, portanto a decisão é tomada em vez de ser assumida por padrão.

A metade em tempo de execução é essencial e foi adicionada após uma revisão mostrar que uma verificação estática não é suficiente: --facets '../../../..' resolveu do endpoint de pesquisa para o fechamento do pedido enquanto todos os literais de origem permaneciam aprovados.

Dito de forma precisa, porque versões anteriores deste arquivo exageravam: nada aqui impede um contribuidor com acesso de escrita de editar a lista de permissões. Nenhum teste no repositório pode.

A única credencial que ele armazena é um token de sessão da loja virtual — a mesma coisa que um navegador logado possui, com escopo restrito aos próprios pedidos e carrinho do seu dono — gravado em ~/.config/d1-cli/session.json com modo 0600. Nenhum appKey/appToken de administrador VTEX é lido em nenhum lugar. O login é feito por um código enviado por e-mail de uso único; a autenticação por senha deliberadamente não é implementada.

O portão do checkout — sempre termine aqui

Finalize cada cesta com d1 cart checkout e aja de acordo com seu código de saída. Não como uma formalidade: é o único comando que verifica novamente todo o carrinho contra a D1 como ele está agora, e os carrinhos ficam desatualizados de maneiras que nada mais revela.

0  toda linha é entregável — a URL é segura para passar adiante
1  pelo menos uma linha NÃO PODE ser entregue; a URL é impressa, mas o carrinho está quebrado
2  o comando foi chamado incorretamente

Isso existe porque cada um desses casos aconteceu em uma cesta real:

  • Uma linha esgotou durante a noite. PAN ARTESANAL INTEGRAL ficou no tiene inventario horas depois de ser adicionada. O carrinho ainda renderizava, ainda tinha um total — um total que estava silenciosamente 6.490 a menos, porque a linha morta havia saído dele.
  • Uma mudança de endereço tornou todas as linhas inviáveis. Nove itens retornaram cannotBeDelivered enquanto cada um ainda tinha um SLA válido e o carrinho ainda mostrava um total pagável.
  • O frete foi subnotificado em 12x por uma alocação por linha que parecia um total.

Em todos os três, o carrinho parecia bem. Uma cotação feita anteriormente em uma sessão não é evidência sobre o carrinho agora, então nunca entregue uma URL de checkout que você obteve antes da última mutação — execute o portão novamente.

Quando ele retorna 1, --json fornece undeliverable[] nomeando as linhas, e readyToCheckout: false. Remova ou substitua essas linhas e execute novamente.

Substituindo uma linha que a D1 não pode fornecer

d1 substitute 192 --limit 5        # classifica produtos em estoque da mesma categoria

Saída 0 significa que há algo a propor; 3 significa que não há — um dos dois comandos que usam 3, junto com d1 basket.

Três, não um, e a distinção é o ponto: 1 significa "D1 recusou, ou não pôde ser acessada" em todos os outros lugares desta CLI, e convida a uma repetição. Uma categoria vazia nunca se torna não vazia com uma repetição, então um agente com uma política de repetir no código 1 ficaria em loop para sempre. Saída 0 com uma lista vazia é a outra resposta errada — ela é lida como sucesso e é atendida.

Cada candidato nomeia o que muda: marca, tamanho da embalagem, $/kg ou $/L, preço da embalagem, e qualquer aviso da Ley 2120 ganho ou perdido. Essa é a saída, não a pontuação. Uma -12% por litro para o mesmo 900 ml e o mesmo rótulo é uma proposta diferente de uma que chega com Exceso en Azúcares anexado, e apenas os deltas as diferenciam.

Proponha; não assuma. substitute nunca escreve — ele imprime o d1 cart add para um humano aprovar. Isso não é cautela por si só: o cliente duas vezes preferiu uma linha removida a um substituto errado, disse isso explicitamente, e estava certo em ambas as vezes. Apresente os candidatos e as compensações; deixe a pessoa decidir, e esteja disposto a remover a linha.

Três coisas que ele lhe dirá que valem a pena ler:

  • "Este item ainda está em estoque na sua loja." A disponibilidade é por loja, então uma linha que falhou em outro lugar pode estar bem aqui. Verifique antes de substituir qualquer coisa. Sem --lat/--lng ele diz isso em vez de adivinhar — não há loja para fazer uma afirmação por loja.
  • "ampliado para nível 2 de 3" — a categoria folha não tinha nada em estoque, então as sugestões vêm de um corredor mais amplo e são correspondentemente menos precisas.
  • "apenas N foram comparados" — a categoria é maior que uma página. Aumente --count. Isso é impresso também no resultado vazio, porque "nada aqui está em estoque" afirmado sobre uma varredura parcial precisa da ressalva mais, não menos.

Encontrando coisas quando o pedido é vago

Para "precisamos de arroz" em vez de "compre o SKU 1092", dois eixos importam e nenhum é padrão:

Classificar por preço unitário, não por preço da embalagem. --sort per-unit usa os dados PUM que a lei colombiana exige que a D1 publique. As duas classificações realmente discordam: ARROZ ESTÁNDAR 500 GRS é a embalagem mais barata a $1.550 e custa $3.100/kg, enquanto o melhor valor nos mesmos resultados é $2.775/kg — em uma sacola de $5.550 que não aparece em nenhum lugar dos cinco primeiros por preço de embalagem. Classificar por preço de embalagem dá uma resposta pior enquanto parece correta.

Como a pesquisa da D1 não pode classificar por isso, --sort per-unit ordena a página que você buscou, não todo o conjunto de resultados. Aumente --count (máx. 50) para ampliá-lo. A saída diz isso em vez de sugerir um superlativo que não pode sustentar, e nomeia quantos resultados não publicam tamanho e, portanto, não podem ser comparados.

O tamanho declarado de um multipacote é o pacote, não um item — não o "corrija". Um censo de todos os 1.600 produtos descobriu que, entre os multipacotes com nome correspondente, 44 dos 46 onde a D1 diz o suficiente para decidir declaram o total do pacote. Analisar N UN de um nome de produto e multiplicar corromperia esses 44 para corrigir 2. A contagem em um nome não é evidência sobre o que o PUM significa.

resolvePackSize portanto lê descrições em vez de nomes. Em todos os 1.548 produtos que carregam um PUM, ele age sobre os 10 cuja descrição afirma tanto um tamanho por item quanto uma contagem: três são corrigidos (SKU 718, 510, 1008), sete são confirmados como já declarando o pacote, e todo o resto é deixado como declarado.

Leia os rótulos de advertência. Os produtos carregam as advertências frontais da Colômbia (Exceso en Azúcares, Exceso en sodio, Exceso en grasas saturadas, Exceso en grasas trans, Contiene Edulcorantes) em warnings[] sob --json. A cobertura é parcial — aproximadamente 70–90% por categoria — então ausência significa "não declarado", nunca "seguro".

Em seguida, restrinja com d1 facets <query> (categoria, marca, subcategoria com contagens) antes de paginar: a pesquisa tem um limite de 50 páginas, então uma consulta ampla é melhor dividida por faceta do que percorrida.

Comandos

ComandoO que faz
region --lat --lngresolver e lembrar o ponto de entrega
search <query>encontrar produtos (--facets --sort --count --page --available)
suggest <partial> · trendingautocompletar · o que a Colômbia está pesquisando
categories · facets [query]árvore de departamentos · filtros para uma consulta
substitute <sku>o que comprar em vez disso, e o que muda (--limit --count)
quote <sku>[:qty]...precificar uma cesta, sem mutação no carrinho
`cart [showadd
login --email / --from-cookie · whoami · logoutconta
orders · order <id>histórico de pedidos (detalhe é ocultado para uma lista de permissões; --raw opta por incluir)
stores nearlojas D1 perto de um ponto — apenas localizações, a D1 não oferece coleta

Testes

bun test        # unidades monetárias, a pegadinha do ponto e vírgula, quantidade em cotação,
                # vacuidade de SKU desconhecido, normalização do carrinho, ocultação de pedidos, e
                # a lista de permissão de endpoints que limita a superfície de pagamento
bun run lint && bun run typecheck

Os códigos de saída são um contrato, não decoração — a tabela em Invocar acima é a única cópia dele.

Consulte README.md para o mapa completo de endpoints, o comportamento do nível de frete, e o que a API pública não fornecerá.

Individual skills in this repo

This repo contains 7 individual skills — each has its own dedicated page.

broomva/skills

Local TTS, voice cloning, voice design, and video dubbing via the OmniVoice Studio MCP server (open-source ElevenLabs alternative; nothing leaves the machine, runs on MPS/CUDA/CPU). Use when: (1) generating speech from text in any of 646 languages, (2) cloning a voice from a 3-second reference clip, (3) designing a voice by gender/age/accent/pitch/style, (4) dubbing a video into another language, (5) listing voice profiles or personality presets, (6) producing narration where privacy, cost, or absent API keys matter, (7) non-English narration where Edge TTS/kokoro fall short, (8) batch audio for blog posts or content pipelines. Triggers: 'omnivoice', 'voice clone', 'clone this voice', 'tts', 'narrate', 'generate speech', 'voice synthesis', 'dub video', 'voice design', 'local tts', 'multilingual voice', 'narrate this post', 'elevenlabs alternative'.

broomva/skills

>- Speak an explanation out loud while working in any project — tiered text-to-speech with a pluggable backend (ElevenLabs by default and quota-guarded, macOS `say` via `--fast` for free instant local speech, local OmniVoice as an unlimited private tier). Markdown-aware, so code fences, URLs and deep paths collapse to short spoken placeholders instead of being dictated character by character, while snake_case identifiers survive intact so the listener can still search for them. Every utterance is saved to disk for later replay. Also carries a **talk mode** toggle: turn it on and the agent speaks a full readback of every turn, for as long as that session lasts — the whole response, not a summary of it, with `brief` and `marker` levels for when you want less. Talk mode is off by default and scoped to the single session that enabled it, so parallel agents in other worktrees stay silent. Use when the user asks to hear something rather than read it — an explanation of a change, a walkthrough of what just happen...

broomva/skills

Stateful, local-first household toxics inventory + swap engine. Identify the items in a home that carry endocrine disruptors and persistent chemicals (BPA/BPS, phthalates, PFAS/PTFE, parabens, flame retardants, VOCs, microplastics), score each by *real* exposure (severity x presence x how it's used x condition), and track the swap to a safer alternative from "flagged" -> "sourced" -> "swapped". Ships a grounded, cited knowledge graph of ~20 hazards, ~40 item-classes, and ~40 alternatives. Hands sourcing off to the `procurer` skill. The skill's state is the source of truth — the agent is the app.

broomva/skills

Tekton — the shared architecture-intent substrate for co-designing systems with the agent. One typed graph across six tiers (system / journey / data / infra / decisions / qualities); views are queries, not separate diagrams. The canonical artifact is a diff-friendly YAML model both human and agent read and write; it renders to Mermaid (agent-legible, GitHub-native) and a self-contained tabbed HTML viewer (human-visual). Cross-tier traceability (`tekton query <from> <to>`) answers "which infra does this user-journey step touch?" as a path query. USE WHEN: designing or thinking deeply about architecture, a system, a data model, user journeys/flows, or a technical plan WITH the agent; when a Category-C HTML doc isn't enough because you need to see AND edit AND traverse the design across tiers; "let's design X", "architect this", "model the system", "draw the flow", "how does this fit together", "diagram this", "/tekton". NOT FOR: a one-off throwaway diagram (use Mermaid inline); prose-only ADRs (write the ADR...

broomva/skills

Generate a polished Remotion video and X thread showcasing the full agent skills inventory. Use when creating social media content about skills, rendering category-based skill visualizations, or producing animated showcases of agent capabilities. Triggers on "skills video", "showcase skills", "skills thread", "render skills", "social content for skills", or requests to visualize the skills inventory.

broomva/skills

OpenCaptions extension for Content Engine — adds intent-driven CWI (Caption With Intent) captions to the post-production pipeline. Hooks into the grade → caption → final stage. Generates captions that understand video intent (pitch, volume, emotion, emphasis) and style themselves accordingly with variable font weight, size, and color. Uses the OpenCaptions CLI or MCP server. Triggers on: 'add captions', 'opencaptions', 'CWI captions', 'intent captions'.

broomva/skills

Produce polished product launch videos using the Liquid Glass aesthetic — dark void backgrounds, 3D perspective floating UI panels, particle effects, spring animations, and cinematic pacing. Built on Remotion with Imagen 4.0 for frames and Veo 3.1 for B-roll. Use when: (1) creating a product demo or launch video, (2) showcasing a UI/app/tool with cinematic polish, (3) building a social-ready video from screenshots and renders, (4) applying the liquid glass floating panel style, (5) composing Remotion videos with 3D transforms and spring animations. Triggers on: 'launch video', 'product video', 'liquid glass video', 'demo video', 'showcase video', 'remotion video', 'floating panel', 'glass aesthetic'.

Habilidades Relacionadas