wendkeep 0.58.3 → 0.60.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.
Files changed (77) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/README.en.md +45 -3
  3. package/README.md +45 -3
  4. package/bin/wendkeep.mjs +54 -6
  5. package/docs/en/commands/changes-and-verification.md +9 -3
  6. package/docs/en/commands/getting-started.md +7 -3
  7. package/docs/en/commands/memory.md +20 -2
  8. package/docs/en/commands/operating-profiles.md +173 -0
  9. package/docs/en/commands/sessions-and-import.md +8 -4
  10. package/docs/en/commands/verify.md +12 -6
  11. package/docs/pt-BR/commands/changes-and-verification.md +9 -4
  12. package/docs/pt-BR/commands/getting-started.md +7 -3
  13. package/docs/pt-BR/commands/memory.md +18 -2
  14. package/docs/pt-BR/commands/operating-profiles.md +171 -0
  15. package/docs/pt-BR/commands/sessions-and-import.md +7 -3
  16. package/docs/pt-BR/commands/verify.md +11 -5
  17. package/hooks/brain-core.mjs +159 -159
  18. package/hooks/brain-inject.mjs +83 -26
  19. package/hooks/brain-recall.mjs +32 -32
  20. package/hooks/brain-reindex.mjs +13 -13
  21. package/hooks/change-context.mjs +24 -10
  22. package/hooks/change-core.mjs +174 -37
  23. package/hooks/change-guard.mjs +115 -16
  24. package/hooks/change-nag.mjs +20 -5
  25. package/hooks/change-warn.mjs +27 -9
  26. package/hooks/decision-capture.mjs +1 -1
  27. package/hooks/derived-sections.mjs +1 -1
  28. package/hooks/flow-core.mjs +891 -0
  29. package/hooks/flow-protected-policy.mjs +218 -0
  30. package/hooks/frontmatter-repair.mjs +3 -1
  31. package/hooks/git-snapshot.mjs +722 -0
  32. package/hooks/import-sessions.mjs +10 -5
  33. package/hooks/memory-mode.mjs +63 -13
  34. package/hooks/memory-store.mjs +309 -69
  35. package/hooks/obsidian-common.mjs +39 -55
  36. package/hooks/operating-profile-runtime.mjs +157 -0
  37. package/hooks/plan-capture.mjs +14 -3
  38. package/hooks/sensors-core.mjs +15 -3
  39. package/hooks/session-backfill.mjs +7 -2
  40. package/hooks/session-ensure.mjs +6 -4
  41. package/hooks/session-iteration.mjs +65 -0
  42. package/hooks/session-memory-lifecycle.mjs +10 -5
  43. package/hooks/session-note-io.mjs +130 -15
  44. package/hooks/session-observability.mjs +4 -2
  45. package/hooks/session-stop.mjs +65 -19
  46. package/hooks/spec-core.mjs +91 -12
  47. package/hooks/subagent-stop.mjs +4 -1
  48. package/hooks/subagent-usage.mjs +2 -2
  49. package/hooks/task-log.mjs +3 -1
  50. package/hooks/token-usage.mjs +1 -1
  51. package/hooks/vault-health.mjs +183 -37
  52. package/hooks/vault-path-safety.mjs +2 -0
  53. package/hooks/vault-runtime-store.mjs +558 -0
  54. package/package.json +10 -3
  55. package/packages/cli/package.json +5 -0
  56. package/packages/harness/package.json +5 -0
  57. package/packages/integrations/package.json +5 -0
  58. package/packages/mcp/package.json +5 -0
  59. package/packages/pi/package.json +5 -0
  60. package/packages/vault/package.json +6 -0
  61. package/packages/vault/src/index.mjs +2 -0
  62. package/packages/vault/src/project-vault.mjs +327 -0
  63. package/packages/vault/src/vault-path-safety.mjs +558 -0
  64. package/src/change.mjs +2 -1
  65. package/src/flow.mjs +232 -0
  66. package/src/init.mjs +26 -3
  67. package/src/memory.mjs +785 -35
  68. package/src/operating-profile.mjs +133 -0
  69. package/src/profile.mjs +224 -0
  70. package/src/project-vault.mjs +2 -221
  71. package/src/rebuild-costs.mjs +11 -4
  72. package/src/skills-seed.mjs +38 -16
  73. package/src/sync-defs.mjs +16 -7
  74. package/src/sync.mjs +9 -1
  75. package/src/taxonomy.mjs +8 -0
  76. package/src/validate-memory.mjs +21 -8
  77. package/src/verify.mjs +12 -2
