@xmarts/genius-setup 1.3.0 → 1.5.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,36 @@
1
+ # Xmarts Genius — Protocolo de Consultor
2
+
3
+ > Esta sección la instala/actualiza automáticamente `@xmarts/genius-setup`. No la edites a mano.
4
+
5
+ ## Cómo funciona (cero fricción)
6
+
7
+ El Brain de Genius está conectado vía el MCP **`beesmart_genius`** y dos hooks de Claude Code:
8
+ - **Inyección por turno** (UserPromptSubmit/SessionStart): en cada turno recibes automáticamente los
9
+ learnings, playbooks y patrones relevantes — no tienes que pedirlos.
10
+ - **Captura automática** (SessionEnd/PreCompact/Stop): tus hallazgos y tu sesión se capturan solos al
11
+ final; no tienes que documentar manualmente.
12
+ - **Auto-actualización**: el paquete se refresca solo en segundo plano (1×/día). Cuando agregamos tools,
13
+ skills o features, las recibes en tus turnos **sin hacer nada**.
14
+
15
+ ## Reglas Obligatorias (siempre activas)
16
+
17
+ 1. **ANTES de cada tarea**: usa `query_knowledge` (o `ask_brain`) para buscar conocimiento existente.
18
+ 2. **AL descubrir algo nuevo**: captura con `capture_learning` — título claro + resolución detallada.
19
+ 3. **AL resolver un error**: documenta error → fix (el Brain auto-detecta el par).
20
+ 4. **SIEMPRE usa `target_client`** para operar en un cliente (p.ej. `target_client="GEA Ecuador"`).
21
+ 5. **NUNCA te conectes directo al Odoo del cliente** — todo fluye por el MCP `beesmart_genius`.
22
+ 6. Tu tiempo se sugiere solo a partir de tu actividad; confírmalo cuando puedas en **My Week**
23
+ (`/mcp/webapp/my-week`). Solo el tiempo que confirmas cuenta como horas reales.
24
+
25
+ ## Tools (servidas dinámicamente por `beesmart_genius`)
26
+
27
+ | Tool | Cuándo usar |
28
+ |------|-------------|
29
+ | `query_knowledge` | Antes de cada tarea — busca en el Brain |
30
+ | `capture_learning` | Al descubrir algo nuevo |
31
+ | `get_my_profile` | Ver tu perfil de consultor |
32
+ | `search_read` / `execute_orm` + `target_client` | Consultar/operar data de cualquier cliente vía gateway |
33
+ | `list_models` / `get_model_schema` + `target_client` | Inspeccionar esquema de un cliente |
34
+
35
+ > La lista completa de tools (y skills como prompts) la sirve el MCP en tiempo real; al agregar nuevas,
36
+ > aparecen automáticamente en tu sesión sin reconfigurar nada.
@@ -2,18 +2,26 @@
2
2
  /**
3
3
  * @xmarts/genius-setup — one-command frictionless onboarding for Xmarts Genius.
4
4
  *
5
- * npx @xmarts/genius-setup --token <bearer> [--base-url https://beesmart.digital] [--client "Acme"]
5
+ * # Secret-free path (preferred — the setup link delivers no secret in the GET):
6
+ * GENIUS_SETUP_TOKEN=<setup-token> npx @xmarts/genius-setup [--base-url https://beesmart.digital]
7
+ *
8
+ * # Back-compat path (an already-resolved consultant Bearer):
9
+ * GENIUS_TOKEN=<bearer> npx @xmarts/genius-setup [--base-url ...] [--client "Acme"]
6
10
  *
7
11
  * Idempotent + cross-platform (incl. Windows). It:
8
- * 1. writes ~/.genius/config.json (endpoints + token) and installs the per-turn
12
+ * 1. (if given GENIUS_SETUP_TOKEN) redeems the single-use setup token for the
13
+ * consultant Bearer via a TLS POST to /xma/genius/v1/setup/exchange — the
14
+ * Bearer never rides inside a GET-able bootstrap script;
15
+ * 2. writes ~/.genius/config.json (endpoints + token) and installs the per-turn
9
16
  * inject hook (hooks/genius_inject.py) + the session-capture hook
10
17
  * (hooks/genius_capture.py);
11
- * 2. registers the beesmart_genius MCP server in ~/.claude.json;
12
- * 3. wires per-turn injection (UserPromptSubmit) + SessionStart priming +
18
+ * 3. registers the beesmart_genius MCP server in ~/.claude.json;
19
+ * 4. wires per-turn injection (UserPromptSubmit) + SessionStart priming +
13
20
  * SessionEnd/PreCompact/Stop capture into ~/.claude/settings.json — merged,
14
- * never duplicated, with a timestamped backup first.
21
+ * never duplicated, with a timestamped backup first;
22
+ * 5. installs/refreshes the Genius Protocol in ~/.claude/CLAUDE.md.
15
23
  * After this, the consultant has Brain + capture + feedback flowing with zero
16
- * further prompts. The token is the consultant's MCP Bearer (no new secret).
24
+ * further prompts, and the package self-updates daily.
17
25
  */
