wendkeep 0.26.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 CHANGED
@@ -4,6 +4,22 @@ 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
+
7
23
  ## [0.26.0] — 2026-07-08
8
24
 
9
25
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wendkeep",
3
- "version": "0.26.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
@@ -249,6 +249,7 @@ const MESSAGES = {
249
249
  step3: ' 3. Abra o Claude Code neste projeto e envie um prompt de teste.',
250
250
  step4: ' 4. Confirme que uma nota aparece em 02-Sessões/<ano>/<mês>/DIA <dd>/ no vault.',
251
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.`,
252
253
  },
253
254
  en: {
254
255
  header: '\nwendkeep init',
@@ -273,6 +274,7 @@ const MESSAGES = {
273
274
  step3: ' 3. Open Claude Code in this project and send a test prompt.',
274
275
  step4: ' 4. Confirm a note appears under 02-Sessões/<year>/<month>/DIA <dd>/ in the vault.',
275
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.`,
276
278
  },
277
279
  };
278
280
 
@@ -287,13 +289,39 @@ export function parseLocaleAnswer(ans) {
287
289
  return 'pt-BR';
288
290
  }
289
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
+
290
310
  export async function runInit(argv) {
291
311
  const args = parseArgs(argv);
292
312
  const projectPath = resolve(args.project || process.cwd());
293
313
  const log = (s) => process.stdout.write(`${s}\n`);
294
314
 
295
- // Language first (i18n): an interactive TTY without --locale is asked the vault language;
296
- // folders, prompts and scaffold all follow the answer.
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.
297
325
  if (!args.locale && process.stdin.isTTY && !args.yes) {
298
326
  const rl = createInterface({ input: process.stdin, output: process.stdout });
299
327
  const ans = await rl.question('Idioma do vault / Vault language:\n [1] Português (pt-BR) [2] English (en)\n> ');
@@ -304,8 +332,10 @@ export async function runInit(argv) {
304
332
  const P = promptStrings(resolvedLocale);
305
333
  const M = initMessages(resolvedLocale);
306
334
 
307
- let vaultPath = args.vault;
308
- if (!vaultPath) {
335
+ let vaultPath = args.vault || registeredVault;
336
+ if (registeredVault) {
337
+ log(M.vaultRegistered(registeredVault, resolvedLocale));
338
+ } else if (!vaultPath) {
309
339
  const fallback = join(projectPath, deriveVaultDirName(projectPath));
310
340
  if (process.stdin.isTTY && !args.yes) {
311
341
  const rl = createInterface({ input: process.stdin, output: process.stdout });