wendkeep 0.25.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/README.md +35 -13
- package/README.pt-BR.md +189 -0
- package/package.json +1 -1
- package/src/init.mjs +117 -28
- package/src/stats.mjs +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,41 @@ All notable changes to **wendkeep** are documented here. Format based on
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this project follows
|
|
5
5
|
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.27.0] — 2026-07-08
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- **Re-running `wendkeep init` no longer re-asks for the vault (or language) — and can't split your
|
|
11
|
+
data.** On a project already set up, init now reads the registered vault from
|
|
12
|
+
`.claude/settings.json` (`OBSIDIAN_VAULT_PATH`) and the locked locale from the vault's
|
|
13
|
+
`.brain/config.json`, reuses both, and skips the prompts. Previously a re-run (e.g. after
|
|
14
|
+
`npm i -D wendkeep@latest`) offered the *derived* default (`.<project>-vault`); accepting it — or
|
|
15
|
+
mistyping the name — created a **second, divergent vault**. `--vault` / `--locale` still override.
|
|
16
|
+
New exported `detectRegisteredVault()` / `readVaultLocale()`. `src/init.mjs`.
|
|
17
|
+
|
|
18
|
+
### Note
|
|
19
|
+
- You do **not** need `wendkeep init` for a routine update: the hooks live in the package
|
|
20
|
+
(`settings.json` calls `npx wendkeep hook …`), so `npm i -D wendkeep@latest` updates them.
|
|
21
|
+
Re-run `init` only when a release adds new wiring (the CHANGELOG says so); it's idempotent.
|
|
22
|
+
|
|
23
|
+
## [0.26.0] — 2026-07-08
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- **`wendkeep init` output now follows the chosen vault language.** Picking Português left the
|
|
27
|
+
whole summary + `[n/4]` steps + "Next steps" block in English; only the interactive prompts were
|
|
28
|
+
localized. All init output is now driven by a locale message set (pt-BR / en) resolved from the
|
|
29
|
+
language answer — "Próximos passos", "taxonomia do vault", "sensores semeados", etc. `src/init.mjs`.
|
|
30
|
+
|
|
31
|
+
## [0.25.1] — 2026-07-08
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
- **Landing page in the repo**: a static SVG hero (`docs/assets/wendkeep-hero.svg`, the knowledge
|
|
35
|
+
graph) embedded at the top of the README, plus the self-contained interactive landing at
|
|
36
|
+
`docs/index.html` (live Canvas graph; serve `docs/` via GitHub Pages for a public URL).
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
- `wendkeep stats` now says **"N dias ativos (first→last)"** — the count is distinct days *with
|
|
40
|
+
activity*, not the calendar span; the old "N dia(s)" read as calendar days.
|
|
41
|
+
|
|
7
42
|
## [0.25.0] — 2026-07-08
|
|
8
43
|
|
|
9
44
|
Cost trend/projection + shareable stats + launch assets.
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# wendkeep
|
|
2
2
|
|
|
3
|
+
[Português](README.pt-BR.md) · **English**
|
|
4
|
+
|
|
3
5
|
> **Your AI coding agent forgets every session. wendkeep makes it remember — in the Obsidian vault you already use.**
|
|
4
6
|
|
|
5
7
|
[](https://www.npmjs.com/package/wendkeep)
|
|
@@ -7,6 +9,10 @@
|
|
|
7
9
|

|
|
8
10
|

|
|
9
11
|
|
|
12
|
+
[](docs/index.html)
|
|
13
|
+
|
|
14
|
+
**In the graph:** 🔵 session · 🟣 decision · 🔴 bug · 🟢 learning · 🟡 change — every note, backlinked.
|
|
15
|
+
|
|
10
16
|
**A persistent‑memory harness for AI coding agents, built on your Obsidian vault.** Every Claude Code / Codex session is captured turn‑by‑turn into local Markdown — with token/cost tracking, auto‑extracted decisions, bugs and learnings, and a curated memory layer injected back at the start of the next session. On top of that memory core sits a native, zero‑dependency **change lifecycle** (spec → change → TDD → sensor‑gated archive) that keeps intent, work and proof wikilinked in one graph. 100% local, open‑core.
|
|
11
17
|
|
|
12
18
|
```bash
|
|
@@ -14,24 +20,28 @@ npm i -D wendkeep && npx wendkeep init # captures from the next session on
|
|
|
14
20
|
npx wendkeep import # backfill past Claude + Codex sessions
|
|
15
21
|
```
|
|
16
22
|
|
|
17
|
-
|
|
23
|
+
**▶ Interactive demo:** [`docs/index.html`](docs/index.html) — a self-contained page with the live knowledge‑graph hero. Open it locally (or serve `docs/` on any static host). The image above is a static render of it.
|
|
24
|
+
|
|
25
|
+
> **From one real production vault** (`npx wendkeep stats`): **308** sessions · **1,696** prompts · **$4,836** captured across **46 active days** (Jan–Jul 2026) · **15** models — every one a note in the graph.
|
|
26
|
+
|
|
27
|
+
<!-- Optional: drop a real Obsidian graph screenshot at docs/assets/graph.png and add it here (see docs/21-graph-screenshot.md). -->
|
|
18
28
|
|
|
19
29
|
> Extracted from a system in daily production use: the capture engine, cost tracking and graph wiring are battle‑tested; the cross‑platform installer (`wendkeep init`) and the native change loop are the newer parts. See [`docs/`](https://github.com/rogersialves/wendkeep/tree/main/docs) for the project's strategy and decision log.
|
|
20
30
|
|
|
21
31
|
---
|
|
22
32
|
|
|
23
|
-
##
|
|
24
|
-
|
|
25
|
-
The pieces to give a coding agent durable memory exist, but fragmented (qmd‑sessions, memsearch, Nexus, hand‑written hooks). wendkeep ships them as one turnkey package that lands the memory **inside the Obsidian graph you already use** — no manual setup, no snapshot to keep in sync.
|
|
33
|
+
## The problem: the context dies when the window closes
|
|
26
34
|
|
|
27
|
-
|
|
35
|
+
Decisions, dead ends, the reason you chose X over Y — gone next session. The pieces to fix that exist but are scattered (qmd‑sessions, memsearch, Nexus, hand‑written hooks). wendkeep ships them as one turnkey package that writes into a knowledge graph **inside the Obsidian vault you already use** — no manual setup, no snapshot to keep in sync.
|
|
28
36
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
| | |
|
|
38
|
+
|---|---|
|
|
39
|
+
| **Capture** — every turn, on disk | `SessionStart` / `Stop` hooks write each session to a dated Markdown note: prompts, iterations, files touched, wikilinks. |
|
|
40
|
+
| **Derive** — decisions, bugs, learnings | Pulled from the transcript into their own notes, backlinked to the session. Your history becomes navigable, not archival. |
|
|
41
|
+
| **Recall** — injected back | A budget‑capped `CORE` + `DIGEST` and the active change are fed to the agent at the next `SessionStart`. It resumes where it left off. |
|
|
42
|
+
| **Cost** — what it all cost | Per‑model, cache‑aware token pricing per session — plus `cost --trend` with a run‑rate projection across the whole vault. |
|
|
43
|
+
| **Multi‑agent** — one install, all agents | Detects the real provider (Claude Code, Codex, Copilot) at runtime. |
|
|
44
|
+
| **Local‑first** — no cloud, no account | Everything is plain Markdown on your disk. An optional MCP server (`@bitbonsai/mcpvault`) lets the agent read/write the vault. |
|
|
35
45
|
|
|
36
46
|
## Requirements
|
|
37
47
|
|
|
@@ -114,9 +124,9 @@ No re‑copying, no snapshot to re‑sync — the package is the single source o
|
|
|
114
124
|
| `wendkeep doctor [--vault P]` | Run a vault health check (integrity of sessions, registry, links). |
|
|
115
125
|
| `wendkeep --version` / `--help` | Version / usage. |
|
|
116
126
|
|
|
117
|
-
## Retroactive memory (`import`)
|
|
127
|
+
## Retroactive memory (`import`) — install today, remember yesterday
|
|
118
128
|
|
|
119
|
-
Install wendkeep into an existing project and it only remembers sessions **from now on**. `wendkeep import` fixes that:
|
|
129
|
+
Install wendkeep into an existing project and it only remembers sessions **from now on**. `wendkeep import` fixes that: one command backfills your project's past **Claude & Codex** sessions into the vault — deduped, dated, with cost — so the graph starts full, not empty. It rebuilds each transcript as a full session note in its **real** date folder — frontmatter (tagged with the transcript's real provider), one iteration block per turn, cost + subagent telemetry, derived decision/bug/learning notes, finalized closing. An offline replay of the live capture flow, so an imported note is indistinguishable from a captured one.
|
|
120
130
|
|
|
121
131
|
```bash
|
|
122
132
|
wendkeep import --vault .myproject-vault --dry-run # preview what would be imported (both agents)
|
|
@@ -143,6 +153,8 @@ explore → propose → apply (TDD) → verify → archive
|
|
|
143
153
|
- **Verify** — `wendkeep verify` runs the sensors your tasks declared (from `wendkeep.sensors.json` at the project root) and records `evidencia.json`. A critical red fails the gate; a `warning` red is advisory.
|
|
144
154
|
- **Archive** — `wendkeep change archive <slug>` **gates** on the evidence (blocks unless every declared critical sensor is green), promotes each capability's spec delta (`ADDED`/`MODIFIED`/`REMOVED`) into the living `07-Specs/<capability>.md`, moves the change to `_arquivo/`, and mints an ADR in `04-Decisões/`.
|
|
145
155
|
|
|
156
|
+
> The gate blocks unless the scaffold is filled, no task is open, evidence is fresh, and every declared requirement is covered. **`--force` is the human's call — never the agent's.**
|
|
157
|
+
|
|
146
158
|
`wendkeep init` also seeds **native process skills** (`wk-workflow`, `wk-tdd`, `wk-debugging`, `wk-brainstorming`, `wk-planning`, `wk-verify`) into `.brain/skills` and delivers them to `.claude/skills` — the *how* layer, zero‑dep. Optional companions (`context-mode`, `dotcontext`, `understand-anything`, `caveman`) remain an opt‑in extra layer.
|
|
147
159
|
|
|
148
160
|
### The loop in five minutes
|
|
@@ -193,6 +205,16 @@ The archive **gate** blocks unless: the change scaffold is filled (G0), no task
|
|
|
193
205
|
- **Transcript formats are agent‑internal** and can change between agent versions; parsing is isolated but may need updates.
|
|
194
206
|
- Installer wires **Claude Code** settings + `.mcp.json`. Codex hooks run on the same scripts but are not auto‑wired yet (import already covers past Codex sessions via `--source codex`).
|
|
195
207
|
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Stop re‑explaining your codebase every morning
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
npm i -D wendkeep && npx wendkeep init
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**[Install from npm](https://www.npmjs.com/package/wendkeep)** · **[Star on GitHub](https://github.com/rogersialves/wendkeep)** — MIT · open‑core · your data never leaves your disk.
|
|
217
|
+
|
|
196
218
|
## License
|
|
197
219
|
|
|
198
220
|
MIT
|
package/README.pt-BR.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# wendkeep
|
|
2
|
+
|
|
3
|
+
**Português** · [English](README.md)
|
|
4
|
+
|
|
5
|
+
> **Seu agente de código esquece cada sessão. O wendkeep faz ele lembrar — no cofre Obsidian que você já usa.**
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/wendkeep)
|
|
8
|
+

|
|
9
|
+

|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
[](docs/index.pt.html)
|
|
13
|
+
|
|
14
|
+
**No grafo:** 🔵 sessão · 🟣 decisão · 🔴 bug · 🟢 aprendizado · 🟡 mudança — cada nota, com backlink.
|
|
15
|
+
|
|
16
|
+
**Um harness de memória persistente para agentes de código, construído sobre o seu cofre Obsidian.** Cada sessão do Claude Code / Codex é capturada turno a turno em Markdown local — com rastreio de tokens/custo, decisões, bugs e aprendizados extraídos automaticamente, e uma camada de memória curada injetada de volta no início da próxima sessão. Sobre esse núcleo de memória fica um **ciclo de mudança** nativo e sem dependências (spec → change → TDD → archive com gate por sensor) que mantém intenção, trabalho e prova wikilinkados num só grafo. 100% local, open‑core.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm i -D wendkeep && npx wendkeep init # captura a partir da próxima sessão
|
|
20
|
+
npx wendkeep import # importa sessões passadas do Claude + Codex
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**▶ Demo interativo:** [`docs/index.pt.html`](docs/index.pt.html) — uma página autocontida com o herói de grafo vivo. Abra local (ou sirva `docs/` em qualquer host estático). A imagem acima é um render estático dele.
|
|
24
|
+
|
|
25
|
+
> **De um cofre de produção real** (`npx wendkeep stats`): **308** sessões · **1.696** prompts · **US$ 4.836** capturados em **46 dias ativos** (jan–jul 2026) · **15** modelos — cada uma delas uma nota no grafo.
|
|
26
|
+
|
|
27
|
+
> Extraído de um sistema em uso diário de produção: o motor de captura, o rastreio de custo e a fiação do grafo são testados em batalha; o instalador multiplataforma (`wendkeep init`) e o ciclo de mudança nativo são as partes mais novas. Veja [`docs/`](https://github.com/rogersialves/wendkeep/tree/main/docs) para a estratégia e o log de decisões do projeto.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## O problema: o contexto morre quando a janela fecha
|
|
32
|
+
|
|
33
|
+
Decisões, becos sem saída, o motivo de você ter escolhido X em vez de Y — some na próxima sessão. As peças pra resolver existem, mas espalhadas (qmd‑sessions, memsearch, Nexus, hooks feitos à mão). O wendkeep entrega tudo num pacote turnkey que escreve num grafo de conhecimento **dentro do cofre Obsidian que você já usa** — sem setup manual, sem snapshot pra manter sincronizado.
|
|
34
|
+
|
|
35
|
+
| | |
|
|
36
|
+
|---|---|
|
|
37
|
+
| **Captura** — cada turno, no disco | Os hooks `SessionStart` / `Stop` escrevem cada sessão numa nota Markdown datada: prompts, iterações, arquivos tocados, wikilinks. |
|
|
38
|
+
| **Deriva** — decisões, bugs, aprendizados | Puxados do transcript pra notas próprias, com backlink pra sessão. Seu histórico fica navegável, não arquivístico. |
|
|
39
|
+
| **Recall** — injetado de volta | Um `CORE` + `DIGEST` com budget capado e a change ativa são injetados no agente no próximo `SessionStart`. Ele retoma de onde parou. |
|
|
40
|
+
| **Custo** — quanto tudo custou | Preço por modelo, ciente de cache, por sessão — mais `cost --trend` com projeção run‑rate no cofre inteiro. |
|
|
41
|
+
| **Multi‑agente** — uma instalação, todos os agentes | Detecta o provedor real (Claude Code, Codex, Copilot) em runtime. |
|
|
42
|
+
| **Local‑first** — sem nuvem, sem conta | Tudo é Markdown puro no seu disco. Um MCP opcional (`@bitbonsai/mcpvault`) deixa o agente ler/escrever o cofre. |
|
|
43
|
+
|
|
44
|
+
## Requisitos
|
|
45
|
+
|
|
46
|
+
- Node.js ≥ 18
|
|
47
|
+
- Um agente de código com hooks (Claude Code hoje; Codex atendido pelos mesmos hooks)
|
|
48
|
+
- Obsidian (pra ver o grafo) — opcional, mas é o ponto
|
|
49
|
+
|
|
50
|
+
## Instalar & configurar
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# no seu projeto
|
|
54
|
+
npm install --save-dev wendkeep # ou: npm install -g wendkeep
|
|
55
|
+
npx wendkeep init
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
O `wendkeep init` é interativo e **idempotente**. Ele:
|
|
59
|
+
|
|
60
|
+
1. Cria a taxonomia de pastas do cofre e um `README.md` templado (cofre padrão: `<projeto>/.<nome-do-projeto>-vault`, ex.: `.MeuApp-vault`; sobrescreva com `--vault`).
|
|
61
|
+
2. **Mescla** os três hooks de sessão e o `OBSIDIAN_VAULT_PATH` no `.claude/settings.json` — sem atropelar suas configs (salva um `.bak`; arquivo ilegível fica intocado e um `.new` é escrito pra você mesclar).
|
|
62
|
+
3. Adiciona o servidor MCP **`wendkeep-vault`** ao `.mcp.json` pro agente ler/escrever o cofre. Pule com `--no-mcp` — ex.: quando o agente já tem um MCP de cofre. (`--no-mcp` pula *só o MCP do próprio wendkeep*; os MCPs de companion seguem `--companions`.)
|
|
63
|
+
4. Oferece fixar plugins/MCP **companion** (múltipla escolha; **nenhum** pré-marcado). Cada um é wirado do jeito mais agnóstico que suporta:
|
|
64
|
+
- **`context-mode`** — otimizador de contexto + memória FTS5, como servidor MCP no `.mcp.json` (qualquer agente).
|
|
65
|
+
- **`understand-anything`** — grafo de domínio do projeto, via um hook `understand-inject` no SessionStart que injeta o grafo quando gerado.
|
|
66
|
+
- **`caveman`** — modo de compressão de tokens; roda seu próprio instalador cross‑agent em agentes não‑Claude.
|
|
67
|
+
- **`dotcontext`** — *legado, não recomendado.* O loop a2 nativo do wendkeep (`change` / `verify` / gate) já faz o trabalho dele, então instalar **duplica o harness**. Ainda selecionável via `--companions dotcontext` pra quem já usa (ajuste com `--dotcontext-mcp` / `--dotcontext-hooks`), mas off por padrão.
|
|
68
|
+
|
|
69
|
+
Controle com `--companions <csv>` ou `--no-companions`. A camada de plugin do Claude Code (`extraKnownMarketplaces` + `enabledPlugins`) é wirada como bônus onde o companion tiver uma.
|
|
70
|
+
5. Instala um **sistema de cores** no `.obsidian/` do cofre: um snippet CSS que colore notas por tipo (sessão/decisão/bug/aprendizado, via as `cssclasses` que os hooks emitem) mais grupos de cor do grafo por pasta. Merge não‑destrutivo em `appearance.json`/`graph.json`; pule com `--no-colors`.
|
|
71
|
+
6. Semeia a **camada de memória curada**: `.brain/CORE.md` (a camada quente curada à mão, com as 3 seções obrigatórias) e `.brain/COMPACTION_PROTOCOL.md` (o guia do protocolo). As camadas automáticas (`DIGEST.md`, `index.jsonl`) são geradas pelos hooks. Valide a camada curada com `wendkeep validate-memory` (cap 25 linhas, 3 seções, sem segredos/PII).
|
|
72
|
+
7. Semeia a **camada de definições + skills**: `.brain/agents/` + `.brain/skills/` (fonte da verdade versionada), incluindo as skills de processo nativas `wk-workflow` / `wk-tdd` / `wk-debugging` / `wk-brainstorming` / `wk-planning` / `wk-verify` (algumas trazem templates, ex.: o `verdict-template.json` + prompt de revisor da `wk-verify`). O `init` roda o `wendkeep sync-defs` pra você, entregando em `.codex/agents/` + `.claude/skills/` (rode `sync-defs` de novo após editar o `.brain`).
|
|
73
|
+
8. Semeia o **ciclo change/spec**: as pastas `07-Specs/` + `08-Mudanças/` e um `wendkeep.sensors.json` nativo (um sensor `validate-memory` mais um por script detectado no `package.json`). Move o `wendkeep change` / `wendkeep verify` — veja **Ciclo de mudança** abaixo.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npx wendkeep init --vault "~/vaults/work" --project . --yes # não-interativo
|
|
77
|
+
npx wendkeep init --companions "context-mode,understand-anything" --yes
|
|
78
|
+
npx wendkeep init --no-companions --no-mcp --yes # zero companions, sem MCP do wendkeep
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Opções do `init`
|
|
82
|
+
|
|
83
|
+
| Flag | O que faz |
|
|
84
|
+
|---|---|
|
|
85
|
+
| `--vault <path>` | Pasta do cofre. Padrão `<projeto>/.<nome-do-projeto>-vault`; o init interativo pergunta. Aponte pra um cofre existente pra instalar nele. |
|
|
86
|
+
| `--project <path>` | Raiz do projeto a wirar (padrão: diretório atual). |
|
|
87
|
+
| `--locale <pt-BR\|en>` | Idioma do cofre — nomes das pastas, scaffold, skills. O init interativo pergunta; travado no init. |
|
|
88
|
+
| `--companions <csv>` | Companions a fixar: `context-mode,caveman,understand-anything` (padrão: **nenhum** — opte explicitamente; `dotcontext` é legado). |
|
|
89
|
+
| `--no-companions` | Não fixa nenhum companion. |
|
|
90
|
+
| `--no-mcp` | Pula o MCP de cofre **do próprio wendkeep** (`wendkeep-vault`). Os MCPs de companion seguem `--companions`. |
|
|
91
|
+
| `--no-colors` | Pula o sistema de cores do Obsidian (snippet `.obsidian` + grupos do grafo). |
|
|
92
|
+
| `--yes`, `-y` | Não-interativo; aceita os padrões (pula os prompts de idioma / cofre / companion). |
|
|
93
|
+
| `--force` | Sobrescreve os blocos de config do wendkeep existentes. |
|
|
94
|
+
|
|
95
|
+
Depois abra o cofre no Obsidian, mande um prompt de teste no seu agente e confirme que uma nota aparece em `02-Sessões/…` (ou `02-Sessions/…` num cofre `en`).
|
|
96
|
+
|
|
97
|
+
## Atualizar
|
|
98
|
+
|
|
99
|
+
Como os hooks vivem dentro do pacote instalado (o settings.json chama `npx wendkeep hook <name>`), atualizar é só:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npm update wendkeep
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Sem recopiar, sem snapshot pra re‑sincronizar — o pacote é a única fonte da verdade.
|
|
106
|
+
|
|
107
|
+
## Comandos
|
|
108
|
+
|
|
109
|
+
| Comando | O que faz |
|
|
110
|
+
|---|---|
|
|
111
|
+
| `wendkeep init` | Configura o wendkeep num projeto (taxonomia do cofre + settings + MCP + skills). |
|
|
112
|
+
| `wendkeep hook <name>` | Roda um hook de sessão; invocado pelo `settings.json` (lê o JSON do agente no stdin). |
|
|
113
|
+
| `wendkeep change <sub>` | Ciclo de mudança: `new [--simple]` / `list` / `show` / `status` / `done <id>` / `undone <id>` / `diff` / `archive [--force]`. |
|
|
114
|
+
| `wendkeep verify [--deep]` | Roda os sensores das tarefas da change; `--deep` monta o pacote de verificação independente. |
|
|
115
|
+
| `wendkeep spec <sub>` | Specs vivos: `list` / `show <capability>`. |
|
|
116
|
+
| `wendkeep sensors <sub>` | `list` / `add <id> "<comando>"` — vê/edita `wendkeep.sensors.json` (JSON Schema incluso). |
|
|
117
|
+
| `wendkeep cost [opts]` | Agrega o gasto de IA nas sessões do cofre — total, por modelo, por dia · `--top [N]` · `--trend [day\|week\|month]` (+ projeção) · `--write` (gera `00-Custo.md`) · `--json`. |
|
|
118
|
+
| `wendkeep stats [--vault P]` | Uma linha compartilhável: sessões · prompts · gasto · período · modelos (`--json`). |
|
|
119
|
+
| `wendkeep import [opts]` | **Memória retroativa** — importa sessões passadas de **Claude + Codex** pro cofre (dedup por `session_id`). `--source all\|claude\|codex` / `--from <dir>` / `--codex-from <dir>` / `--stamp-ids` / `--since d` / `--limit n` / `--dry-run` / `--json`. |
|
|
120
|
+
| `wendkeep dashboard [--force]` | (Re)gera os Bases filtrados por pasta + o MOC `00-Dashboard`. |
|
|
121
|
+
| `wendkeep lesson add "t" "l"` | Registra uma lição local do projeto (injetada no próximo SessionStart). |
|
|
122
|
+
| `wendkeep sync-defs` | Copia `.brain/agents\|skills` pro projeto (`.codex/agents`, `.claude/skills`). |
|
|
123
|
+
| `wendkeep validate-memory [path]` | Valida `.brain/CORE.md` (cap 25, 3 seções, sem segredos/PII). |
|
|
124
|
+
| `wendkeep doctor [--vault P]` | Roda um check de saúde do cofre (integridade de sessões, registry, links). |
|
|
125
|
+
| `wendkeep --version` / `--help` | Versão / uso. |
|
|
126
|
+
|
|
127
|
+
## Memória retroativa (`import`) — instale hoje, lembre de ontem
|
|
128
|
+
|
|
129
|
+
Instale o wendkeep num projeto existente e ele só lembra sessões **a partir de agora**. O `wendkeep import` conserta isso: um comando importa as sessões passadas de **Claude & Codex** do projeto pro cofre — dedup, datadas, com custo — então o grafo começa cheio, não vazio. Reconstrói cada transcript como uma nota de sessão completa na pasta datada **real** — frontmatter (taggeado com o provedor real), um bloco de iteração por turno, custo + telemetria de subagents, notas derivadas de decisão/bug/aprendizado, encerramento finalizado. Um replay offline do fluxo de captura vivo, então uma nota importada é indistinguível de uma capturada.
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
wendkeep import --vault .meuprojeto-vault --dry-run # prévia do que seria importado (os dois agentes)
|
|
133
|
+
wendkeep import --vault .meuprojeto-vault # escreve as notas
|
|
134
|
+
wendkeep import --vault .meuprojeto-vault --source codex # só Codex
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- **Os dois agentes por padrão** (`--source all`). As sessões do Claude vêm de `~/.claude/projects/<slug>/`; os rollouts do Codex de `~/.codex/sessions/**`, escopados pro projeto pelo `cwd` gravado em cada sessão (insensível a case e separador, subpastas inclusas). Estreite com `--source claude` / `--source codex`.
|
|
138
|
+
- Toda nota grava o **`session_id`** e o **`provider`** no frontmatter (captura live e import iguais). Carimbe notas antigas com `wendkeep import --stamp-ids` (preenche o id a partir do registry; idempotente).
|
|
139
|
+
- **Dedup** por `session_id` contra o `SESSION_REGISTRY` do cofre **e** o frontmatter das notas existentes — só importa sessões ausentes e nunca sobrescreve. Rodar de novo é no‑op.
|
|
140
|
+
- Depois de importar, o `wendkeep cost` agrega seu histórico inteiro — retroativamente, nos dois agentes.
|
|
141
|
+
|
|
142
|
+
## Ciclo de mudança — o loop a2 (spec‑driven, nativo)
|
|
143
|
+
|
|
144
|
+
Além de capturar sessões, o wendkeep é um **harness**: um loop nativo e sem dependências que mantém *intenção* (specs), *trabalho* (changes) e *prova* (sensores) juntos no cofre, wikilinkados no grafo Obsidian.
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
explore → propose → apply (TDD) → verify → archive
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
- **Propose** — `wendkeep change new <slug>` faz o scaffold de `08-Mudanças/<slug>/` (`proposta.md`, `design.md`, `tarefas.md` e um delta `specs/`). A change vira *ativa* e é injetada no próximo `SessionStart`, então o agente retoma o trabalho em curso.
|
|
151
|
+
- **Apply** — implemente cada tarefa de `tarefas.md`. Taggeie a tarefa que precisa de prova de máquina com `[sensor:<id>]`.
|
|
152
|
+
- **Verify** — `wendkeep verify` roda os sensores que suas tarefas declararam (do `wendkeep.sensors.json` na raiz do projeto) e grava `evidencia.json`. Um vermelho crítico falha o gate; um vermelho `warning` é aviso.
|
|
153
|
+
- **Archive** — `wendkeep change archive <slug>` faz **gate** na evidência (bloqueia a não ser que todo sensor crítico declarado esteja verde), promove o delta de cada capability (`ADDED`/`MODIFIED`/`REMOVED`) pro `07-Specs/<capability>.md` vivo, move a change pro `_arquivo/` e cunha um ADR em `04-Decisões/`.
|
|
154
|
+
|
|
155
|
+
> O gate bloqueia a não ser que o scaffold esteja preenchido, nenhuma tarefa aberta, evidência fresca e todo requisito declarado coberto. **`--force` é decisão do humano — nunca do agente.**
|
|
156
|
+
|
|
157
|
+
O `wendkeep init` também semeia **skills de processo nativas** (`wk-workflow`, `wk-tdd`, `wk-debugging`, `wk-brainstorming`, `wk-planning`, `wk-verify`) em `.brain/skills` e as entrega em `.claude/skills` — a camada do *como*, zero‑dep. Companions opcionais (`context-mode`, `dotcontext`, `understand-anything`, `caveman`) ficam como camada extra opt‑in.
|
|
158
|
+
|
|
159
|
+
## Como funciona
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
sessão do agente ──hooks──▶ wendkeep ──▶ Markdown no cofre ──▶ índice .brain + grafo Obsidian
|
|
163
|
+
(Claude/Codex) (Node) (02-Sessões/…) (CORE+DIGEST, backlinks)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
O settings.json do agente aponta cada hook pra `npx wendkeep hook …`. No `Stop`, o wendkeep parseia o transcript, anexa o turno, atualiza a tabela de tokens/custo e (idempotentemente) emite qualquer nota de decisão/bug/aprendizado. Em todo `SessionStart`, o `brain-inject` injeta de volta a memória curada (CORE + DIGEST), a change ativa, as lições do projeto e um roteador `<wk_process>` que roteia qualquer tarefa não‑trivial pelo loop a2 (planejar → `change new` + preencher o scaffold → TDD → verify → archive).
|
|
167
|
+
|
|
168
|
+
O **gate** do archive bloqueia a não ser que: o scaffold da change esteja preenchido (G0), nenhuma tarefa esteja aberta (G1), todo sensor crítico declarado esteja verde (com evidência fresca) e — quando a change declara `[req:]` — um `verdict.json` independente cubra eles. O `--force` é a saída de emergência humana; o agente é instruído a nunca usar por conta própria.
|
|
169
|
+
|
|
170
|
+
## Notas & roadmap
|
|
171
|
+
|
|
172
|
+
- **Nomes das pastas do cofre são em Português por padrão** (`02-Sessões`, `04-Decisões`, …). Passe `wendkeep init --locale en` pra um cofre em inglês (`02-Sessions`, `04-Decisions`, scaffold/skills em inglês). O locale é uma propriedade do cofre, travada no init; os parsers são bilíngues, então conteúdo misto nunca quebra.
|
|
173
|
+
- **Busca é scoring por keyword/frontmatter**, não embeddings on‑device (isso está no roadmap).
|
|
174
|
+
- **Formatos de transcript são internos ao agente** e podem mudar entre versões; o parsing é isolado mas pode precisar de atualizações.
|
|
175
|
+
- O instalador wira settings do **Claude Code** + `.mcp.json`. Os hooks do Codex rodam nos mesmos scripts mas ainda não são auto‑wirados (o import já cobre sessões Codex passadas via `--source codex`).
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Pare de reexplicar seu código toda manhã
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
npm i -D wendkeep && npx wendkeep init
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**[Instalar do npm](https://www.npmjs.com/package/wendkeep)** · **[Deixar uma star no GitHub](https://github.com/rogersialves/wendkeep)** — MIT · open‑core · seus dados nunca saem do seu disco.
|
|
186
|
+
|
|
187
|
+
## Licença
|
|
188
|
+
|
|
189
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wendkeep",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "A persistent-memory harness for AI coding agents on your Obsidian vault: turn-by-turn session capture plus a native, zero-dependency spec→change→verify→archive loop (sensor-gated, independent verdict, mutation discrimination). Local-first, agent-agnostic (Claude Code, Codex, Cursor…).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/init.mjs
CHANGED
|
@@ -223,6 +223,65 @@ export function promptStrings(localeId) {
|
|
|
223
223
|
return PROMPTS[localeId] || PROMPTS['pt-BR'];
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
// Output messages by locale — the summary, the [n/4] steps and the next-steps block follow the
|
|
227
|
+
// chosen vault language (before this, a pt-BR install still printed English output).
|
|
228
|
+
const MESSAGES = {
|
|
229
|
+
'pt-BR': {
|
|
230
|
+
header: '\nwendkeep init',
|
|
231
|
+
lProject: ' projeto ', lVault: ' vault ', lMcp: ' mcp ',
|
|
232
|
+
lCompanions: ' companions ', lColors: ' cores ',
|
|
233
|
+
skipped: 'ignorado', none: 'nenhum',
|
|
234
|
+
colorsOn: 'wendkeep-colors (snippet + grupos do grafo)',
|
|
235
|
+
taxonomy: (n, c, loc, readme, views) => ` [1/4] taxonomia do vault: ${n} pastas (${c} criadas, locale ${loc})${readme}, .brain + change/spec + sensores semeados${views}`,
|
|
236
|
+
readmeCreated: ', README.md criado', viewsNote: (n) => `, ${n} view(s) + dashboard`,
|
|
237
|
+
defs: (s, a) => ` defs entregues: ${s} skill(s) -> .claude/skills, ${a} agent(s) -> .codex/agents`,
|
|
238
|
+
settingsBadJson: (p) => ` [2/4] settings.json existe mas não é JSON válido -> escrevi ${p}.new (mescle à mão)`,
|
|
239
|
+
settings: (verb, added, bak) => ` [2/4] settings.json ${verb} (${added} hook(s) wirados, OBSIDIAN_VAULT_PATH setado${bak})`,
|
|
240
|
+
mcpBadJson: (p) => ` [3/4] .mcp.json existe mas não é JSON válido -> escrevi ${p}.new (mescle à mão)`,
|
|
241
|
+
mcp: (verb, names, bak) => ` [3/4] .mcp.json ${verb} (${names}${bak})`,
|
|
242
|
+
mcpSkipped: ' [3/4] .mcp.json ignorado (--no-mcp, sem companions MCP)',
|
|
243
|
+
colorsSkipped: ' [4/4] cores ignoradas (--no-colors)',
|
|
244
|
+
colors: (r) => ` [4/4] cores: ${r}`,
|
|
245
|
+
merged: 'mesclado', created: 'criado', bakSaved: ', .bak salvo',
|
|
246
|
+
nextSteps: '\nPróximos passos:',
|
|
247
|
+
step1: (v) => ` 1. Abra o vault no Obsidian: "Abrir pasta como cofre" -> ${v}`,
|
|
248
|
+
step2: ' 2. Garanta que o wendkeep está instalado onde o agente roda (npm i -D wendkeep, ou -g).',
|
|
249
|
+
step3: ' 3. Abra o Claude Code neste projeto e envie um prompt de teste.',
|
|
250
|
+
step4: ' 4. Confirme que uma nota aparece em 02-Sessões/<ano>/<mês>/DIA <dd>/ no vault.',
|
|
251
|
+
updateLater: ' Atualize depois com: npm update wendkeep (sem recopiar — os hooks vivem no pacote).\n',
|
|
252
|
+
vaultRegistered: (v, loc) => `\n cofre já registrado neste projeto: ${v} (locale ${loc}) — pergunta pulada. Use --vault para mudar.`,
|
|
253
|
+
},
|
|
254
|
+
en: {
|
|
255
|
+
header: '\nwendkeep init',
|
|
256
|
+
lProject: ' project ', lVault: ' vault ', lMcp: ' mcp ',
|
|
257
|
+
lCompanions: ' companions ', lColors: ' colors ',
|
|
258
|
+
skipped: 'skipped', none: 'none',
|
|
259
|
+
colorsOn: 'wendkeep-colors (snippet + graph groups)',
|
|
260
|
+
taxonomy: (n, c, loc, readme, views) => ` [1/4] vault taxonomy: ${n} folders (${c} created, locale ${loc})${readme}, .brain + change/spec + sensors seeded${views}`,
|
|
261
|
+
readmeCreated: ', README.md created', viewsNote: (n) => `, ${n} view(s) + dashboard`,
|
|
262
|
+
defs: (s, a) => ` defs delivered: ${s} skill(s) -> .claude/skills, ${a} agent(s) -> .codex/agents`,
|
|
263
|
+
settingsBadJson: (p) => ` [2/4] settings.json exists but is not valid JSON -> wrote ${p}.new (merge by hand)`,
|
|
264
|
+
settings: (verb, added, bak) => ` [2/4] settings.json ${verb} (${added} hook(s) wired, OBSIDIAN_VAULT_PATH set${bak})`,
|
|
265
|
+
mcpBadJson: (p) => ` [3/4] .mcp.json exists but is not valid JSON -> wrote ${p}.new (merge by hand)`,
|
|
266
|
+
mcp: (verb, names, bak) => ` [3/4] .mcp.json ${verb} (${names}${bak})`,
|
|
267
|
+
mcpSkipped: ' [3/4] .mcp.json skipped (--no-mcp, no MCP companions)',
|
|
268
|
+
colorsSkipped: ' [4/4] colors skipped (--no-colors)',
|
|
269
|
+
colors: (r) => ` [4/4] colors: ${r}`,
|
|
270
|
+
merged: 'merged', created: 'created', bakSaved: ', .bak saved',
|
|
271
|
+
nextSteps: '\nNext steps:',
|
|
272
|
+
step1: (v) => ` 1. Open the vault in Obsidian: "Open folder as vault" -> ${v}`,
|
|
273
|
+
step2: ' 2. Make sure wendkeep is installed where the agent runs (npm i -D wendkeep, or -g).',
|
|
274
|
+
step3: ' 3. Open Claude Code in this project and send a test prompt.',
|
|
275
|
+
step4: ' 4. Confirm a note appears under 02-Sessões/<year>/<month>/DIA <dd>/ in the vault.',
|
|
276
|
+
updateLater: ' Update later with: npm update wendkeep (no re-copying — hooks live in the package).\n',
|
|
277
|
+
vaultRegistered: (v, loc) => `\n vault already registered for this project: ${v} (locale ${loc}) — prompt skipped. Use --vault to change.`,
|
|
278
|
+
},
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
export function initMessages(localeId) {
|
|
282
|
+
return MESSAGES[localeId] || MESSAGES['pt-BR'];
|
|
283
|
+
}
|
|
284
|
+
|
|
226
285
|
// Map the language answer to a locale id. 2/en → en; 1/pt/empty/unknown → pt-BR.
|
|
227
286
|
export function parseLocaleAnswer(ans) {
|
|
228
287
|
const a = String(ans || '').trim().toLowerCase();
|
|
@@ -230,23 +289,53 @@ export function parseLocaleAnswer(ans) {
|
|
|
230
289
|
return 'pt-BR';
|
|
231
290
|
}
|
|
232
291
|
|
|
292
|
+
// The vault path this project was set up with — read from .claude/settings.json's
|
|
293
|
+
// OBSIDIAN_VAULT_PATH (written by a prior init). Empty when the project isn't configured yet.
|
|
294
|
+
export function detectRegisteredVault(projectPath) {
|
|
295
|
+
try {
|
|
296
|
+
const s = JSON.parse(readFileSync(join(projectPath, '.claude', 'settings.json'), 'utf8'));
|
|
297
|
+
const v = s && s.env && s.env.OBSIDIAN_VAULT_PATH;
|
|
298
|
+
return typeof v === 'string' && v ? v : '';
|
|
299
|
+
} catch { return ''; }
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// The locale locked in a vault's .brain/config.json (empty if absent/invalid).
|
|
303
|
+
export function readVaultLocale(vaultPath) {
|
|
304
|
+
try {
|
|
305
|
+
const c = JSON.parse(readFileSync(join(vaultPath, '.brain', 'config.json'), 'utf8'));
|
|
306
|
+
return c && LOCALES[c.locale] ? c.locale : '';
|
|
307
|
+
} catch { return ''; }
|
|
308
|
+
}
|
|
309
|
+
|
|
233
310
|
export async function runInit(argv) {
|
|
234
311
|
const args = parseArgs(argv);
|
|
235
312
|
const projectPath = resolve(args.project || process.cwd());
|
|
236
313
|
const log = (s) => process.stdout.write(`${s}\n`);
|
|
237
314
|
|
|
238
|
-
//
|
|
239
|
-
//
|
|
315
|
+
// Recognize an already-configured project: the vault is registered in the project's
|
|
316
|
+
// settings.json (OBSIDIAN_VAULT_PATH) and its locale is locked in the vault's config.json.
|
|
317
|
+
// On re-run (e.g. after `npm i -D wendkeep@latest`) we reuse both and SKIP the language + vault
|
|
318
|
+
// prompts — asking again risks a divergent vault from a mistyped name. `--vault` / `--locale`
|
|
319
|
+
// override; the vault question is a once-per-project thing.
|
|
320
|
+
const registeredVault = args.vault ? '' : detectRegisteredVault(projectPath);
|
|
321
|
+
if (registeredVault && !args.locale) args.locale = readVaultLocale(registeredVault) || args.locale;
|
|
322
|
+
|
|
323
|
+
// Language first (i18n): an interactive TTY without --locale (and not already registered) is
|
|
324
|
+
// asked the vault language; folders, prompts and scaffold all follow the answer.
|
|
240
325
|
if (!args.locale && process.stdin.isTTY && !args.yes) {
|
|
241
326
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
242
327
|
const ans = await rl.question('Idioma do vault / Vault language:\n [1] Português (pt-BR) [2] English (en)\n> ');
|
|
243
328
|
rl.close();
|
|
244
329
|
args.locale = parseLocaleAnswer(ans);
|
|
245
330
|
}
|
|
246
|
-
const
|
|
331
|
+
const resolvedLocale = args.locale && LOCALES[args.locale] ? args.locale : DEFAULT_LOCALE;
|
|
332
|
+
const P = promptStrings(resolvedLocale);
|
|
333
|
+
const M = initMessages(resolvedLocale);
|
|
247
334
|
|
|
248
|
-
let vaultPath = args.vault;
|
|
249
|
-
if (
|
|
335
|
+
let vaultPath = args.vault || registeredVault;
|
|
336
|
+
if (registeredVault) {
|
|
337
|
+
log(M.vaultRegistered(registeredVault, resolvedLocale));
|
|
338
|
+
} else if (!vaultPath) {
|
|
250
339
|
const fallback = join(projectPath, deriveVaultDirName(projectPath));
|
|
251
340
|
if (process.stdin.isTTY && !args.yes) {
|
|
252
341
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -285,12 +374,12 @@ export async function runInit(argv) {
|
|
|
285
374
|
companions = resolveCompanions({});
|
|
286
375
|
}
|
|
287
376
|
|
|
288
|
-
log(
|
|
289
|
-
log(
|
|
290
|
-
log(
|
|
291
|
-
log(
|
|
292
|
-
log(
|
|
293
|
-
log(
|
|
377
|
+
log(M.header);
|
|
378
|
+
log(`${M.lProject}: ${projectPath}`);
|
|
379
|
+
log(`${M.lVault}: ${vaultPath}`);
|
|
380
|
+
log(`${M.lMcp}: ${args.mcp ? 'mcpvault (wendkeep-vault)' : M.skipped}`);
|
|
381
|
+
log(`${M.lCompanions}: ${companions.length ? companions.join(', ') : M.none}`);
|
|
382
|
+
log(`${M.lColors}: ${args.noColors ? M.skipped : M.colorsOn}\n`);
|
|
294
383
|
|
|
295
384
|
// dotcontext controls (only relevant when selected): hook level + MCP placement.
|
|
296
385
|
// Skip the project MCP entry when dotcontext is already global (avoids a duplicate
|
|
@@ -329,7 +418,7 @@ export async function runInit(argv) {
|
|
|
329
418
|
let readmeNote = '';
|
|
330
419
|
if (!existsSync(readmePath)) {
|
|
331
420
|
writeFileSync(readmePath, renderVaultReadme({ projectName: basename(projectPath), vaultPath, withMcp: args.mcp, locale: loc.id }), 'utf8');
|
|
332
|
-
readmeNote =
|
|
421
|
+
readmeNote = M.readmeCreated;
|
|
333
422
|
}
|
|
334
423
|
// Seed the curated memory layer (CORE.md) + the compaction-protocol doc. The
|
|
335
424
|
// DIGEST/index are auto-generated by the hooks; CORE is hand-curated, so we
|
|
@@ -369,14 +458,14 @@ export async function runInit(argv) {
|
|
|
369
458
|
let viewsNote = '';
|
|
370
459
|
try {
|
|
371
460
|
const views = seedVaultViews(vaultPath);
|
|
372
|
-
if (views.length) viewsNote =
|
|
461
|
+
if (views.length) viewsNote = M.viewsNote(views.length);
|
|
373
462
|
} catch { /* views são bônus — nunca derrubam o init */ }
|
|
374
|
-
log(
|
|
463
|
+
log(M.taxonomy(folders.length, created, loc.id, readmeNote, viewsNote));
|
|
375
464
|
// Deliver the seeded defs (agents + wk process skills) to the project so they're
|
|
376
465
|
// usable immediately — no separate `wendkeep sync-defs` step needed.
|
|
377
466
|
const synced = syncDefs(vaultPath, projectPath);
|
|
378
467
|
if (synced.skills.length || synced.agents.length) {
|
|
379
|
-
log(
|
|
468
|
+
log(M.defs(synced.skills.length, synced.agents.length));
|
|
380
469
|
}
|
|
381
470
|
|
|
382
471
|
// 2. .claude/settings.json --------------------------------------------------
|
|
@@ -386,13 +475,13 @@ export async function runInit(argv) {
|
|
|
386
475
|
// Unparseable existing file — never clobber. Drop a .new for manual merge.
|
|
387
476
|
const fresh = mergeSettings(null, { vaultPath, withMcp: args.mcp, force: true, companions, skipMcp, dotcontextHookLevel }).settings;
|
|
388
477
|
writeJson(`${settingsPath}.new`, fresh);
|
|
389
|
-
log(
|
|
478
|
+
log(M.settingsBadJson(settingsPath));
|
|
390
479
|
} else {
|
|
391
480
|
const hadFile = settingsRead.data !== null;
|
|
392
481
|
const { settings, added } = mergeSettings(settingsRead.data, { vaultPath, withMcp: args.mcp, force: args.force, companions, skipMcp, dotcontextHookLevel });
|
|
393
482
|
if (hadFile) backup(settingsPath);
|
|
394
483
|
writeJson(settingsPath, settings);
|
|
395
|
-
log(
|
|
484
|
+
log(M.settings(hadFile ? M.merged : M.created, added, hadFile ? M.bakSaved : ''));
|
|
396
485
|
}
|
|
397
486
|
|
|
398
487
|
// 3. .mcp.json --------------------------------------------------------------
|
|
@@ -405,22 +494,22 @@ export async function runInit(argv) {
|
|
|
405
494
|
const names = [args.mcp && MCP_SERVER_KEY, ...Object.keys(companionMcp)].filter(Boolean).join(', ');
|
|
406
495
|
if (!mcpRead.ok) {
|
|
407
496
|
writeJson(`${mcpPath}.new`, mergeMcp(null, mcpOpts));
|
|
408
|
-
log(
|
|
497
|
+
log(M.mcpBadJson(mcpPath));
|
|
409
498
|
} else {
|
|
410
499
|
const hadFile = mcpRead.data !== null;
|
|
411
500
|
if (hadFile) backup(mcpPath);
|
|
412
501
|
writeJson(mcpPath, mergeMcp(mcpRead.data, mcpOpts));
|
|
413
|
-
log(
|
|
502
|
+
log(M.mcp(hadFile ? M.merged : M.created, names, hadFile ? M.bakSaved : ''));
|
|
414
503
|
}
|
|
415
504
|
} else {
|
|
416
|
-
log(
|
|
505
|
+
log(M.mcpSkipped);
|
|
417
506
|
}
|
|
418
507
|
|
|
419
508
|
// 4. Vault color system (.obsidian) -----------------------------------------
|
|
420
509
|
if (args.noColors) {
|
|
421
|
-
log(
|
|
510
|
+
log(M.colorsSkipped);
|
|
422
511
|
} else {
|
|
423
|
-
log(
|
|
512
|
+
log(M.colors(installVaultColors(vaultPath)));
|
|
424
513
|
}
|
|
425
514
|
|
|
426
515
|
// caveman has no MCP / agnostic-hook path: on non-Claude agents its skills come
|
|
@@ -437,10 +526,10 @@ export async function runInit(argv) {
|
|
|
437
526
|
log(` [!] add to .gitignore (wendkeep não toca git): ${DOTCONTEXT_GITIGNORE.join(' ')}`);
|
|
438
527
|
}
|
|
439
528
|
|
|
440
|
-
log(
|
|
441
|
-
log(
|
|
442
|
-
log(
|
|
443
|
-
log(
|
|
444
|
-
log(
|
|
445
|
-
log(
|
|
529
|
+
log(M.nextSteps);
|
|
530
|
+
log(M.step1(vaultPath));
|
|
531
|
+
log(M.step2);
|
|
532
|
+
log(M.step3);
|
|
533
|
+
log(M.step4);
|
|
534
|
+
log(M.updateLater);
|
|
446
535
|
}
|
package/src/stats.mjs
CHANGED
|
@@ -22,7 +22,8 @@ export function statsFrom(agg) {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export function statsLine(s) {
|
|
25
|
-
|
|
25
|
+
// "dias ativos" = distinct days WITH activity, not the calendar span (shown in parens).
|
|
26
|
+
const span = s.firstDay && s.lastDay ? ` · ${s.spanDays} dias ativos (${s.firstDay}→${s.lastDay})` : '';
|
|
26
27
|
return `wendkeep: ${num(s.sessions)} sessão(ões) · ${num(s.prompts)} prompts · ${usd(s.cost)} capturado${span} · ${s.models} modelo(s)`;
|
|
27
28
|
}
|
|
28
29
|
|