18
26
  'use strict';
19
27
  const fs = require('fs');
@@ -26,104 +34,202 @@ function arg(name, def) {
26
34
  }
27
35
  function log(msg) { process.stdout.write(msg + '\n'); }
28
36
 
29
- // (#pkg-4) Prefer GENIUS_TOKEN env over --token argv: argv leaks into the
30
- // process list and shell history. Warn if a token is passed on the CLI.
37
+ const BASE = (arg('base-url', 'https://beesmart.digital')).replace(/\/+$/, '');
38
+ const CLIENT = arg('client', '');
39
+
40
+ // -----------------------------------------------------------------------------
41
+ // Token resolution (priority order):
42
+ // 1. GENIUS_TOKEN env — an already-resolved consultant Bearer (back-compat
43
+ // with links/commands minted before the exchange).
44
+ // 2. --token argv — same, but leaks to the process list (warn).
45
+ // 3. GENIUS_SETUP_TOKEN / — a single-use setup token we redeem ONCE, over TLS,
46
+ // --setup-token for the Bearer. This is the secret-free path: the
47
+ // Bearer is never embedded in a GET-able script.
48
+ // -----------------------------------------------------------------------------
31
49
  let TOKEN = process.env.GENIUS_TOKEN || '';
32
50
  if (!TOKEN) {
33
51
  TOKEN = arg('token', '');
34
52
  if (TOKEN) log('WARN: passing --token on the CLI leaks it to the process list / shell history. Prefer GENIUS_TOKEN=... npx @xmarts/genius-setup');
35
53
  }
