wendkeep 0.86.0 → 0.88.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/.githooks/commit-msg +16 -0
- package/.githooks/prepare-commit-msg +16 -0
- package/CHANGELOG.md +32 -0
- package/README.en.md +3 -1
- package/README.md +3 -1
- package/docs/en/commands/commit.md +159 -0
- package/docs/en/commands/observer-security.md +154 -0
- package/docs/en/commands/observer.md +30 -12
- package/docs/pt-BR/commands/commit.md +159 -0
- package/docs/pt-BR/commands/observer-security.md +154 -0
- package/docs/pt-BR/commands/observer.md +30 -12
- package/hooks/observer-publish.mjs +3 -1
- package/package.json +6 -2
- package/packages/cli/src/index.mjs +11 -1
- package/packages/commit/package.json +6 -0
- package/packages/commit/src/cli.mjs +89 -0
- package/packages/commit/src/commit-input.mjs +181 -0
- package/packages/commit/src/commit-message.mjs +51 -0
- package/packages/commit/src/commit-policy.mjs +144 -0
- package/packages/commit/src/git-runtime.mjs +428 -0
- package/packages/commit/src/index.mjs +28 -0
- package/packages/commit/src/proof-validation.mjs +443 -0
- package/packages/mcp/src/executor.mjs +35 -2
- package/packages/observer/package.json +16 -0
- package/packages/observer/src/audit.mjs +1 -0
- package/packages/observer/src/authz.mjs +38 -0
- package/packages/observer/src/encryption.mjs +75 -0
- package/packages/observer/src/index.mjs +7 -0
- package/packages/observer/src/policy.mjs +305 -0
- package/packages/observer/src/purge.mjs +100 -0
- package/packages/observer/src/redaction.mjs +54 -0
- package/packages/observer/src/retention.mjs +39 -0
- package/packages/observer/src/token-registry.mjs +122 -0
- package/schema/commit-message-v1.schema.json +75 -0
- package/schema/observer/006-observer-security.sql +64 -0
- package/schema/observer-policy-v1.schema.json +63 -0
- package/schema/sync-event-v1.schema.json +10 -0
- package/scripts/validate-commit-range.mjs +244 -0
- package/src/doctor.mjs +7 -0
- package/src/git-commit-hooks.mjs +112 -0
- package/src/init.mjs +13 -0
- package/src/observer-auth.mjs +8 -0
- package/src/observer-privacy.mjs +7 -3
- package/src/observer-publish.mjs +31 -0
- package/src/observer-server.mjs +179 -20
- package/src/observer-sql-migrate.mjs +5 -2
- package/src/observer-sql-publish.mjs +114 -39
- package/src/observer-sql-store.mjs +299 -45
- package/src/observer-transcript-store.mjs +23 -8
- package/src/observer.mjs +145 -12
- package/src/skills-seed.mjs +79 -0
- package/src/sync-protocol.mjs +20 -0
- package/web/observer/app.mjs +107 -31
- package/web/observer/index.html +7 -0
- package/web/observer/styles.css +5 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# Commits baseados em evidências
|
|
2
|
+
|
|
3
|
+
**PT-BR** · [English](../../en/commands/commit.md)
|
|
4
|
+
|
|
5
|
+
## Objetivo
|
|
6
|
+
|
|
7
|
+
Produzir a mesma mensagem auditável em Codex, Claude Code ou outro cliente Git, usando somente
|
|
8
|
+
entrada tipada, referências públicas e o resumo do index staged. O kernel é determinístico e não
|
|
9
|
+
lê o Vault, `.brain`, registros de sessão ou rede.
|
|
10
|
+
|
|
11
|
+
## Quando usar
|
|
12
|
+
|
|
13
|
+
Use antes de commits de implementação `feat`, `fix`, `refactor` ou `perf` que precisam registrar
|
|
14
|
+
autoridade causal, tarefas, testes, escopo e evidência verificável de forma equivalente entre
|
|
15
|
+
harnesses.
|
|
16
|
+
|
|
17
|
+
## Quando não usar
|
|
18
|
+
|
|
19
|
+
Não use para inventar prova, publicar conteúdo privado, reescrever histórico ou automatizar push.
|
|
20
|
+
Commits `docs`, `test` e `chore` dispensam contexto somente quando todos os arquivos alterados são
|
|
21
|
+
objetivamente documentação/testes. Alteração de produto exige o corpo governado mesmo com outro tipo.
|
|
22
|
+
|
|
23
|
+
## Pré-requisitos
|
|
24
|
+
|
|
25
|
+
Execute dentro de um repositório Git, com o WendKeep instalado localmente e os arquivos do produto
|
|
26
|
+
já selecionados no index staged.
|
|
27
|
+
|
|
28
|
+
## Sintaxe
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx --no-install wendkeep commit context --input <json|-> [--json]
|
|
32
|
+
npx --no-install wendkeep commit context --clear [--json]
|
|
33
|
+
npx --no-install wendkeep commit render --input <json|->
|
|
34
|
+
npx --no-install wendkeep commit prepare --message-file <path> [--source <source>]
|
|
35
|
+
npx --no-install wendkeep commit validate --message-file <path> [--json]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Opções e códigos de saída
|
|
39
|
+
|
|
40
|
+
- Exit `0`: contexto escrito/limpo ou mensagem válida.
|
|
41
|
+
- Exit `1`: mensagem governada inválida.
|
|
42
|
+
- Exit `2`: argumento, JSON, Git, privacidade ou contexto inválido/stale.
|
|
43
|
+
- `--consume-context` é reservado ao wrapper `commit-msg`; remove o contexto após validação verde.
|
|
44
|
+
|
|
45
|
+
## Instalação opt-in
|
|
46
|
+
|
|
47
|
+
Os hooks Git não são ativados pelo `init` padrão. Para copiar os wrappers portáteis e configurar
|
|
48
|
+
`core.hooksPath=.githooks` somente neste repositório:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx --no-install wendkeep init --git-commit-hooks --yes
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Hooks personalizados nunca são sobrescritos silenciosamente. Se o `init` encontrar conflito, ele
|
|
55
|
+
preserva o arquivo. Revise-o e, somente se quiser substituí-lo, execute novamente com `--force`; o
|
|
56
|
+
arquivo anterior fica em `.bak`.
|
|
57
|
+
Um `core.hooksPath` customizado também é conflito: sem `--force` ele permanece intocado.
|
|
58
|
+
|
|
59
|
+
## Exemplos
|
|
60
|
+
|
|
61
|
+
### Preparar um commit
|
|
62
|
+
|
|
63
|
+
Crie um JSON conforme `schema/commit-message-v1.schema.json`. Declare autoridade e referências de
|
|
64
|
+
evidência, mas não envie `tasks`, `tests`, `fresh` ou `verified`. O runtime deriva tarefas do
|
|
65
|
+
checklist canônico com Task Contracts concluídos. Testes vêm somente de sensores declarados por
|
|
66
|
+
`[sensor:<id>]` e executados pelo coletor; `[phase:verify]`
|
|
67
|
+
sozinho nunca é resultado. Sensors declarados no Envelope devem corresponder exatamente em IDs,
|
|
68
|
+
configuração, comando, severidade e resultado à reexecução canônica; apenas essa reexecução gera a
|
|
69
|
+
linha `Tests`. O gate remoto reexecuta o sensor no checkout do SHA correspondente.
|
|
70
|
+
Cada referência publicada recebe digest SHA-256 rederivado. ADR/design validam
|
|
71
|
+
ID/path/artefato. Tasks com `[req:]` exigem uma referência `spec` versionada e sanitizada que defina
|
|
72
|
+
cada requisito. Evidence Envelope, Verdict, receipt e TDD attestation podem participar da validação
|
|
73
|
+
local, mas são omitidos da Evidence remota: não há publicação de IDs de worktree/sessão/branch nem
|
|
74
|
+
promoção de consistência autocontida para prova. Se uma mensagem os alegar como `fresh`/`verified`,
|
|
75
|
+
o range rejeita `WENDKEEP_COMMIT_REMOTE_PROOF_UNAVAILABLE`. Os trailers fixos
|
|
76
|
+
`Remote-Proof-Scope: git,authority,tasks,spec,sensors` e `Local-Causal-Proof: unpublished` tornam
|
|
77
|
+
essa fronteira explícita. No range, authority/artefatos, task/spec, `Scope` Git e config/sensors são
|
|
78
|
+
rederivados do SHA, e apenas a reexecução canônica gera `Tests`. `Co-Authored-By` é
|
|
79
|
+
omitido enquanto não houver identidade registrada confiável.
|
|
80
|
+
|
|
81
|
+
A autoridade normal é a ADR causal:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{ "authority": { "kind": "adr", "adr": "ADR-1234", "ref": "docs/ADR-1234.md", "issue": "#123" } }
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Somente quando não existe change/ADR causal, o harness nativo pode declarar o fallback abaixo.
|
|
88
|
+
`issue` deve ser `#NNN` e `design` precisa estar versionado no mesmo commit sob
|
|
89
|
+
`docs/superpowers/specs/` ou `plans/`:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"authority": {
|
|
94
|
+
"kind": "native",
|
|
95
|
+
"issue": "#40",
|
|
96
|
+
"design": "docs/superpowers/specs/design-aprovado.md"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
O runtime confirma perfil efetivo `OFF`, ausência de context/change/lease e ADR causal reais, além
|
|
102
|
+
da issue no design. Esse modo gera trailers únicos `Authority: native-no-causal-change`, `Issue` e `Design`. Texto solto,
|
|
103
|
+
design não versionado, prova stale/unverified, corpo ou testes ausentes falham fechados.
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
git add <arquivos-do-produto>
|
|
107
|
+
npx --no-install wendkeep commit context --input commit-input.json
|
|
108
|
+
git commit -m "feat(escopo): rascunho"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`commit context` calcula o hash SHA-256 do diff staged e guarda o contexto sanitizado em
|
|
112
|
+
`.git/wendkeep-commit-input.json`, fora do working tree. `prepare-commit-msg` substitui o rascunho
|
|
113
|
+
pela mensagem canônica; `commit-msg` valida e consome o contexto. Se o index mudar, o contexto fica
|
|
114
|
+
stale e deve ser recriado.
|
|
115
|
+
O `commit-msg` relê o contexto, compara a mensagem inteira e o hash/files staged, e só consome o
|
|
116
|
+
contexto após sucesso. `merge`, `squash` e amend limpam contexto incompatível para não contaminar o
|
|
117
|
+
commit seguinte. `--message-file` fica contido no repositório ou git-dir.
|
|
118
|
+
|
|
119
|
+
Outros comandos:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
npx --no-install wendkeep commit render --input commit-input.json
|
|
123
|
+
npx --no-install wendkeep commit validate --message-file .git/COMMIT_EDITMSG
|
|
124
|
+
npx --no-install wendkeep commit context --clear
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Commits realmente triviais permanecem intactos. Commits de implementação
|
|
128
|
+
`feat`, `fix`, `refactor` e `perf` exigem assunto Conventional Commit com ADR ou o fallback nativo
|
|
129
|
+
restrito acima, seções Capability, Evidence, Tasks, Tests e Scope, hash staged e trailer
|
|
130
|
+
`WendKeep-Commit: v1`. Amend, merge e squash não recebem corpo duplicado ou prova inventada.
|
|
131
|
+
|
|
132
|
+
## Privacidade e falha segura
|
|
133
|
+
|
|
134
|
+
- Caminhos absolutos mesmo embutidos, qualquer Vault configurado/default, `.brain`, registros de sessão, PII e segredos são
|
|
135
|
+
rejeitados antes da persistência.
|
|
136
|
+
- Evidência `reported`, `legacy-unbound`, `stale` ou `unproven` não pode ser apresentada como prova.
|
|
137
|
+
- O contexto contém referências sanitizadas e metadados do diff, nunca o conteúdo privado do Vault.
|
|
138
|
+
- `--no-verify` não é um fluxo aceito: o CI valida cada commit novo, inclusive merges e resoluções inéditas.
|
|
139
|
+
|
|
140
|
+
## Resultado esperado
|
|
141
|
+
|
|
142
|
+
Uma mensagem determinística, autocontida, sem material privado, com hash do mesmo index que foi
|
|
143
|
+
commitado e trailers causais coerentes.
|
|
144
|
+
|
|
145
|
+
## Erros comuns e diagnóstico
|
|
146
|
+
|
|
147
|
+
`wendkeep doctor` mostra `[commit-hooks] healthy`, `disabled`, `missing` ou `drift` e permanece
|
|
148
|
+
read-only. Para recuperar arquivos ausentes ou divergentes após revisão:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
npx --no-install wendkeep init --git-commit-hooks --force --yes
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Se um commit for abandonado, limpe apenas o contexto transitório com
|
|
155
|
+
`wendkeep commit context --clear`. Nenhum comando reescreve histórico ou faz push automaticamente.
|
|
156
|
+
|
|
157
|
+
## Próximos passos
|
|
158
|
+
|
|
159
|
+
Revise a mensagem gerada, faça o commit e deixe o gate de range do PR validar qualquer bypass local.
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Segurança do Observer
|
|
2
|
+
|
|
3
|
+
**PT-BR** · [English](../../en/commands/observer-security.md)
|
|
4
|
+
|
|
5
|
+
## Objetivo
|
|
6
|
+
|
|
7
|
+
O Observer é um read model local ou de equipe, nunca uma nova autoridade sobre Vault, spec, memória
|
|
8
|
+
ou sync. O modelo de ameaça considera host remoto comprometido, token roubado, operador curioso,
|
|
9
|
+
banco/outbox copiados, payload adversarial e purge interrompido. Host/Origin continuam validados;
|
|
10
|
+
mutações e leituras sensíveis falham fechadas, inclusive no loopback.
|
|
11
|
+
|
|
12
|
+
| Classe | Padrão | Risco principal |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| documento | `metadata` | memória/decisões integrais |
|
|
15
|
+
| transcript | `metadata` | conversa e ferramentas |
|
|
16
|
+
| prompt/resposta | `redacted` | PII e segredos |
|
|
17
|
+
| uso | `aggregate` | custo e identidade operacional |
|
|
18
|
+
| audit/receipt | metadados mínimos | apagar a própria prova |
|
|
19
|
+
|
|
20
|
+
A policy v1 restringe por classe, `project_id`, glob de path e `entity_type`. Regras mais tardias
|
|
21
|
+
vencem apenas no projeto correspondente. Redaction cobre Bearer, credenciais em URL/connection
|
|
22
|
+
string, access keys, e-mail, telefone e regexes configuráveis seguras. O schema é
|
|
23
|
+
`schema/observer-policy-v1.schema.json`.
|
|
24
|
+
Em `transcript_capture: messages`, arrays, JSONL e o envelope canônico `{messages:[...]}` preservam
|
|
25
|
+
somente mensagens `user|assistant|system` com `role`/`content` string após redaction; campos extras,
|
|
26
|
+
tools e entradas malformadas são descartados ou falham fechados.
|
|
27
|
+
A policy explícita é a única autoridade de captura do publisher; `WENDKEEP_OBSERVER_CAPTURE_LEVEL`
|
|
28
|
+
é apenas compatibilidade traduzida para policy quando nenhum arquivo de policy foi fornecido e
|
|
29
|
+
nunca eleva nem suprime `none|metadata|messages|full` ou documentos `selected` explícitos.
|
|
30
|
+
Nos upserts de documento/transcript, `content_hash` sempre representa o conteúdo final após captura
|
|
31
|
+
e redaction; captura metadata/selected usa o SHA-256 do conteúdo vazio. Exclusões de documento
|
|
32
|
+
continuam efetivas mesmo com captura `none`, preservam path/revision/operação e nunca transportam
|
|
33
|
+
conteúdo ou hash obsoleto.
|
|
34
|
+
A redaction nunca reescreve campos validados de identidade estrutural, como IDs de projeto/evento/
|
|
35
|
+
entidade, paths lógicos, revisions ou operações. A privacidade do path é aplicada de modo fail-closed
|
|
36
|
+
pelas regras de captura por projeto/path, não pela renomeação da chave de storage por uma regra de
|
|
37
|
+
redaction de conteúdo.
|
|
38
|
+
O contrato estrutural por evento também preserva aliases snake/camel aceitos, chaves de documento/
|
|
39
|
+
sessão/agente/call/transcript/rollup, timestamps, roles, status, coverage, dimensões de modelo/preço,
|
|
40
|
+
workflow e proveniência de source. `title`, `summary`, `agent_name`, conteúdo, prompt/resposta e
|
|
41
|
+
metadata continuam como campos de display/conteúdo sujeitos a redaction.
|
|
42
|
+
Na publicação incremental, timestamps de turn ausentes ou vazios herdam o instante canônico do
|
|
43
|
+
lote, epoch numérico em milissegundos é normalizado para ISO 8601 e valor não vazio inválido falha
|
|
44
|
+
fechado antes da policy/store; evento e payload usam o mesmo instante.
|
|
45
|
+
|
|
46
|
+
## Quando usar
|
|
47
|
+
|
|
48
|
+
Use ao habilitar o Observer para dados reais, cadastrar ou revogar credenciais, restringir captura,
|
|
49
|
+
proteger SQLite/outbox, definir retenção ou eliminar dados com prova verificável.
|
|
50
|
+
|
|
51
|
+
## Quando não usar
|
|
52
|
+
|
|
53
|
+
Não use como KMS/secret manager corporativo, para publicar Vault/runtime, para substituir a
|
|
54
|
+
autoridade local ou para apagar manualmente tabelas e índices. Captura `full` continua opt-in e
|
|
55
|
+
sujeita à policy/redaction.
|
|
56
|
+
|
|
57
|
+
## Pré-requisitos
|
|
58
|
+
|
|
59
|
+
Use Node.js 22.13+, mantenha o bind no loopback e injete tokens/chaves somente por variáveis de
|
|
60
|
+
ambiente. O token de bootstrap é registrado somente pelo hash, exige projetos explícitos e
|
|
61
|
+
expiração finita; não é um admin wildcard fora do registry. Para Docker, defina também
|
|
62
|
+
`WENDKEEP_OBSERVER_BOOTSTRAP_PROJECTS`, `WENDKEEP_OBSERVER_BOOTSTRAP_EXPIRES_AT` e uma chave de
|
|
63
|
+
32 bytes em hex/base64 em `WENDKEEP_OBSERVER_ENCRYPTION_KEY`. O operador guarda a chave e receipts externos.
|
|
64
|
+
|
|
65
|
+
## Sintaxe
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npx wendkeep observer serve --token <token> --bootstrap-projects <p1,p2> --bootstrap-expires-at <ISO> [--bootstrap-token-id <id>] [--require-loopback-auth] [--require-encryption]
|
|
69
|
+
npx wendkeep observer security token create --project-id <projeto> --role <role> --scopes <scopes> --token-env <env> --expires-at <ISO>
|
|
70
|
+
npx wendkeep observer security token rotate --project-id <projeto> --token-id <id> --token-env <env> --expires-at <ISO> [--new-token-id <id>]
|
|
71
|
+
npx wendkeep observer security token revoke --project-id <projeto> --token-id <id>
|
|
72
|
+
npx wendkeep observer security policy set --project-id <projeto> --file <policy.json>
|
|
73
|
+
npx wendkeep observer security policy show --project-id <projeto>
|
|
74
|
+
npx wendkeep observer security purge --project-id <projeto> --before <ISO> --classes <classes> [--dry-run]
|
|
75
|
+
npx wendkeep observer security retention run --project-id <projeto> [--dry-run] [--operation-id <id>]
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Opções e códigos de saída
|
|
79
|
+
|
|
80
|
+
- `viewer` lê metadata/agregados; `auditor` pode receber scopes sensíveis; `publisher` ingere;
|
|
81
|
+
`admin` administra policy, purge e recovery. Role, scope e projeto precisam autorizar juntos.
|
|
82
|
+
- Tokens são persistidos somente como SHA-256; expiração, rotação e revogação valem sem restart.
|
|
83
|
+
- Após rotacionar o bootstrap, atualize token e token ID no ambiente; reiniciar nunca reativa a
|
|
84
|
+
credencial antiga revogada ou expirada.
|
|
85
|
+
- `--token-env` nomeia a variável com o segredo; o comando nunca imprime o valor.
|
|
86
|
+
- `--require-loopback-auth` protege toda a API; reads sensíveis exigem token mesmo sem a flag.
|
|
87
|
+
- `--require-encryption` falha se a chave externa estiver ausente ou inválida.
|
|
88
|
+
- `WENDKEEP_OBSERVER_REQUIRE_ENCRYPTION=1` aplica a mesma falha fechada a `status`, `security`,
|
|
89
|
+
`register`, `publish` e `reconcile`; com chave configurada, todo primeiro upgrade v5 usa apenas
|
|
90
|
+
`.bak.enc` + manifest antes de qualquer leitura/backfill.
|
|
91
|
+
- Exit `0` indica operação concluída; exit `1` indica configuração, autorização, policy, chave ou
|
|
92
|
+
operação inválida. O hook mantém exit `0` fail-open para o fluxo local, mas aborta antes de
|
|
93
|
+
persistir conteúdo inseguro.
|
|
94
|
+
|
|
95
|
+
O audit guarda capability, resultado, rota e horário, nunca Bearer, prompt, resposta ou payload.
|
|
96
|
+
|
|
97
|
+
## Exemplos
|
|
98
|
+
|
|
99
|
+
Recovery offline explícito e auditado:
|
|
100
|
+
|
|
101
|
+
```powershell
|
|
102
|
+
$env:OBSERVER_RECOVERY_TOKEN = '<segredo-forte-temporário>'
|
|
103
|
+
npx wendkeep observer security token create --data-dir C:\WendKeepObserver `
|
|
104
|
+
--project-id project-a --role admin --scopes '*' --token-env OBSERVER_RECOVERY_TOKEN `
|
|
105
|
+
--expires-at 2026-09-29T12:00:00Z --reason 'offline recovery' --json
|
|
106
|
+
npx wendkeep observer security token revoke --data-dir C:\WendKeepObserver `
|
|
107
|
+
--project-id project-a --token-id <id> --reason 'recovery complete' --json
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Sempre faça dry-run antes do purge. O runner de retenção é explícito/idempotente (CLI ou
|
|
111
|
+
`POST /v1/projects/:id/security/retention`), sem timer oculto:
|
|
112
|
+
|
|
113
|
+
```powershell
|
|
114
|
+
npx wendkeep observer security purge --data-dir C:\WendKeepObserver `
|
|
115
|
+
--project-id project-a --before 2026-08-01T00:00:00Z `
|
|
116
|
+
--classes documents,calls,transcripts --dry-run --json
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```powershell
|
|
120
|
+
npx wendkeep observer security retention run --data-dir C:\WendKeepObserver `
|
|
121
|
+
--project-id project-a --operation-id scheduled-2026-08-29 --dry-run --json
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Resultado esperado
|
|
125
|
+
|
|
126
|
+
TTL é independente para documentos, calls e transcripts. Contagens, remoção de projeções/FTS,
|
|
127
|
+
eventos e receipt usam a mesma transação; retry é idempotente e dado antigo tardio gera nova prova.
|
|
128
|
+
|
|
129
|
+
AES-256-GCM usa AAD por projeto/classe/registro/campo e `keyProvider` externo. O backfill v6 remove
|
|
130
|
+
plaintext e índices derivados antes de liberar leituras; chave errada falha sem revelar conteúdo.
|
|
131
|
+
A migration estrutural `006-observer-security.sql` cria backup, valida checksum, faz rollback e
|
|
132
|
+
permite retry. Em modo at-rest obrigatório, o backup é `.bak.enc`, tem manifest/key ID/permissão
|
|
133
|
+
restrita e restauração falha com chave errada; nenhum `.bak` plaintext permanece.
|
|
134
|
+
|
|
135
|
+
O hook aplica policy metadata/redacted por padrão; `WENDKEEP_OBSERVER_POLICY_FILE` seleciona policy
|
|
136
|
+
explícita. `WENDKEEP_OBSERVER_OUTBOX_KEY_ENV` nomeia a variável da chave da outbox e
|
|
137
|
+
`WENDKEEP_OBSERVER_OUTBOX_KEY_ID` identifica a chave. O Compose exige autenticação e criptografia.
|
|
138
|
+
O painel guarda Bearer somente em memória, exporta cópia sanitizada e expõe Segurança. MCP exige
|
|
139
|
+
scope para calls/busca integral. Sync leva apenas `policy_ref`, sem duplicar tokens ou autoridade.
|
|
140
|
+
|
|
141
|
+
## Erros comuns e diagnóstico
|
|
142
|
+
|
|
143
|
+
- `observer_token_missing|expired|revoked`: crie/rotacione um token escopado ou faça recovery offline.
|
|
144
|
+
- `observer_project_forbidden|role_forbidden|scope_forbidden`: confira a interseção projeto/role/scope.
|
|
145
|
+
- `observer_encryption_key_unavailable|observer_decryption_failed`: confira key ID e material externo;
|
|
146
|
+
nunca enfraqueça o modo obrigatório.
|
|
147
|
+
- `observer_policy_invalid`: valide campos/captures e remova regex inválida ou explosiva.
|
|
148
|
+
- Falha de migration v6: preserve `.pre-006-*.bak.enc` e seu manifest, corrija a causa e repita.
|
|
149
|
+
|
|
150
|
+
## Próximos passos
|
|
151
|
+
|
|
152
|
+
Leia [Observer local](observer.md), faça um dry-run de retenção, valide token revogado/expirado e
|
|
153
|
+
guarde o receipt fora do banco quando precisar de prova externa. Nunca publique banco, backup,
|
|
154
|
+
outbox, chave, token ou `/data`.
|
|
@@ -26,7 +26,9 @@ pelos hooks e pelo WendKeep local.
|
|
|
26
26
|
|
|
27
27
|
Tenha Node.js 22.13 ou mais recente para executar o Observer SQL. O Keep Core e os demais comandos
|
|
28
28
|
continuam compatíveis com Node.js 18 ou mais recente. Registre explicitamente cada projeto e defina
|
|
29
|
-
`WENDKEEP_OBSERVER_TOKEN
|
|
29
|
+
`WENDKEEP_OBSERVER_TOKEN`. Toda mutação e toda leitura de conteúdo sensível exigem Bearer, inclusive
|
|
30
|
+
no loopback; metadados e agregados podem permanecer abertos localmente quando
|
|
31
|
+
`--require-loopback-auth` não é usado. Veja [Segurança do Observer](observer-security.md).
|
|
30
32
|
|
|
31
33
|
## Sintaxe
|
|
32
34
|
|
|
@@ -36,7 +38,7 @@ npx wendkeep observer register --project <projeto> --vault <vault> --data-dir <d
|
|
|
36
38
|
npx wendkeep observer publish --project <projeto> --vault <vault> --data-dir <diretório>
|
|
37
39
|
npx wendkeep observer reconcile --project <projeto> --vault <vault> --data-dir <diretório> [--url http://127.0.0.1:8787]
|
|
38
40
|
npx wendkeep observer memory import --project <projeto> --vault <vault> --url http://127.0.0.1:8787 --token <token> --json
|
|
39
|
-
npx wendkeep observer serve --host 127.0.0.1 --port 8787 --data-dir <diretório> --token <token>
|
|
41
|
+
npx wendkeep observer serve --host 127.0.0.1 --port 8787 --data-dir <diretório> --token <token> --bootstrap-projects <p1,p2> --bootstrap-expires-at <ISO> [--require-loopback-auth] [--require-encryption]
|
|
40
42
|
```
|
|
41
43
|
|
|
42
44
|
## Opções e códigos de saída
|
|
@@ -46,7 +48,13 @@ npx wendkeep observer serve --host 127.0.0.1 --port 8787 --data-dir <diretório>
|
|
|
46
48
|
- `--project` e `--vault` identificam o projeto nos comandos `register`, `publish`, `reconcile` e `memory import`.
|
|
47
49
|
- `--host` aceita somente `127.0.0.1`, `localhost` ou `::1`; outros hosts são recusados antes do
|
|
48
50
|
listen.
|
|
49
|
-
- `--token` ou `WENDKEEP_OBSERVER_TOKEN`
|
|
51
|
+
- `--token` ou `WENDKEEP_OBSERVER_TOKEN` fornece o segredo de bootstrap hash-only; projetos
|
|
52
|
+
explícitos e expiração finita são obrigatórios, e toda mutação/leitura sensível passa pelo registry;
|
|
53
|
+
`--allow-non-loopback` falha sem token.
|
|
54
|
+
- `--require-loopback-auth` exige Bearer também para metadados e agregados locais e ativa a policy
|
|
55
|
+
segura do projeto na ingestão.
|
|
56
|
+
- `--require-encryption` exige `WENDKEEP_OBSERVER_ENCRYPTION_KEY` com 32 bytes em hex/base64; use
|
|
57
|
+
`WENDKEEP_OBSERVER_ENCRYPTION_KEY_ID` para identificar a chave externa.
|
|
50
58
|
- `WENDKEEP_OBSERVER_CAPTURE_LEVEL` aceita `metadata` (padrão, sem mensagens), `messages` ou
|
|
51
59
|
`full-transcript`. Caminhos locais absolutos nunca são publicados.
|
|
52
60
|
- Exit `0` indica sucesso; exit `1` indica falha de configuração ou operação; o hook publisher
|
|
@@ -57,7 +65,10 @@ npx wendkeep observer serve --host 127.0.0.1 --port 8787 --data-dir <diretório>
|
|
|
57
65
|
```powershell
|
|
58
66
|
npx wendkeep observer register --project C:\GitHub\WendKeep --vault C:\GitHub\WendKeep\.WendKeep-vault --data-dir C:\WendKeepObserver
|
|
59
67
|
$env:WENDKEEP_OBSERVER_TOKEN = '<token-local-forte>'
|
|
60
|
-
|
|
68
|
+
$env:WENDKEEP_OBSERVER_BOOTSTRAP_PROJECTS = 'project-a'
|
|
69
|
+
$env:WENDKEEP_OBSERVER_BOOTSTRAP_EXPIRES_AT = '2026-09-29T12:00:00Z'
|
|
70
|
+
$env:WENDKEEP_OBSERVER_ENCRYPTION_KEY = '<32-bytes-em-hex-ou-base64>'
|
|
71
|
+
npx wendkeep observer serve --host 127.0.0.1 --port 8787 --data-dir C:\WendKeepObserver --token $env:WENDKEEP_OBSERVER_TOKEN --require-loopback-auth
|
|
61
72
|
$env:WENDKEEP_OBSERVER_URL = 'http://127.0.0.1:8787'
|
|
62
73
|
```
|
|
63
74
|
|
|
@@ -67,15 +78,19 @@ Para Docker local:
|
|
|
67
78
|
docker compose -f docker/wendkeep-observer/compose.yaml up -d --build
|
|
68
79
|
```
|
|
69
80
|
|
|
81
|
+
O Compose exige token, allowlist/expiração do bootstrap e chave; inicia com autenticação integral
|
|
82
|
+
e criptografia obrigatória. A policy `encryption_required` recusa ingestão e outbox plaintext.
|
|
83
|
+
|
|
70
84
|
## Painel web local
|
|
71
85
|
|
|
72
86
|
Com o servidor em execução, abra [http://127.0.0.1:8787/](http://127.0.0.1:8787/) no navegador.
|
|
73
|
-
O painel é servido pelo mesmo processo
|
|
74
|
-
|
|
87
|
+
O painel é servido pelo mesmo processo. Informe o token no formulário local: ele fica somente na
|
|
88
|
+
memória da página, segue como Bearer nas consultas e é descartado ao recarregar. A porta fica presa
|
|
89
|
+
ao loopback do computador; não coloque o endereço em uma interface de rede.
|
|
75
90
|
|
|
76
91
|
O painel mostra a lista multi-projeto, versão, saúde, sessão mais recente, change ativa, contagem
|
|
77
92
|
de changes e data da última captura. Ao abrir um projeto, o workspace oferece Overview, Consumo,
|
|
78
|
-
Sessões, Memória, Changes e
|
|
93
|
+
Sessões, Memória, Changes, Sincronização e Segurança. A aba Consumo mostra custo total, tokens por categoria,
|
|
79
94
|
agentes principais, subagentes, provedores, modelos, tendência diária, cobertura histórica e
|
|
80
95
|
chamadas conforme o nível de captura escolhido. Os estados de carregamento, vazio, servidor
|
|
81
96
|
indisponível, conflito, modelo sem tarifa e dados desatualizados ficam visíveis, e a atualização
|
|
@@ -160,18 +175,21 @@ corte. As telas do Observer não concluem, arquivam, reparam ou promovem estado.
|
|
|
160
175
|
- `POST /v1/projects/:project_id/ingest` — lote idempotente de documentos, sessões, agentes, rollups,
|
|
161
176
|
chamadas e transcripts.
|
|
162
177
|
- `GET /v1/projects/:project_id/memory/tree` — árvore e metadados dos documentos.
|
|
163
|
-
- `GET /v1/projects/:project_id/memory/document?path=...` — conteúdo Markdown integral.
|
|
178
|
+
- `GET /v1/projects/:project_id/memory/document?path=...` — conteúdo Markdown integral; exige Bearer.
|
|
164
179
|
- `GET /v1/projects/:project_id/memory/search?q=...` — busca ranqueada por chunks, com trecho do
|
|
165
|
-
match e proveniência; usa fallback lexical quando FTS5 não está disponível.
|
|
180
|
+
match e proveniência; usa fallback lexical quando FTS5 não está disponível e exige Bearer.
|
|
166
181
|
- `GET /v1/projects/:project_id/sync` — modo, contagem, conflitos e último evento.
|
|
167
182
|
- `PUT /v1/projects/:project_id/sync` — compatibilidade de configuração; a autoridade continua SQL.
|
|
168
|
-
- `GET /v1/projects/:project_id/memory/export` — exportação read-only
|
|
183
|
+
- `GET /v1/projects/:project_id/memory/export` — exportação read-only sanitizada por padrão; exige Bearer.
|
|
169
184
|
- `POST /v1/projects/:project_id/memory/events` — ingestão idempotente em lote.
|
|
170
185
|
- `GET /v1/projects/:project_id/usage/summary` — totais filtráveis por período, change, sessão,
|
|
171
186
|
agente, provedor, modelo e papel.
|
|
172
187
|
- `GET /v1/projects/:project_id/usage/breakdown` — hierarquia de agentes, subagentes e modelos.
|
|
173
|
-
- `GET /v1/projects/:project_id/usage/calls` — chamadas individuais com prompt e resposta.
|
|
174
|
-
- `GET /v1/projects/:project_id/transcripts/:transcript_id` — transcript comprimido, validado por hash.
|
|
188
|
+
- `GET /v1/projects/:project_id/usage/calls` — chamadas individuais com prompt e resposta; exige Bearer.
|
|
189
|
+
- `GET /v1/projects/:project_id/transcripts/:transcript_id` — transcript comprimido, validado por hash; exige Bearer.
|
|
190
|
+
- `GET /v1/projects/:project_id/security` — policy, contagens de tokens e audit sanitizado; exige admin.
|
|
191
|
+
- `PUT /v1/projects/:project_id/security/policy` — atualiza a policy efetiva sem restart; exige admin.
|
|
192
|
+
- `POST /v1/projects/:project_id/security/purge` — dry-run/purge transacional com receipt; exige admin.
|
|
175
193
|
|
|
176
194
|
As rotas `/v1` rejeitam corpo transportado ou expandido acima do limite e validam projeto, caminho,
|
|
177
195
|
revisão, hash, idempotência e isolamento antes de gravar o conteúdo no SQLite. Para preservar uma
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { pathToFileURL } from 'node:url';
|
|
3
3
|
import { debugLog, readHookInput, resolveVault } from './obsidian-common.mjs';
|
|
4
|
-
import { publishObserverSnapshot } from '../src/observer-publish.mjs';
|
|
4
|
+
import { publishObserverSnapshot, resolveObserverPublisherSecurity } from '../src/observer-publish.mjs';
|
|
5
5
|
|
|
6
6
|
async function main() {
|
|
7
7
|
const input = readHookInput();
|
|
8
8
|
const resolved = resolveVault(input);
|
|
9
|
+
const publisherSecurity = resolveObserverPublisherSecurity();
|
|
9
10
|
const result = await publishObserverSnapshot({
|
|
10
11
|
vaultBase: resolved.base,
|
|
11
12
|
projectRoot: resolved.projectRoot,
|
|
12
13
|
input,
|
|
14
|
+
...publisherSecurity,
|
|
13
15
|
});
|
|
14
16
|
if (!result.ok && result.error) debugLog('Observer publish fail-open:', result.error);
|
|
15
17
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wendkeep",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.88.0",
|
|
4
4
|
"description": "Vault-first persistent memory for AI coding agents, with an optional profile-aware governance runtime: OFF, FLOW, GUIDE, GOVERN, or ASSURE. Local-first and agent-agnostic (Claude Code, Codex, Cursor…).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"workspaces": [
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"exports": {
|
|
10
10
|
"./harness": "./packages/harness/src/index.mjs",
|
|
11
11
|
"./vault": "./packages/vault/src/index.mjs",
|
|
12
|
+
"./commit": "./packages/commit/src/index.mjs",
|
|
12
13
|
"./hooks/*": "./hooks/*",
|
|
13
14
|
"./src/*": "./src/*",
|
|
14
15
|
"./bin/*": "./bin/*",
|
|
@@ -28,8 +29,10 @@
|
|
|
28
29
|
"bin",
|
|
29
30
|
"src",
|
|
30
31
|
"hooks",
|
|
32
|
+
".githooks",
|
|
31
33
|
"packages",
|
|
32
34
|
"schema",
|
|
35
|
+
"scripts/validate-commit-range.mjs",
|
|
33
36
|
"web/observer",
|
|
34
37
|
"docs/pt-BR/commands/*.md",
|
|
35
38
|
"docs/en/commands/*.md",
|
|
@@ -42,7 +45,8 @@
|
|
|
42
45
|
},
|
|
43
46
|
"scripts": {
|
|
44
47
|
"precheck": "node --check src/capabilities.mjs && node --check src/host-capabilities.mjs && node --check src/task-contracts.mjs && node --check src/task-leases.mjs && node --check src/task.mjs && node --check src/change.mjs && node --check src/archive-operation-lock.mjs && node --check src/worktree.mjs && node --check src/worktree-cleanup.mjs && node --check src/provenance-gate.mjs && node --check src/provenance-sources.mjs && node --check src/receipt-ledger.mjs && node --check src/evidence-envelope.mjs && node --check src/context.mjs && node --check src/active-context-health.mjs && node --check src/active-context-runtime.mjs && node --check hooks/active-context-store.mjs && node --check hooks/change-core.mjs && node --check hooks/brain-inject.mjs && node --check hooks/change-context.mjs && node --check hooks/session-stop.mjs && node --check packages/vault/src/worktree-metadata.mjs && node --check packages/vault/src/evidence-envelope.mjs && node --check packages/vault/src/memory-handoff.mjs && node --check packages/integrations/src/capabilities.mjs && node --check packages/pi/src/index.mjs && node --check src/sync-protocol.mjs && node --check src/sync-outbox.mjs && node --check src/sync-adapters.mjs && node --check src/sync-protocol-cli.mjs && node --check packages/mcp/src/sync.mjs && node --check src/portable.mjs && node --check src/tdd.mjs && node --check src/tdd-attestation.mjs && node --check src/tdd-attestation-store.mjs",
|
|
45
|
-
"check": "node --check scripts/release.mjs && node --check scripts/release-plan.mjs && node --check scripts/release-provenance.mjs && node --check scripts/run-scope.mjs && node --check src/release-provenance.mjs && node --check bin/wendkeep.mjs && node --check packages/cli/src/index.mjs && node --check src/mcp.mjs && node --check src/init.mjs && node --check src/doctor.mjs && node --check src/active-context-health.mjs && node --check src/project-vault.mjs && node --check src/observer-auth.mjs && node --check src/observer-privacy.mjs && node --check src/observer-snapshot.mjs && node --check src/observer-store.mjs && node --check src/observer-memory.mjs && node --check src/observer-memory-publish.mjs && node --check src/observer-sql-store.mjs && node --check src/observer-sql-migrate.mjs && node --check src/observer-sql-publish.mjs && node --check src/observer-transcript-store.mjs && node --check src/observer-server.mjs && node --check src/observer.mjs && node --check src/observer-publish.mjs && node --check src/operating-profile.mjs && node --check src/profile.mjs && node --check src/flow.mjs && node --check src/work-kind.mjs && node --check src/delivery.mjs && node --check web/observer/app.mjs && node --check hooks/observer-publish.mjs && node --check hooks/evidence-context.mjs && node --check hooks/active-context-handoff-evidence.mjs && node --check hooks/evidence-recall.mjs && node --check hooks/memory-scope.mjs && node --check hooks/operating-profile-runtime.mjs && node --check hooks/operating-profile-task-store.mjs && node --check hooks/flow-core.mjs && node --check hooks/flow-protected-policy.mjs && node --check hooks/git-snapshot.mjs && node --check hooks/vault-path-safety.mjs && node --check hooks/vault-runtime-store.mjs && node --check packages/harness/src/index.mjs && node --check packages/harness/src/flow-store.mjs && node --check packages/harness/src/operating-profile.mjs && node --check packages/harness/src/sensors-core.mjs && node --check packages/integrations/src/host-hooks.mjs && node --check packages/integrations/src/hook-envelope.mjs && node --check packages/integrations/src/prompt-content.mjs && node --check packages/integrations/src/transcript-usage.mjs && node --check packages/integrations/src/transcripts.mjs && node --check packages/integrations/src/session-identity.mjs && node --check packages/integrations/src/index.mjs && node --check packages/mcp/src/audit.mjs && node --check packages/mcp/src/cli.mjs && node --check packages/mcp/src/config.mjs && node --check packages/mcp/src/effects.mjs && node --check packages/mcp/src/executor.mjs && node --check packages/mcp/src/server.mjs && node --check packages/mcp/src/stdio.mjs && node --check packages/mcp/src/index.mjs && node --check packages/vault/src/index.mjs && node --check packages/vault/src/project-vault.mjs && node --check packages/vault/src/vault-path-safety.mjs && node --check packages/vault/src/locale.mjs && node --check packages/vault/src/memory-schema.mjs && node --check packages/vault/src/memory-mode.mjs && node --check packages/vault/src/memory-scope.mjs && node --check packages/vault/src/memory-candidate-policy.mjs && node --check packages/vault/src/evidence-recall.mjs && node --check packages/vault/src/memory-handoff.mjs && node --check packages/vault/src/memory-store.mjs && node --check packages/vault/src/validate-core.mjs && node --check packages/vault/src/validate-memory.mjs",
|
|
48
|
+
"check": "node --check scripts/validate-commit-range.mjs && node --check packages/commit/src/index.mjs && node --check packages/commit/src/cli.mjs && node --check packages/commit/src/git-runtime.mjs && node --check src/git-commit-hooks.mjs && node --check scripts/release.mjs && node --check scripts/release-plan.mjs && node --check scripts/release-provenance.mjs && node --check scripts/run-scope.mjs && node --check src/release-provenance.mjs && node --check bin/wendkeep.mjs && node --check packages/cli/src/index.mjs && node --check src/mcp.mjs && node --check src/init.mjs && node --check src/doctor.mjs && node --check src/active-context-health.mjs && node --check src/project-vault.mjs && node --check src/observer-auth.mjs && node --check src/observer-privacy.mjs && node --check src/observer-snapshot.mjs && node --check src/observer-store.mjs && node --check src/observer-memory.mjs && node --check src/observer-memory-publish.mjs && node --check src/observer-sql-store.mjs && node --check src/observer-sql-migrate.mjs && node --check src/observer-sql-publish.mjs && node --check src/observer-transcript-store.mjs && node --check src/observer-server.mjs && node --check src/observer.mjs && node --check src/observer-publish.mjs && node --check src/operating-profile.mjs && node --check src/profile.mjs && node --check src/flow.mjs && node --check src/work-kind.mjs && node --check src/delivery.mjs && node --check web/observer/app.mjs && node --check hooks/observer-publish.mjs && node --check hooks/evidence-context.mjs && node --check hooks/active-context-handoff-evidence.mjs && node --check hooks/evidence-recall.mjs && node --check hooks/memory-scope.mjs && node --check hooks/operating-profile-runtime.mjs && node --check hooks/operating-profile-task-store.mjs && node --check hooks/flow-core.mjs && node --check hooks/flow-protected-policy.mjs && node --check hooks/git-snapshot.mjs && node --check hooks/vault-path-safety.mjs && node --check hooks/vault-runtime-store.mjs && node --check packages/harness/src/index.mjs && node --check packages/harness/src/flow-store.mjs && node --check packages/harness/src/operating-profile.mjs && node --check packages/harness/src/sensors-core.mjs && node --check packages/integrations/src/host-hooks.mjs && node --check packages/integrations/src/hook-envelope.mjs && node --check packages/integrations/src/prompt-content.mjs && node --check packages/integrations/src/transcript-usage.mjs && node --check packages/integrations/src/transcripts.mjs && node --check packages/integrations/src/session-identity.mjs && node --check packages/integrations/src/index.mjs && node --check packages/mcp/src/audit.mjs && node --check packages/mcp/src/cli.mjs && node --check packages/mcp/src/config.mjs && node --check packages/mcp/src/effects.mjs && node --check packages/mcp/src/executor.mjs && node --check packages/mcp/src/server.mjs && node --check packages/mcp/src/stdio.mjs && node --check packages/mcp/src/index.mjs && node --check packages/vault/src/index.mjs && node --check packages/vault/src/project-vault.mjs && node --check packages/vault/src/vault-path-safety.mjs && node --check packages/vault/src/locale.mjs && node --check packages/vault/src/memory-schema.mjs && node --check packages/vault/src/memory-mode.mjs && node --check packages/vault/src/memory-scope.mjs && node --check packages/vault/src/memory-candidate-policy.mjs && node --check packages/vault/src/evidence-recall.mjs && node --check packages/vault/src/memory-handoff.mjs && node --check packages/vault/src/memory-store.mjs && node --check packages/vault/src/validate-core.mjs && node --check packages/vault/src/validate-memory.mjs",
|
|
49
|
+
"postcheck": "node --check packages/observer/src/index.mjs && node --check packages/observer/src/policy.mjs && node --check packages/observer/src/redaction.mjs && node --check packages/observer/src/authz.mjs && node --check packages/observer/src/token-registry.mjs && node --check packages/observer/src/encryption.mjs && node --check packages/observer/src/retention.mjs && node --check packages/observer/src/purge.mjs && node --check packages/observer/src/audit.mjs",
|
|
46
50
|
"test": "node --test --test-concurrency=2",
|
|
47
51
|
"test:core": "node scripts/run-scope.mjs core",
|
|
48
52
|
"release": "node scripts/release.mjs",
|
|
@@ -34,6 +34,7 @@ Usage:
|
|
|
34
34
|
--no-companions Skip companion plugins/MCP entirely.
|
|
35
35
|
--no-colors Skip the Obsidian color system (.obsidian snippet + graph groups).
|
|
36
36
|
--vscode-worktree-tasks Create local, Git-excluded VS Code tasks for managed worktrees.
|
|
37
|
+
--git-commit-hooks Opt in to .githooks + local core.hooksPath for evidence commits.
|
|
37
38
|
--dotcontext-mcp <v> dotcontext MCP placement: auto (default; skip project entry
|
|
38
39
|
if already global), project, or none.
|
|
39
40
|
--dotcontext-hooks <v> dotcontext hooks: full (default), light (no PostToolUse), none.
|
|
@@ -53,6 +54,7 @@ Usage:
|
|
|
53
54
|
Uses explicit CAS/conflicts and an offline outbox; --remote path or --url HTTPS.
|
|
54
55
|
|
|
55
56
|
wendkeep doctor [--vault P] Health check. --scope core|runtime · --strict for CI/release.
|
|
57
|
+
wendkeep commit <sub> Evidence-based Git commits: context | render | prepare | validate.
|
|
56
58
|
wendkeep portable <sub> Shared authored state: status | export | import | diff.
|
|
57
59
|
Default file: .wendkeep/portable/state.json; private runtime stays local.
|
|
58
60
|
wendkeep mcp <serve|config> Native semantic MCP over stdio, or client config generation.
|
|
@@ -232,6 +234,9 @@ async function main(argv) {
|
|
|
232
234
|
} else if (cmd === 'capabilities') {
|
|
233
235
|
const { CAPABILITIES_HELP } = await import('../../../src/capabilities.mjs');
|
|
234
236
|
process.stdout.write(CAPABILITIES_HELP);
|
|
237
|
+
} else if (cmd === 'commit') {
|
|
238
|
+
const { COMMIT_HELP } = await import('../../commit/src/cli.mjs');
|
|
239
|
+
process.stdout.write(COMMIT_HELP);
|
|
235
240
|
} else {
|
|
236
241
|
process.stdout.write(HELP);
|
|
237
242
|
}
|
|
@@ -245,7 +250,7 @@ async function main(argv) {
|
|
|
245
250
|
// `sync` starts with `init` and resolves the freshly bound Vault itself. Pre-resolving
|
|
246
251
|
// here would prevent that repair step from reporting a corrupt binding as its own
|
|
247
252
|
// first-stage failure (and could never make it as far as the guarded init).
|
|
248
|
-
&& !['init', 'sync', 'worktree', 'hook', 'observer', 'mcp', 'capabilities', '--version', '-v', '--help', '-h', 'help'].includes(cmd)) {
|
|
253
|
+
&& !['init', 'sync', 'worktree', 'hook', 'observer', 'mcp', 'capabilities', 'commit', '--version', '-v', '--help', '-h', 'help'].includes(cmd)) {
|
|
249
254
|
await preferProjectVault(rest);
|
|
250
255
|
}
|
|
251
256
|
switch (cmd) {
|
|
@@ -262,6 +267,11 @@ async function main(argv) {
|
|
|
262
267
|
process.exit(runDoctor(rest));
|
|
263
268
|
break;
|
|
264
269
|
}
|
|
270
|
+
case 'commit': {
|
|
271
|
+
const { runCommit } = await import('../../commit/src/cli.mjs');
|
|
272
|
+
process.exit(runCommit(rest));
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
265
275
|
case 'portable': {
|
|
266
276
|
const { runPortable } = await import('../../../src/portable.mjs');
|
|
267
277
|
process.exit(runPortable(rest));
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
|
|
3
|
+
import { renderCommitMessage } from './commit-message.mjs';
|
|
4
|
+
import {
|
|
5
|
+
buildCommitInput,
|
|
6
|
+
clearCommitContext,
|
|
7
|
+
prepareCommitMessageFile,
|
|
8
|
+
validateCommitMessageFile,
|
|
9
|
+
writeCommitContext,
|
|
10
|
+
} from './git-runtime.mjs';
|
|
11
|
+
|
|
12
|
+
export const COMMIT_HELP = `wendkeep commit — evidence-based Git commit policy
|
|
13
|
+
|
|
14
|
+
Usage:
|
|
15
|
+
wendkeep commit context --input <json|-> [--json]
|
|
16
|
+
wendkeep commit context --clear [--json]
|
|
17
|
+
wendkeep commit render --input <json|->
|
|
18
|
+
wendkeep commit prepare --message-file <path> [--source <source>]
|
|
19
|
+
wendkeep commit validate --message-file <path> [--consume-context] [--json]
|
|
20
|
+
|
|
21
|
+
The context is stored under the repository Git directory, never in the Vault or working tree.
|
|
22
|
+
`;
|
|
23
|
+
|
|
24
|
+
function option(argv, name) {
|
|
25
|
+
const index = argv.indexOf(name);
|
|
26
|
+
if (index >= 0) return argv[index + 1] || '';
|
|
27
|
+
return argv.find((item) => item.startsWith(`${name}=`))?.slice(name.length + 1) || '';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function readInput(path) {
|
|
31
|
+
if (!path) throw Object.assign(new Error('--input is required'), { code: 'WENDKEEP_COMMIT_ARGUMENT' });
|
|
32
|
+
const source = path === '-' ? readFileSync(0, 'utf8') : readFileSync(path, 'utf8');
|
|
33
|
+
return JSON.parse(source);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function outputJson(value) {
|
|
37
|
+
process.stdout.write(`${JSON.stringify(value)}\n`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function runCommit(argv, { cwd = process.cwd() } = {}) {
|
|
41
|
+
const [subcommand, ...rest] = argv;
|
|
42
|
+
const json = rest.includes('--json');
|
|
43
|
+
try {
|
|
44
|
+
if (!subcommand || subcommand === 'help' || rest.includes('--help') || rest.includes('-h')) {
|
|
45
|
+
process.stdout.write(COMMIT_HELP);
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
if (subcommand === 'context') {
|
|
49
|
+
const result = rest.includes('--clear')
|
|
50
|
+
? clearCommitContext({ cwd })
|
|
51
|
+
: writeCommitContext(readInput(option(rest, '--input')), { cwd });
|
|
52
|
+
if (json) outputJson(rest.includes('--clear') ? result : { path: result.path, schema_version: 1 });
|
|
53
|
+
else process.stdout.write(`${rest.includes('--clear') ? 'cleared' : 'written'}: ${result.path}\n`);
|
|
54
|
+
return 0;
|
|
55
|
+
}
|
|
56
|
+
if (subcommand === 'render') {
|
|
57
|
+
const input = buildCommitInput(readInput(option(rest, '--input')), { cwd });
|
|
58
|
+
process.stdout.write(renderCommitMessage(input));
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
if (subcommand === 'prepare') {
|
|
62
|
+
const result = prepareCommitMessageFile({
|
|
63
|
+
messageFile: option(rest, '--message-file'),
|
|
64
|
+
source: option(rest, '--source'),
|
|
65
|
+
cwd,
|
|
66
|
+
});
|
|
67
|
+
if (json) outputJson(result);
|
|
68
|
+
return 0;
|
|
69
|
+
}
|
|
70
|
+
if (subcommand === 'validate') {
|
|
71
|
+
const result = validateCommitMessageFile({
|
|
72
|
+
messageFile: option(rest, '--message-file'),
|
|
73
|
+
consumeContext: rest.includes('--consume-context'),
|
|
74
|
+
cwd,
|
|
75
|
+
});
|
|
76
|
+
if (json) outputJson(result);
|
|
77
|
+
if (!result.ok) {
|
|
78
|
+
process.stderr.write(`WENDKEEP_COMMIT_MESSAGE_INVALID\n${result.errors.map((error) => `- ${error}`).join('\n')}\n`);
|
|
79
|
+
return 1;
|
|
80
|
+
}
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
process.stderr.write(`wendkeep commit: unknown subcommand "${subcommand}"\n`);
|
|
84
|
+
return 2;
|
|
85
|
+
} catch (error) {
|
|
86
|
+
process.stderr.write(`${error.code || 'WENDKEEP_COMMIT_ERROR'}: ${error.message}\n`);
|
|
87
|
+
return 2;
|
|
88
|
+
}
|
|
89
|
+
}
|