wendkeep 0.69.0 → 0.70.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.
@@ -0,0 +1,108 @@
1
+ import { homedir } from 'node:os';
2
+ import { isAbsolute, resolve } from 'node:path';
3
+ import { appendObserverEvent, readObserverIndex, registerObserverProject } from './observer-store.mjs';
4
+ import { buildProjectSnapshot } from './observer-snapshot.mjs';
5
+ import { startObserverServer } from './observer-server.mjs';
6
+ import { resolveProjectVault } from '../packages/vault/src/project-vault.mjs';
7
+
8
+ export const OBSERVER_HELP = `wendkeep observer — Observer local multi-projeto
9
+
10
+ Uso:
11
+ wendkeep observer serve [--data-dir P] [--host 127.0.0.1] [--port 8787] [--token T]
12
+ [--allow-non-loopback]
13
+ wendkeep observer register --project P [--vault V] [--data-dir D] [--json]
14
+ wendkeep observer publish --project P [--vault V] [--data-dir D] [--json]
15
+ wendkeep observer status [--data-dir D] [--json]
16
+
17
+ O vault continua local e é a fonte oficial. O Observer armazena apenas snapshots sanitizados
18
+ e um índice reconstruível; o container não monta nem copia vaults de projetos.
19
+ `;
20
+
21
+ function optionValue(argv, name) {
22
+ const index = argv.indexOf(name);
23
+ if (index >= 0) return argv[index + 1] || '';
24
+ return argv.find((item) => item.startsWith(`${name}=`))?.slice(name.length + 1) || '';
25
+ }
26
+
27
+ function dataDir(argv) {
28
+ return resolve(optionValue(argv, '--data-dir')
29
+ || process.env.WENDKEEP_OBSERVER_DATA_DIR
30
+ || `${homedir()}/.wendkeep-observer`);
31
+ }
32
+
33
+ function projectRoot(argv) {
34
+ const value = optionValue(argv, '--project') || process.cwd();
35
+ return isAbsolute(value) ? resolve(value) : resolve(process.cwd(), value);
36
+ }
37
+
38
+ function vaultBase(argv, root) {
39
+ const explicit = optionValue(argv, '--vault');
40
+ if (explicit) return isAbsolute(explicit) ? resolve(explicit) : resolve(root, explicit);
41
+ return resolveProjectVault({ startDir: root }).base;
42
+ }
43
+
44
+ function print(value, asJson) {
45
+ process.stdout.write(`${asJson ? JSON.stringify(value, null, 2) : String(value)}\n`);
46
+ }
47
+
48
+ function summary(index) {
49
+ return {
50
+ schema_version: index.schema_version,
51
+ projects: index.projects.map(({ snapshot, ...item }) => item),
52
+ };
53
+ }
54
+
55
+ export async function runObserver(argv = []) {
56
+ const [sub] = argv;
57
+ const asJson = argv.includes('--json');
58
+ if (!sub || sub === 'help') {
59
+ process.stdout.write(OBSERVER_HELP);
60
+ return 0;
61
+ }
62
+ const dir = dataDir(argv);
63
+
64
+ if (sub === 'status') {
65
+ print(summary(readObserverIndex(dir)), asJson);
66
+ return 0;
67
+ }
68
+
69
+ if (sub === 'serve') {
70
+ const token = optionValue(argv, '--token') || process.env.WENDKEEP_OBSERVER_TOKEN || '';
71
+ const host = optionValue(argv, '--host') || '127.0.0.1';
72
+ const server = await startObserverServer({
73
+ dataDir: dir,
74
+ host,
75
+ port: Number(optionValue(argv, '--port') || 8787),
76
+ token,
77
+ allowNonLoopback: argv.includes('--allow-non-loopback'),
78
+ });
79
+ if (!token) {
80
+ await server.close();
81
+ throw new Error('Observer exige --token ou WENDKEEP_OBSERVER_TOKEN.');
82
+ }
83
+ const address = server.address();
84
+ process.stdout.write(`wendkeep observer listening: http://${address.address}:${address.port}\n`);
85
+ return 0;
86
+ }
87
+
88
+ if (!['register', 'publish'].includes(sub)) throw new Error(`observer: subcomando desconhecido: ${sub}`);
89
+ const root = projectRoot(argv);
90
+ const vault = vaultBase(argv, root);
91
+ const snapshot = buildProjectSnapshot({ vaultBase: vault, projectRoot: root });
92
+
93
+ if (sub === 'register') {
94
+ const result = registerObserverProject(dir, {
95
+ projectId: snapshot.project_id,
96
+ projectName: snapshot.project_name,
97
+ wendkeepVersion: snapshot.wendkeep_version,
98
+ });
99
+ if (!result.registered) throw new Error(result.errors.join(' '));
100
+ print(result, asJson);
101
+ return 0;
102
+ }
103
+
104
+ const result = appendObserverEvent(dir, snapshot);
105
+ if (!result.accepted && !result.duplicate) throw new Error(result.errors.join(' '));
106
+ print({ ok: true, ...result }, asJson);
107
+ return 0;
108
+ }
package/src/taxonomy.mjs CHANGED
@@ -99,6 +99,7 @@ export const HOOK_FILES = [
99
99
  'change-guard.mjs',
100
100
  'change-nag.mjs',
101
101
  'plan-capture.mjs',
102
+ 'observer-publish.mjs',
102
103
  ];
103
104
 
104
105
  // Hook scripts that are safe to invoke directly via `wendkeep hook <name>`.
@@ -122,6 +123,7 @@ export const RUNNABLE_HOOKS = [
122
123
  'change-guard',
123
124
  'change-nag',
124
125
  'plan-capture',
126
+ 'observer-publish',
125
127
  ];
126
128
 
127
129
  // --- companion plugins / MCP --------------------------------------------------