36
- const BASE = (arg('base-url', 'https://beesmart.digital')).replace(/\/+$/, '');
37
- const CLIENT = arg('client', '');
38
- if (!TOKEN) {
39
- log('ERROR: a consultant Bearer token is required. Set GENIUS_TOKEN=<token> (preferred) or pass --token <token>.');
40
- process.exit(1);
54
+ const SETUP_TOKEN = process.env.GENIUS_SETUP_TOKEN || arg('setup-token', '');
55
+
56
+ function exchangeSetupToken(setupToken, cb) {
57
+ // Redeem the single-use setup token for the consultant Bearer. The api_key
58
+ // crosses the wire exactly once, in this TLS POST body, to a caller holding
59
+ // the unguessable 256-bit token; the server consumes the token atomically.
60
+ let url;
61
+ try { url = new URL(BASE + '/xma/genius/v1/setup/exchange'); }
62
+ catch (e) { return cb(e); }
63
+ const mod = url.protocol === 'http:' ? require('http') : require('https');
64
+ const payload = JSON.stringify({
65
+ jsonrpc: '2.0', method: 'call', id: 1,
66
+ params: { setup_token: setupToken },
67
+ });
68
+ const req = mod.request({
69
+ hostname: url.hostname,
70
+ port: url.port || (url.protocol === 'http:' ? 80 : 443),
71
+ path: url.pathname,
72
+ method: 'POST',
73
+ headers: {
74
+ 'Content-Type': 'application/json',
75
+ 'Content-Length': Buffer.byteLength(payload),
76
+ // Cloudflare in front of beesmart.digital 403s the default Node UA.
77
+ 'User-Agent': 'XmartsGenius-Setup/1.5.0',
78
+ },
79
+ timeout: 15000,
80
+ }, (res) => {
81
+ let data = '';
82
+ res.on('data', (c) => { data += c; });
83
+ res.on('end', () => {
84
+ try {
85
+ const parsed = JSON.parse(data);
86
+ const result = parsed.result || parsed;
87
+ if (result && result.status === 'ok' && result.api_key) {
88
+ cb(null, result.api_key);
89
+ } else {
90
+ cb(new Error((result && result.message) || 'exchange_failed'));
91
+ }
92
+ } catch (e) { cb(e); }
93
+ });
94
+ });
95
+ req.on('error', (e) => cb(e));
96
+ req.on('timeout', () => { req.destroy(new Error('exchange_timeout')); });
97
+ req.write(payload);
98
+ req.end();
41
99
  }
42
100
 
43
- const HOME = os.homedir();
44
- const GENIUS_DIR = path.join(HOME, '.genius');
45
- const HOOKS_DIR = path.join(GENIUS_DIR, 'hooks');
46
- const CLAUDE_DIR = path.join(HOME, '.claude');
101
+ function runSetup(token) {
102
+ const HOME = os.homedir();
103
+ const GENIUS_DIR = path.join(HOME, '.genius');
104
+ const HOOKS_DIR = path.join(GENIUS_DIR, 'hooks');
105
+ const CLAUDE_DIR = path.join(HOME, '.claude');
47
106
 
48
- function ensureDir(d) { fs.mkdirSync(d, { recursive: true }); }
49
- function readJson(p) { try { return JSON.parse(fs.readFileSync(p, 'utf8')); } catch (_) { return {}; } }
50
- function backup(p) {
51
- if (fs.existsSync(p)) {
52
- const stamp = new Date().toISOString().replace(/[:.]/g, '-');
53
- fs.copyFileSync(p, p + '.genius-bak-' + stamp);
107
+ function ensureDir(d) { fs.mkdirSync(d, { recursive: true }); }
108
+ function readJson(p) { try { return JSON.parse(fs.readFileSync(p, 'utf8')); } catch (_) { return {}; } }
109
+ function backup(p) {
110
+ if (fs.existsSync(p)) {
111
+ const stamp = new Date().toISOString().replace(/[:.]/g, '-');
112
+ fs.copyFileSync(p, p + '.genius-bak-' + stamp);
113
+ }
114
+ }
115
+ function writeJson(p, obj, secret) {
116
+ // (#pkg-3) secret files (token-bearing) are written 0600, never world-readable.
117
+ ensureDir(path.dirname(p));
118
+ fs.writeFileSync(p, JSON.stringify(obj, null, 2), secret ? { mode: 0o600 } : undefined);
119
+ if (secret) { try { fs.chmodSync(p, 0o600); } catch (_) {} }
54
120
  }
55
- }
56
- function writeJson(p, obj, secret) {
57
- // (#pkg-3) secret files (token-bearing) are written 0600, never world-readable.
58
- ensureDir(path.dirname(p));
59
- fs.writeFileSync(p, JSON.stringify(obj, null, 2), secret ? { mode: 0o600 } : undefined);
60
- if (secret) { try { fs.chmodSync(p, 0o600); } catch (_) {} }
61
- }
62
121
 
63
- // 1) ~/.genius/config.json + hook
64
- ensureDir(HOOKS_DIR);
65
- const cfg = {
66
- base_url: BASE,
67
- token: TOKEN,
68
- capture_endpoint: BASE + '/xma/genius/v1/capture/transcript',
69
- inject_endpoint: BASE + '/xma/genius/v1/inject',
70
- };
71
- if (CLIENT) cfg.target_client = CLIENT;
72
- writeJson(path.join(GENIUS_DIR, 'config.json'), cfg, true); // secret: 0600
122
+ // 1) ~/.genius/config.json + hook
123
+ ensureDir(HOOKS_DIR);
124
+ const cfg = {
125
+ base_url: BASE,
126
+ token: token,
127
+ capture_endpoint: BASE + '/xma/genius/v1/capture/transcript',
128
+ inject_endpoint: BASE + '/xma/genius/v1/inject',
129
+ };
130
+ if (CLIENT) cfg.target_client = CLIENT;
131
+ writeJson(path.join(GENIUS_DIR, 'config.json'), cfg, true); // secret: 0600
73
132
 
74
- // Copy the hooks shipped alongside this script (capture + per-turn inject).
75
- function copyHook(fname) {
76
- const src = path.join(__dirname, '..', 'hooks', fname);
77
- const dst = path.join(HOOKS_DIR, fname);
78
- try {
79
- fs.copyFileSync(src, dst);
80
- try { fs.chmodSync(dst, 0o755); } catch (_) {}
81
- } catch (e) {
82
- log('WARN: could not copy hook from ' + src + ' (' + e.message + ')');
133
+ // Copy the hooks shipped alongside this script (capture + per-turn inject).
134
+ function copyHook(fname) {
135
+ const src = path.join(__dirname, '..', 'hooks', fname);
136
+ const dst = path.join(HOOKS_DIR, fname);
137
+ try {
138
+ fs.copyFileSync(src, dst);
139
+ try { fs.chmodSync(dst, 0o755); } catch (_) {}
140
+ } catch (e) {
141
+ log('WARN: could not copy hook from ' + src + ' (' + e.message + ')');
142
+ }
143
+ return dst;
83
144
  }
84
- return dst;
85
- }
86
- const hookDst = copyHook('genius_capture.py');
87
- const injectDst = copyHook('genius_inject.py');
145
+ const hookDst = copyHook('genius_capture.py');
146
+ const injectDst = copyHook('genius_inject.py');
88
147
 
89
- // 2) ~/.claude.json mcpServers (merge, no clobber)
90
- const claudeJsonPath = path.join(HOME, '.claude.json');
91
- const claudeJson = readJson(claudeJsonPath);
92
- backup(claudeJsonPath);
93
- claudeJson.mcpServers = claudeJson.mcpServers || {};
94
- claudeJson.mcpServers['beesmart_genius'] = {
95
- type: 'http',
96
- url: BASE + '/mcp/consultant',
97
- headers: { Authorization: 'Bearer ' + TOKEN },
98
- };
99
- writeJson(claudeJsonPath, claudeJson, true); // contains the Bearer -> 0600
148
+ // 2) ~/.claude.json mcpServers (merge, no clobber)
149
+ const claudeJsonPath = path.join(HOME, '.claude.json');
150
+ const claudeJson = readJson(claudeJsonPath);
151
+ backup(claudeJsonPath);
152
+ claudeJson.mcpServers = claudeJson.mcpServers || {};
153
+ claudeJson.mcpServers['beesmart_genius'] = {
154
+ type: 'http',
155
+ url: BASE + '/mcp/consultant',
156
+ headers: { Authorization: 'Bearer ' + token },
157
+ };
158
+ writeJson(claudeJsonPath, claudeJson, true); // contains the Bearer -> 0600
100
159
 
101
- // 3) ~/.claude/settings.json hooks (merge by command, no dup)
102
- const settingsPath = path.join(CLAUDE_DIR, 'settings.json');
103
- const settings = readJson(settingsPath);
104
- backup(settingsPath);
105
- settings.hooks = settings.hooks || {};
106
- function addHook(eventName, scriptPath) {
107
- settings.hooks[eventName] = settings.hooks[eventName] || [];
108
- const marker = path.basename(scriptPath);
109
- const already = JSON.stringify(settings.hooks[eventName]).includes(marker);
110
- if (!already) {
111
- const cmd = `python3 ${JSON.stringify(scriptPath)} || true`;
112
- settings.hooks[eventName].push({ hooks: [{ type: 'command', command: cmd }] });
160
+ // 3) ~/.claude/settings.json hooks (merge by command, no dup)
161
+ const settingsPath = path.join(CLAUDE_DIR, 'settings.json');
162
+ const settings = readJson(settingsPath);
163
+ backup(settingsPath);
164
+ settings.hooks = settings.hooks || {};
165
+ function addHook(eventName, scriptPath) {
166
+ settings.hooks[eventName] = settings.hooks[eventName] || [];
167
+ const marker = path.basename(scriptPath);
168
+ const already = JSON.stringify(settings.hooks[eventName]).includes(marker);
169
+ if (!already) {
170
+ const cmd = `python3 ${JSON.stringify(scriptPath)} || true`;
171
+ settings.hooks[eventName].push({ hooks: [{ type: 'command', command: cmd }] });
172
+ }
113
173
  }
174
+ // Capture (transcript -> Brain) on session boundaries.
175
+ ['SessionEnd', 'PreCompact', 'Stop'].forEach((e) => addHook(e, hookDst));
176
+ // Per-turn knowledge injection + session priming (consultant_access guarantee).
177
+ ['UserPromptSubmit', 'SessionStart'].forEach((e) => addHook(e, injectDst));
178
+ writeJson(settingsPath, settings);
179
+
180
+ // 4) ~/.claude/CLAUDE.md — install/refresh the Genius Protocol between auto-managed
181
+ // markers (idempotent; never clobbers the consultant's surrounding content).
182
+ const BEGIN = '<!-- XMARTS-GENIUS-PROTOCOL:BEGIN (auto-managed by @xmarts/genius-setup) -->';
183
+ const END = '<!-- XMARTS-GENIUS-PROTOCOL:END -->';
184
+ try {
185
+ ensureDir(CLAUDE_DIR);
186
+ const claudeMdPath = path.join(CLAUDE_DIR, 'CLAUDE.md');
187
+ let existing = '';
188
+ try { existing = fs.readFileSync(claudeMdPath, 'utf8'); } catch (_) {}
189
+ const proto = fs.readFileSync(path.join(__dirname, '..', 'CLAUDE_PROTOCOL.md'), 'utf8').trim();
190
+ const block = BEGIN + '\n' + proto + '\n' + END;
191
+ let out;
192
+ if (existing.includes(BEGIN) && existing.includes(END)) {
193
+ out = existing.slice(0, existing.indexOf(BEGIN)) + block +
194
+ existing.slice(existing.indexOf(END) + END.length);
195
+ } else {
196
+ out = (existing ? existing.replace(/\s+$/, '') + '\n\n' : '') + block + '\n';
197
+ }
198
+ fs.writeFileSync(claudeMdPath, out);
199
+ } catch (e) {
200
+ log('WARN: could not write CLAUDE.md protocol (' + e.message + ')');
201
+ }
202
+
203
+ log('');
204
+ log(' Xmarts Genius is set up.');
205
+ log(' - MCP server : beesmart_genius -> ' + BASE + '/mcp/consultant');
206
+ log(' - Capture hook : ' + hookDst + ' (SessionEnd / PreCompact / Stop)');
207
+ log(' - Inject hook : ' + injectDst + ' (UserPromptSubmit / SessionStart)');
208
+ log(' - Config : ' + path.join(GENIUS_DIR, 'config.json'));
209
+ log(' - Protocol : ' + path.join(CLAUDE_DIR, 'CLAUDE.md') + ' (auto-managed)');
210
+ if (CLIENT) log(' - Default client : ' + CLIENT);
211
+ log('');
212
+ log(' Restart Claude Code. Per-turn Brain injection + automatic capture + the Genius');
213
+ log(' protocol are now active. The package SELF-UPDATES daily in the background, so new');
214
+ log(' tools, skills and features arrive automatically — you never have to run this again.');
114
215
  }
115
- // Capture (transcript -> Brain) on session boundaries.
116
- ['SessionEnd', 'PreCompact', 'Stop'].forEach((e) => addHook(e, hookDst));
117
- // Per-turn knowledge injection + session priming (consultant_access guarantee).
118
- ['UserPromptSubmit', 'SessionStart'].forEach((e) => addHook(e, injectDst));
119
- writeJson(settingsPath, settings);
120
216
 
121
- log('');
122
- log(' Xmarts Genius is set up.');
123
- log(' - MCP server : beesmart_genius -> ' + BASE + '/mcp/consultant');
124
- log(' - Capture hook : ' + hookDst + ' (SessionEnd / PreCompact / Stop)');
125
- log(' - Inject hook : ' + injectDst + ' (UserPromptSubmit / SessionStart)');
126
- log(' - Config : ' + path.join(GENIUS_DIR, 'config.json'));
127
- if (CLIENT) log(' - Default client : ' + CLIENT);
128
- log('');
129
- log(' Restart Claude Code. Per-turn Brain injection + automatic capture are now active — no further prompts.');
217
+ // -----------------------------------------------------------------------------
218
+ // Entry point
219
+ // -----------------------------------------------------------------------------
220
+ if (TOKEN) {
221
+ // Already-resolved Bearer (back-compat path / self-update). No exchange.
222
+ runSetup(TOKEN);
223
+ } else if (SETUP_TOKEN) {
224
+ // Secret-free path: redeem the single-use setup token for the Bearer.
225
+ exchangeSetupToken(SETUP_TOKEN, (err, key) => {
226
+ if (err || !key) {
227
+ log('ERROR: el enlace de setup ya fue usado o expiró. Pide a tu admin de Xmarts que regenere el link de setup.');
228
+ process.exit(1);
229
+ }
230
+ runSetup(key);
231
+ });
232
+ } else {
233
+ log('ERROR: falta el token. Ejecuta el link de setup de Genius (recomendado) o define GENIUS_TOKEN=<token>.');
234
+ process.exit(1);
235
+ }
@@ -22,6 +22,8 @@ import urllib.request
22
22
  HOME = os.path.expanduser("~")
23
23
  CFG_PATH = os.path.join(HOME, ".genius", "config.json")
24
24
  TIMEOUT = 3.5
25
+ SELF_UPDATE_TTL = 86400 # at most once/day
26
+ SELF_UPDATE_STAMP = os.path.join(HOME, ".genius", ".last_selfupdate")
25
27
 
26
28
  SESSION_PRIMER = (
27
29
  "[Xmarts Genius — Brain connected]\n"
@@ -77,10 +79,53 @@ def _inject(cfg, prompt):
77
79
  return ""
78
80
 
79
81
 
82
+ def _maybe_self_update(cfg):
83
+ """Keep the consultant on the LATEST Genius package with ZERO action: at most
84
+ once/day, silently re-run the installer in the background. New hooks, MCP
85
+ tools, settings and the CLAUDE.md protocol then flow automatically — the
86
+ consultant never re-onboards. Detached + fully guarded; never blocks a turn.
87
+ """
88
+ import time
89
+ import subprocess
90
+ try:
91
+ token = cfg.get("token")
92
+ if not token:
93
+ return
94
+ if os.path.exists(SELF_UPDATE_STAMP) and (
95
+ time.time() - os.path.getmtime(SELF_UPDATE_STAMP)) < SELF_UPDATE_TTL:
96
+ return
97
+ # Stamp FIRST so a failing/slow npx never causes a retry storm.
98
+ try:
99
+ os.makedirs(os.path.dirname(SELF_UPDATE_STAMP), exist_ok=True)
100
+ with open(SELF_UPDATE_STAMP, "w") as fh:
101
+ fh.write(str(int(time.time())))
102
+ except Exception:
103
+ return
104
+ env = dict(os.environ)
105
+ env["GENIUS_TOKEN"] = token
106
+ base = cfg.get("base_url")
107
+ devnull = open(os.devnull, "w")
108
+ if os.name == "nt":
109
+ cmd = "npx -y @xmarts/genius-setup@latest"
110
+ if base:
111
+ cmd += ' --base-url "%s"' % base
112
+ subprocess.Popen(cmd, shell=True, env=env, stdout=devnull, stderr=devnull,
113
+ stdin=subprocess.DEVNULL, creationflags=0x00000008) # DETACHED_PROCESS
114
+ else:
115
+ args = ["npx", "-y", "@xmarts/genius-setup@latest"]
116
+ if base:
117
+ args += ["--base-url", base]
118
+ subprocess.Popen(args, env=env, stdout=devnull, stderr=devnull,
119
+ stdin=subprocess.DEVNULL, start_new_session=True)
120
+ except Exception:
121
+ pass
122
+
123
+
80
124
  def main():
81
125
  cfg = _cfg()
82
126
  if not cfg.get("token"):
83
127
  return # not configured -> silent no-op
128
+ _maybe_self_update(cfg) # background, daily, zero-action upgrades
84
129
  event = _event()
85
130
  name = event.get("hook_event_name") or (
86
131
  "UserPromptSubmit" if event.get("prompt") else "SessionStart")
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xmarts/genius-setup",
3
- "version": "1.3.0",
4
- "description": "One-command frictionless onboarding for Xmarts Genius (Brain MCP + per-turn injection + automatic session capture + Claude-session time telemetry).",
3
+ "version": "1.5.0",
4
+ "description": "One-command, self-updating onboarding for Xmarts Genius (Brain MCP + per-turn injection + automatic session/time capture + CLAUDE.md protocol). Secret-free onboarding via single-use setup-token exchange (no Bearer in the GET-able bootstrap). Installs once; self-updates daily so new tools/skills/features arrive with zero action.",
5
5
  "bin": {
6
6
  "genius-setup": "bin/genius-setup.js"
7
7
  },
@@ -9,6 +9,7 @@
9
9
  "bin/genius-setup.js",
10
10
  "hooks/genius_inject.py",
11
11
  "hooks/genius_capture.py",
12
+ "CLAUDE_PROTOCOL.md",
12
13
  "README.md"
13
14
  ],
14
15
  "engines": {