@@ -11,18 +11,29 @@ function skill(name, description, body, files = []) {
11
11
  return { name, description, body: `---\nname: ${name}\ndescription: ${description}\n---\n${body}`, files };
12
12
  }
13
13
 
14
- const WORKFLOW = `# Loop a2o ciclo de trabalho do wendkeep
14
+ const WORKFLOW = `# Perfis de Operação roteador de trabalho do wendkeep
15
15
 
16
- Use ao começar qualquer mudança não-trivial. O loop mantém memória (vault) e prova
17
- (sensores) juntas, tudo linkado no grafo do Obsidian.
16
+ Use ao começar implementação, correção ou refatoração. **Keep Core permanece sempre ativo**
17
+ em todos os perfis: Vault, sessão, identidade, memória, lessons e persistência. Na ausência de
18
+ configuração válida, **GOVERN é o padrão** compatível.
18
19
 
19
20
  <HARD-GATE>
20
- NÃO edite arquivos de código antes do passo 2 (Propose / \`wendkeep change new\`).
21
- Toda tarefa não-trivial passa pelo loop planejar no chat e sair editando deixa o
22
- vault cego. Exceção única: mudança trivial (typo, 1 linha).
21
+ Antes de editar, leia o **perfil efetivo** injetado pelo WendKeep e siga somente sua rota:
22
+ - \`OFF\`: não imponha processo Wend; a governança pertence ao **harness nativo da LLM**.
23
+ - \`FLOW\`: inicie o microcontrato com \`wendkeep flow start\` antes de editar os paths permitidos.
24
+ - \`GUIDE\`, \`GOVERN\` ou \`ASSURE\`: não edite código antes de Propose / \`wendkeep change new\`.
25
+ Este gate nunca transforma \`OFF\` ou \`FLOW\` silenciosamente em \`GOVERN\`.
23
26
  </HARD-GATE>
24
27
 
25
- ## Os passos
28
+ ## Rotas por perfil
29
+
30
+ - **OFF — LLM nativa:** Wend Runtime desligado; esta skill devolve a execução ao harness nativo.
31
+ - **FLOW — E → V:** \`flow start\` → implementar com wk-tdd → \`flow finish\`; sem change/ADR/verdict.
32
+ - **GUIDE — P → E → V:** change compacta, sem revisão formal obrigatória.
33
+ - **GOVERN — P → R → E → V:** loop a2 atual, com design/revisão; é o padrão conservador.
34
+ - **ASSURE — P → R → E → V → C:** GOVERN acrescido de confirmação e handoff explícitos.
35
+
36
+ ## Passos para GUIDE, GOVERN e ASSURE
26
37
 
27
38
  1. **Explore** — entenda o problema antes de propor. Leia o código/contexto relevante.
28
39
  2. **Propose** — \`wendkeep change new <slug>\`. Isso cria \`08-Mudanças/<slug>/\` com:
@@ -251,18 +262,29 @@ nunca tivesse visto a implementação. Contexto fresco, read-only.
251
262
  - \`verdict-template.json\` — o formato exato do \`verdict.json\` a gravar.
252
263
  `;
253
264
 
254
- const WORKFLOW_EN = `# The a2 loop — wendkeep's work cycle
265
+ const WORKFLOW_EN = `# Operating Profiles — wendkeep work router
255
266
 
256
- Use it when starting any non-trivial change. The loop keeps memory (vault) and proof
257
- (sensors) together, wikilinked in the Obsidian graph.
267
+ Use this when starting an implementation, fix, or refactor. **Keep Core is always active**
268
+ in every profile: Vault, session, identity, memory, lessons, and persistence. With no valid
269
+ configuration, **GOVERN is the default** for compatibility.
258
270
 
259
271
  <HARD-GATE>
260
- Do NOT edit code files before step 2 (Propose / \`wendkeep change new\`).
261
- Every non-trivial task goes through the loop planning in chat and editing right away
262
- leaves the vault blind. Single exception: a trivial change (typo, one line).
272
+ Before editing, read the injected **effective profile** and follow only its route:
273
+ - \`OFF\`: impose no Wend process; governance belongs to the **native LLM harness**.
274
+ - \`FLOW\`: start the microcontract with \`wendkeep flow start\` before editing allowed paths.
275
+ - \`GUIDE\`, \`GOVERN\`, or \`ASSURE\`: do not edit code before Propose / \`wendkeep change new\`.
276
+ This gate never silently turns \`OFF\` or \`FLOW\` into \`GOVERN\`.
263
277
  </HARD-GATE>
264
278
 
265
- ## Steps
279
+ ## Profile routes
280
+
281
+ - **OFF — native LLM:** Wend Runtime is disabled; this skill returns execution to the native harness.
282
+ - **FLOW — E → V:** \`flow start\` → implement with wk-tdd → \`flow finish\`; no change/ADR/verdict.
283
+ - **GUIDE — P → E → V:** a compact change with no mandatory formal review.
284
+ - **GOVERN — P → R → E → V:** the current a2 loop with design/review; the conservative default.
285
+ - **ASSURE — P → R → E → V → C:** GOVERN plus explicit confirmation and handoff.
286
+
287
+ ## Steps for GUIDE, GOVERN, and ASSURE
266
288
 
267
289
  1. **Explore** — understand the problem before proposing.
268
290
  2. **Propose** — \`wendkeep change new <slug>\` scaffolds \`08-Changes/<slug>/\`
@@ -597,7 +619,7 @@ size of the problem>
597
619
  // usuário ("implementa X", "corrige Y"), não com abstrações ("mudança não-trivial"). Gatilhos
598
620
  // concretos + instrução imperativa = a skill dispara sozinha (paridade Superpowers).
599
621
  const WK_SKILLS_PT = [
600
- skill('wk-workflow', 'Use SEMPRE que o usuário pedir para implementar, criar, corrigir, refatorar, adicionar ou alterar código qualquer tarefa de código não-trivial. Invoque ANTES de editar qualquer arquivo: orquestra o loop a2 (wendkeep change new → tarefas → verify → archive) e registra tudo no vault.', WORKFLOW),
622
+ skill('wk-workflow', 'Use quando o usuário pedir para implementar, criar, corrigir, refatorar, adicionar ou alterar código: leia o perfil efetivo e roteie OFF/FLOW/GUIDE/GOVERN/ASSURE ANTES de editar. Keep Core permanece ativo; GOVERN é o padrão compatível.', WORKFLOW),
601
623
  skill('wk-tdd', 'Use ao implementar qualquer comportamento — Red/Green/Refactor com testes que discriminam (derivados do spec, litmus não-raso, adequação).', TDD),
602
624
  skill('wk-debugging', 'Use quando algo falha, quebra, dá erro ou regride — depuração sistemática por hipótese antes de corrigir.', DEBUGGING),
603
625
  skill('wk-brainstorming', 'Use quando a ideia ainda é vaga ou o usuário quer discutir/planejar uma feature (inclusive em plan mode) — vira design aprovado, com closure gate e tabela out-of-scope, antes de código.', BRAINSTORMING, [{ name: 'design-template.md', content: DESIGN_TEMPLATE_PT }]),
@@ -606,7 +628,7 @@ const WK_SKILLS_PT = [
606
628
  ];
607
629
 
608
630
  const WK_SKILLS_EN = [
609
- skill('wk-workflow', 'Use WHENEVER the user asks to implement, create, fix, refactor, add or change code — any non-trivial coding task. Invoke BEFORE editing any file: it orchestrates the a2 loop (wendkeep change new tasks verify archive) and records everything in the vault.', WORKFLOW_EN),
631
+ skill('wk-workflow', 'Use when the user asks to implement, create, fix, refactor, add, or change code: read the effective profile and route OFF/FLOW/GUIDE/GOVERN/ASSURE BEFORE editing. Keep Core stays active; GOVERN is the compatible default.', WORKFLOW_EN),
610
632
  skill('wk-tdd', 'Use when implementing any behaviour — Red/Green/Refactor with tests that discriminate (spec-derived, non-shallow litmus, adequacy).', TDD_EN),
611
633
  skill('wk-debugging', 'Use when something fails, breaks, errors or regresses — systematic hypothesis-driven debugging before fixing.', DEBUGGING_EN),
612
634
  skill('wk-brainstorming', 'Use when the idea is still vague or the user wants to discuss/plan a feature (plan mode included) — turns it into an approved design, with a closure gate and out-of-scope table, before code.', BRAINSTORMING_EN, [{ name: 'design-template.md', content: DESIGN_TEMPLATE_EN }]),
package/src/sync-defs.mjs CHANGED
@@ -58,14 +58,23 @@ function renderAgentsSection(skills, sourceHash = '') {
58
58
  const list = skills.map((s) => `- **${s.name}** — ${s.description}`).join('\n');
59
59
  return `${AG_START}
60
60
  <!-- wendkeep-version: ${WENDKEEP_VERSION}; skills-sha256: ${sourceHash} -->
61
- ## wendkeep — process skills & loop
61
+ ## wendkeep — Keep Core & operating profiles
62
62
 
63
- This project uses the [wendkeep](https://github.com/rogersialves/wendkeep) harness. Work
64
- through its change loop: \`wendkeep change new <slug>\` implement tasks test-first
65
- (tag proof \`[sensor:id]\` and requirement \`[req:ID]\`) \`wendkeep verify\`
66
- \`wendkeep verify --deep\` + an independent read-only verification pass writing
67
- \`verdict.json\` \`wendkeep change archive\` (gated). Inspect with \`wendkeep change
68
- status\` / \`spec effective --change <slug>\` / \`sensors list\`. Author specs only in
63
+ This project uses the [wendkeep](https://github.com/rogersialves/wendkeep) harness. **Keep Core is always active**
64
+ in every profile: Vault, session, identity, memory, lessons, and persistence integrations.
65
+ The effective profile is selected explicitly; missing or invalid configuration uses **GOVERN as the default**.
66
+
67
+ Route work by the effective profile:
68
+ - **OFF** Wend Runtime is disabled and governance belongs to the native LLM harness; Keep Core stays active.
69
+ - **FLOW** — Execute → Validate through \`wendkeep flow start/finish\`, without creating a change.
70
+ - **GUIDE** — Plan → Execute → Validate through a compact change.
71
+ - **GOVERN** — the default a2 loop: \`wendkeep change new <slug>\` → review → implement tasks test-first
72
+ (tag proof \`[sensor:id]\` and requirement \`[req:ID]\`) → \`wendkeep verify\` →
73
+ \`wendkeep verify --deep\` + independent read-only verdict → \`wendkeep change archive\`.
74
+ - **ASSURE** — GOVERN plus explicit confirmation and handoff.
75
+
76
+ Inspect with \`wendkeep profile status\` / \`wendkeep change status\` /
77
+ \`spec effective --change <slug>\` / \`sensors list\`. Author specs only in
69
78
  \`08-Mudanças/<slug>/specs/\`; \`07-Specs\` is generated and must not be edited directly.
70
79
 
71
80
  Process skills (full text in \`.claude/skills/\`, \`.agents/skills/\`, and the vault's \`.brain/skills/\`):
package/src/sync.mjs CHANGED
@@ -22,6 +22,9 @@ const step = (n, label) => process.stdout.write(`\n[${n}/3] ${label}\n`);
22
22
  export async function runSync(argv) {
23
23
  const projectRaw = opt(argv, '--project');
24
24
  const vaultRaw = opt(argv, '--vault');
25
+ const hasProfile = argv.includes('--profile') || argv.some((a) => a.startsWith('--profile='));
26
+ const profileRaw = opt(argv, '--profile');
27
+ const profileArgs = hasProfile ? ['--profile', profileRaw] : [];
25
28
  const projectPath = resolve(projectRaw && !projectRaw.startsWith('--') ? projectRaw : process.cwd());
26
29
  const passthrough = argv.filter((a) => a === '--yes' || a === '-y' || a === '--force');
27
30
 
@@ -29,7 +32,12 @@ export async function runSync(argv) {
29
32
  step(1, 'init');
30
33
  const { runInit } = await import('./init.mjs');
31
34
  try {
32
- await runInit(['--project', projectPath, ...(vaultRaw ? ['--vault', vaultRaw] : []), ...passthrough]);
35
+ await runInit([
36
+ '--project', projectPath,
37
+ ...(vaultRaw ? ['--vault', vaultRaw] : []),
38
+ ...profileArgs,
39
+ ...passthrough,
40
+ ]);
33
41
  } catch (error) {
34
42
  process.stderr.write(`wendkeep sync: init falhou — ${error.message}\n`);
35
43
  return 1;
package/src/taxonomy.mjs CHANGED
@@ -38,6 +38,14 @@ export const HOOK_FILES = [
38
38
  'memory-store.mjs',
39
39
  'memory-handoff.mjs',
40
40
  'session-memory-lifecycle.mjs',
41
+ 'session-note-io.mjs',
42
+ 'operating-profile-runtime.mjs',
43
+ 'git-snapshot.mjs',
44
+ 'flow-protected-policy.mjs',
45
+ 'session-iteration.mjs',
46
+ 'vault-path-safety.mjs',
47
+ 'vault-runtime-store.mjs',
48
+ 'flow-core.mjs',
41
49
  'change-core.mjs',
42
50
  'spec-core.mjs',
43
51
  'sensors-core.mjs',
@@ -1,16 +1,29 @@
1
- import { existsSync, readFileSync } from 'node:fs';
1
+ import { readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { validateMemoryEvent, validateSharedMemory } from '../hooks/memory-schema.mjs';
4
+ import { assertVaultPathSafe } from '../hooks/vault-path-safety.mjs';
4
5
  import { validateCore } from './validate-core.mjs';
5
6
 
6
7
  function failedComponent(errors, extra = {}) {
7
8
  return { ok: false, errors: Array.isArray(errors) ? errors : [errors], warnings: [], ...extra };
8
9
  }
9
10
 
10
- function readRequired(path, label) {
11
- if (!existsSync(path)) return { ok: false, error: `${label} ausente: ${path}` };
11
+ function readRequired(vaultBase, path, label) {
12
+ let checked;
12
13
  try {
13
- return { ok: true, content: readFileSync(path, 'utf8') };
14
+ checked = assertVaultPathSafe(vaultBase, path, {
15
+ expectedType: 'file', label: `artefato ${label}`,
16
+ });
17
+ } catch (error) {
18
+ return { ok: false, error: `${label} inseguro: ${error?.message || error}` };
19
+ }
20
+ if (!checked.exists) return { ok: false, error: `${label} ausente: ${path}` };
21
+ try {
22
+ // Deliberately adjacent to the open performed by readFileSync.
23
+ checked = assertVaultPathSafe(vaultBase, checked.target, {
24
+ allowMissing: false, expectedType: 'file', label: `artefato ${label}`,
25
+ });
26
+ return { ok: true, content: readFileSync(checked.target, 'utf8') };
14
27
  } catch (error) {
15
28
  return { ok: false, error: `${label} ilegível: ${error?.message || error}` };
16
29
  }
@@ -18,7 +31,7 @@ function readRequired(path, label) {
18
31
 
19
32
  export function readProjectForValidation(vaultBase) {
20
33
  const path = join(vaultBase, '.brain', 'PROJECT.json');
21
- const read = readRequired(path, 'PROJECT.json');
34
+ const read = readRequired(vaultBase, path, 'PROJECT.json');
22
35
  if (!read.ok) return failedComponent(read.error, { projectId: '', path });
23
36
  try {
24
37
  const marker = JSON.parse(read.content);
@@ -34,7 +47,7 @@ export function readProjectForValidation(vaultBase) {
34
47
  /** Read and validate the append-only JSONL authority without repairing or mutating it. */
35
48
  export function readLedgerForValidation(vaultBase, { projectId } = {}) {
36
49
  const path = join(vaultBase, '.brain', 'MEMORY_EVENTS.jsonl');
37
- const read = readRequired(path, 'MEMORY_EVENTS.jsonl');
50
+ const read = readRequired(vaultBase, path, 'MEMORY_EVENTS.jsonl');
38
51
  if (!read.ok) return failedComponent(read.error, { events: [], eventIds: new Set(), path });
39
52
 
40
53
  const errors = [];
@@ -79,14 +92,14 @@ export function readLedgerForValidation(vaultBase, { projectId } = {}) {
79
92
 
80
93
  function validateCoreArtifact(vaultBase) {
81
94
  const path = join(vaultBase, '.brain', 'CORE.md');
82
- const read = readRequired(path, 'CORE.md');
95
+ const read = readRequired(vaultBase, path, 'CORE.md');
83
96
  if (!read.ok) return failedComponent(read.error, { lineCount: 0, path });
84
97
  return { ...validateCore(read.content), path, content: read.content };
85
98
  }
86
99
 
87
100
  function validateSharedArtifact(vaultBase, eventIds) {
88
101
  const path = join(vaultBase, '.brain', 'SHARED_MEMORY.md');
89
- const read = readRequired(path, 'SHARED_MEMORY.md');
102
+ const read = readRequired(vaultBase, path, 'SHARED_MEMORY.md');
90
103
  if (!read.ok) return failedComponent(read.error, { path });
91
104
  return { ...validateSharedMemory(read.content, { eventIds }), path, content: read.content };
92
105
  }
package/src/verify.mjs CHANGED
@@ -4,7 +4,14 @@
4
4
  import { readFileSync, unlinkSync, writeFileSync } from 'node:fs';
5
5
  import { isAbsolute, join, resolve } from 'node:path';
6
6
  import { parseTasks, activeChange, appendFixTasks, healSpecBacklinks } from '../hooks/change-core.mjs';
7
- import { loadSensorsDetailed, findProjectRoot, requiredSensors, runSensors, evaluateGate } from '../hooks/sensors-core.mjs';
7
+ import {
8
+ loadSensorsDetailed,
9
+ findProjectRoot,
10
+ requiredSensors,
11
+ runSensors,
12
+ evaluateGate,
13
+ sensorProcessEnv,
14
+ } from '../hooks/sensors-core.mjs';
8
15
  import {
9
16
  buildEffectiveRequirementPackage,
10
17
  captureSpecBaseline,
@@ -54,7 +61,10 @@ export function runVerify(argv) {
54
61
  process.stderr.write(`wendkeep verify: wendkeep.sensors.json não encontrado em ${loaded.path} — rode da raiz do projeto ou use --project <raiz>\n`);
55
62
  }
56
63
  const sensors = loaded.sensors;
57
- const evidence = runSensors(sensors, ids, { cwd: projectRoot });
64
+ const evidence = runSensors(sensors, ids, {
65
+ cwd: projectRoot,
66
+ env: sensorProcessEnv(vaultBase),
67
+ });
58
68
  writeFileSync(join(changeDir, 'evidencia.json'), `${JSON.stringify(evidence, null, 2)}\n`, 'utf8');
59
69
  // Freshness seal: bind this evidence to the tarefas.md it was produced against, so the archive
60
70
  // gate can reject evidence gone stale (a sensor task added after this verify run).