wendkeep 0.47.0 → 0.49.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wendkeep",
3
- "version": "0.47.0",
3
+ "version": "0.49.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/doctor.mjs CHANGED
@@ -4,7 +4,7 @@ import { spawnSync } from 'node:child_process';
4
4
  import { existsSync } from 'node:fs';
5
5
  import { dirname, join, resolve } from 'node:path';
6
6
  import { fileURLToPath } from 'node:url';
7
- import { checkHarness } from '../hooks/harness-doctor.mjs';
7
+ import { checkHarness, checkVaultLinks, checkSessionActivity } from '../hooks/harness-doctor.mjs';
8
8
  import { checkSyncDefs } from './sync-defs.mjs';
9
9
  import { resolveProjectVault } from './project-vault.mjs';
10
10
 
@@ -60,5 +60,25 @@ export function runDoctor(argv) {
60
60
  for (const e of errors) process.stdout.write(` ✗ ${e}\n`);
61
61
  for (const w of warnings) process.stdout.write(` ! ${w}\n`);
62
62
 
63
+ // 3. Link/graph health — órfãos que o grafo do Obsidian mostraria, com o comando de reparo.
64
+ const links = checkVaultLinks(vaultBase);
65
+ const graphLabel = links.graphColors === true ? 'com cores' : links.graphColors === false ? 'sem cores' : 'sem graph.json';
66
+ process.stdout.write(`\n[links] ${links.derivedOrphans} derivada(s) órfã(s) · ${links.artifactOrphans} artefato(s) órfão(s) · grafo: ${graphLabel}\n`);
67
+ if (links.derivedOrphans) process.stdout.write(' → wendkeep note relink --apply\n');
68
+ if (links.artifactOrphans) process.stdout.write(' → wendkeep change backlink --apply\n');
69
+ if (links.graphColors === false) process.stdout.write(' → wendkeep theme sync (feche o Obsidian antes)\n');
70
+ if (!links.derivedOrphans && !links.artifactOrphans && links.graphColors !== false) process.stdout.write(' grafo conectado ✓\n');
71
+
72
+ // 4. Sessão: não mente "inativa" quando há atividade recente (workflow/subagente em background).
73
+ const act = checkSessionActivity(vaultBase);
74
+ if (act.lastSession) {
75
+ const label = act.active
76
+ ? 'ativa'
77
+ : act.backgroundSuspected
78
+ ? `inativa no control, mas escrita há ${Math.round((act.ageMs || 0) / 1000)}s — possível workflow/subagente em background`
79
+ : 'inativa';
80
+ process.stdout.write(`[sessão] última: ${act.lastSession} (${label})\n`);
81
+ }
82
+
63
83
  process.exit(healthStatus !== 0 || errors.length ? 1 : 0);
64
84
  }
package/src/note.mjs CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  toVaultRelative,
15
15
  } from '../hooks/obsidian-common.mjs';
16
16
  import { getLocale } from '../hooks/locale.mjs';
17
- import { buildManualBugNote, buildManualLearningNote } from '../hooks/linked-notes.mjs';
17
+ import { buildManualBugNote, buildManualLearningNote, relinkDerivedNotes } from '../hooks/linked-notes.mjs';
18
18
 
19
19
  const TYPES = {
20
20
  bug: { folderKey: 'bugs', prefix: 'BUG', build: buildManualBugNote },
@@ -30,8 +30,23 @@ function opt(argv, name) {
30
30
 
31
31
  export function runNote(argv) {
32
32
  const [sub, ...rest] = argv;
33
+
34
+ if (sub === 'relink') {
35
+ const vaultRaw = opt(rest, '--vault') || process.env.OBSIDIAN_VAULT_PATH;
36
+ if (!vaultRaw) { process.stderr.write('wendkeep note relink: no vault (--vault or OBSIDIAN_VAULT_PATH).\n'); process.exit(2); }
37
+ const vaultBase = isAbsolute(vaultRaw) ? vaultRaw : resolve(process.cwd(), vaultRaw);
38
+ if (!existsSync(vaultBase)) { process.stderr.write(`wendkeep note relink: vault not found: ${vaultBase}\n`); process.exit(2); }
39
+ const r = relinkDerivedNotes(vaultBase, { apply: rest.includes('--apply') });
40
+ if (rest.includes('--json')) { process.stdout.write(`${JSON.stringify(r, null, 2)}\n`); process.exit(0); }
41
+ process.stdout.write(`${r.linked.length} nota(s) derivada(s) órfã(s)${r.applied ? ' linkadas' : ' seriam linkadas'}\n`);
42
+ for (const l of r.linked) process.stdout.write(` ${l.file} -> ${l.session}\n`);
43
+ for (const s of r.skipped) process.stdout.write(` pulado: ${s.file} (${s.reason})\n`);
44
+ if (!r.applied && r.linked.length) process.stdout.write('\ndry-run — nada escrito. Rode com --apply para injetar os backlinks.\n');
45
+ process.exit(0);
46
+ }
47
+
33
48
  if (sub !== 'new') {
34
- process.stderr.write('wendkeep note: subcomando desconhecido (use `note new --type bug|learning "<título>"`).\n');
49
+ process.stderr.write('wendkeep note: subcomando desconhecido (use `note new --type bug|learning "<título>"` ou `note relink [--apply]`).\n');
35
50
  process.exit(2);
36
51
  }
37
52