rex-claude 1.1.7 → 2.0.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 (57) hide show
  1. package/dist/guards/completion-guard.sh +40 -0
  2. package/dist/guards/dangerous-cmd-guard.sh +50 -0
  3. package/dist/guards/scope-guard.sh +16 -0
  4. package/dist/guards/session-summary.sh +42 -0
  5. package/dist/guards/test-protect-guard.sh +15 -0
  6. package/dist/guards/ui-checklist-guard.sh +44 -0
  7. package/dist/index.js +454 -0
  8. package/dist/init-YMRG5ZXU.js +248 -0
  9. package/dist/optimize-NE47FMOP.js +111 -0
  10. package/package.json +26 -22
  11. package/README.md +0 -163
  12. package/activity/activity.jsonl +0 -443
  13. package/activity/config.lua +0 -3
  14. package/activity/init.lua +0 -49
  15. package/dist/cli.js +0 -504
  16. package/dotfiles/CLAUDE.md +0 -136
  17. package/dotfiles/commands/clean.md +0 -8
  18. package/dotfiles/commands/doc.md +0 -8
  19. package/dotfiles/commands/review.md +0 -15
  20. package/dotfiles/commands/scaffold.md +0 -11
  21. package/dotfiles/commands/test.md +0 -11
  22. package/dotfiles/docs/cloudflare.md +0 -62
  23. package/dotfiles/docs/nextjs.md +0 -79
  24. package/dotfiles/docs/react.md +0 -63
  25. package/dotfiles/docs/tailwind.md +0 -45
  26. package/dotfiles/docs/telegram-bot.md +0 -55
  27. package/dotfiles/rules/api-design.md +0 -63
  28. package/dotfiles/rules/defensive-engineering.md +0 -42
  29. package/dotfiles/rules/docs-first.md +0 -47
  30. package/dotfiles/rules/frontend.md +0 -41
  31. package/dotfiles/rules/git-workflow.md +0 -57
  32. package/dotfiles/rules/never-assume.md +0 -39
  33. package/dotfiles/rules/security.md +0 -46
  34. package/dotfiles/rules/testing.md +0 -33
  35. package/dotfiles/settings.json +0 -80
  36. package/dotfiles/skills/build-validate/SKILL.md +0 -16
  37. package/dotfiles/skills/code-review/SKILL.md +0 -18
  38. package/dotfiles/skills/context-loader/SKILL.md +0 -25
  39. package/dotfiles/skills/debug-assist/SKILL.md +0 -26
  40. package/dotfiles/skills/deploy-checklist/SKILL.md +0 -54
  41. package/dotfiles/skills/dstudio-design-system/SKILL.md +0 -120
  42. package/dotfiles/skills/figma-workflow/SKILL.md +0 -23
  43. package/dotfiles/skills/fix-issue/SKILL.md +0 -43
  44. package/dotfiles/skills/one-shot/SKILL.md +0 -18
  45. package/dotfiles/skills/pr-review-loop/SKILL.md +0 -41
  46. package/dotfiles/skills/project-init/SKILL.md +0 -45
  47. package/dotfiles/skills/research/SKILL.md +0 -17
  48. package/dotfiles/skills/spec-interview/SKILL.md +0 -20
  49. package/dotfiles/skills/token-guard/SKILL.md +0 -26
  50. package/dotfiles/templates/CLAUDE.md.template +0 -39
  51. package/memory/package.json +0 -24
  52. package/memory/src/embed.ts +0 -23
  53. package/memory/src/ingest.ts +0 -257
  54. package/memory/src/search.ts +0 -32
  55. package/memory/src/server.ts +0 -69
  56. package/memory/tsconfig.json +0 -14
  57. package/tmux/.tmux.conf +0 -73
package/dist/cli.js DELETED
@@ -1,504 +0,0 @@
1
- #!/usr/bin/env node
2
- import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync } from 'fs';
3
- import { join, resolve, dirname } from 'path';
4
- import { homedir, platform } from 'os';
5
- import { execSync } from 'child_process';
6
- import { fileURLToPath } from 'url';
7
- const __dirname = dirname(fileURLToPath(import.meta.url));
8
- const HOME = homedir();
9
- const CLAUDE_DIR = join(HOME, '.claude');
10
- const REX_MEMORY_DIR = join(HOME, '.rex-memory');
11
- const PKG_DIR = resolve(__dirname, '..');
12
- const GREEN = '\x1b[32m';
13
- const YELLOW = '\x1b[33m';
14
- const RED = '\x1b[31m';
15
- const CYAN = '\x1b[36m';
16
- const BOLD = '\x1b[1m';
17
- const DIM = '\x1b[2m';
18
- const RESET = '\x1b[0m';
19
- function log(icon, msg) { console.log(` ${icon} ${msg}`); }
20
- function ok(msg) { log(`${GREEN}✓${RESET}`, msg); }
21
- function warn(msg) { log(`${YELLOW}⚠${RESET}`, msg); }
22
- function info(msg) { log(`${CYAN}→${RESET}`, msg); }
23
- function fail(msg) { log(`${RED}✗${RESET}`, msg); }
24
- // ─── Helpers ──────────────────────────────────────────────────────────────────
25
- function safeWhich(bin, fallback) {
26
- try {
27
- return execSync(`which ${bin}`, { stdio: 'pipe' }).toString().trim() || fallback;
28
- }
29
- catch {
30
- return fallback;
31
- }
32
- }
33
- function ensureDir(dirPath) {
34
- try {
35
- mkdirSync(dirPath, { recursive: true });
36
- return true;
37
- }
38
- catch (e) {
39
- warn(`Impossible de créer ${dirPath}: ${e.message?.split('\n')[0]}`);
40
- return false;
41
- }
42
- }
43
- function safeReadFile(filePath) {
44
- try {
45
- return readFileSync(filePath, 'utf-8');
46
- }
47
- catch {
48
- return null;
49
- }
50
- }
51
- function safeWriteFile(filePath, content) {
52
- try {
53
- writeFileSync(filePath, content);
54
- return true;
55
- }
56
- catch (e) {
57
- warn(`Impossible d'écrire ${filePath}: ${e.message?.split('\n')[0]}`);
58
- return false;
59
- }
60
- }
61
- function backup(filePath) {
62
- if (!existsSync(filePath))
63
- return null;
64
- const backupPath = `${filePath}.backup-${Date.now()}`;
65
- try {
66
- copyFileSync(filePath, backupPath);
67
- return backupPath;
68
- }
69
- catch (e) {
70
- warn(`Backup impossible pour ${filePath}: ${e.message?.split('\n')[0]}`);
71
- return null;
72
- }
73
- }
74
- function loadPlist(plistPath) {
75
- try {
76
- execSync(`launchctl unload "${plistPath}" 2>/dev/null; launchctl load "${plistPath}"`, { stdio: 'pipe' });
77
- }
78
- catch (e) {
79
- throw new Error(`launchctl load: ${e.message?.split('\n')[0]}`);
80
- }
81
- }
82
- // ─── Settings merge ───────────────────────────────────────────────────────────
83
- function deepMerge(target, source) {
84
- const result = { ...target };
85
- for (const key of Object.keys(source)) {
86
- if (result[key] && typeof result[key] === 'object' && !Array.isArray(result[key]) &&
87
- typeof source[key] === 'object' && !Array.isArray(source[key])) {
88
- result[key] = deepMerge(result[key], source[key]);
89
- }
90
- else {
91
- result[key] = source[key];
92
- }
93
- }
94
- return result;
95
- }
96
- function mergeArraysByMatcher(existing, incoming) {
97
- const result = [...existing];
98
- for (const item of incoming) {
99
- const idx = result.findIndex((e) => e.matcher === item.matcher);
100
- if (idx === -1)
101
- result.push(item);
102
- else
103
- result[idx] = item;
104
- }
105
- return result;
106
- }
107
- function mergeSettings(existingPath, rexSettingsPath) {
108
- let existing = {};
109
- if (existsSync(existingPath)) {
110
- try {
111
- existing = JSON.parse(readFileSync(existingPath, 'utf-8'));
112
- }
113
- catch {
114
- warn('settings.json existant corrompu — réinitialisé');
115
- }
116
- }
117
- let rex = {};
118
- try {
119
- rex = JSON.parse(readFileSync(rexSettingsPath, 'utf-8'));
120
- }
121
- catch (e) {
122
- throw new Error(`settings.json REX illisible: ${e.message}`);
123
- }
124
- const merged = deepMerge(existing, rex);
125
- if (rex.hooks) {
126
- merged.hooks = { ...existing.hooks };
127
- for (const hookType of Object.keys(rex.hooks)) {
128
- if (Array.isArray(rex.hooks[hookType])) {
129
- merged.hooks[hookType] = mergeArraysByMatcher(existing.hooks?.[hookType] || [], rex.hooks[hookType]);
130
- }
131
- }
132
- }
133
- if (!merged.mcpServers)
134
- merged.mcpServers = {};
135
- merged.mcpServers['rex-memory'] = {
136
- command: 'node',
137
- args: [join(REX_MEMORY_DIR, 'dist', 'server.js')]
138
- };
139
- return merged;
140
- }
141
- // ─── Install steps ────────────────────────────────────────────────────────────
142
- function installOllama(os) {
143
- const ollamaPath = safeWhich('ollama', '');
144
- if (!ollamaPath) {
145
- warn('Ollama non installé — embeddings désactivés');
146
- info(' brew install ollama && ollama pull nomic-embed-text');
147
- return;
148
- }
149
- ok(`Ollama détecté (${ollamaPath})`);
150
- if (os !== 'darwin') {
151
- // Linux: systemd user service
152
- info('Linux: démarrer Ollama manuellement ou via systemd');
153
- info(' ollama serve &');
154
- return;
155
- }
156
- const launchAgentsDir = join(HOME, 'Library', 'LaunchAgents');
157
- if (!ensureDir(launchAgentsDir))
158
- return;
159
- const logsDir = join(REX_MEMORY_DIR, 'logs');
160
- if (!ensureDir(logsDir))
161
- return;
162
- const plistPath = join(launchAgentsDir, 'com.rex.ollama.plist');
163
- const plist = `<?xml version="1.0" encoding="UTF-8"?>
164
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
165
- <plist version="1.0">
166
- <dict>
167
- <key>Label</key>
168
- <string>com.rex.ollama</string>
169
- <key>ProgramArguments</key>
170
- <array>
171
- <string>${ollamaPath}</string>
172
- <string>serve</string>
173
- </array>
174
- <key>EnvironmentVariables</key>
175
- <dict>
176
- <key>HOME</key>
177
- <string>${HOME}</string>
178
- <key>OLLAMA_HOST</key>
179
- <string>127.0.0.1:11434</string>
180
- </dict>
181
- <key>RunAtLoad</key>
182
- <true/>
183
- <key>KeepAlive</key>
184
- <true/>
185
- <key>StandardOutPath</key>
186
- <string>${join(logsDir, 'ollama.log')}</string>
187
- <key>StandardErrorPath</key>
188
- <string>${join(logsDir, 'ollama-error.log')}</string>
189
- <key>ThrottleInterval</key>
190
- <integer>10</integer>
191
- </dict>
192
- </plist>`;
193
- if (!safeWriteFile(plistPath, plist))
194
- return;
195
- try {
196
- loadPlist(plistPath);
197
- ok('LaunchAgent Ollama installé (keepalive au login)');
198
- }
199
- catch (e) {
200
- warn(`LaunchAgent Ollama créé — chargement manuel: launchctl load "${plistPath}"`);
201
- info(` Erreur: ${e.message}`);
202
- }
203
- }
204
- function installMemoryIngest(os) {
205
- const ingestScript = join(REX_MEMORY_DIR, 'dist', 'ingest.js');
206
- if (!existsSync(ingestScript)) {
207
- warn('ingest.js non trouvé — ingest auto ignoré (rex-memory non compilé ?)');
208
- return;
209
- }
210
- const logsDir = join(REX_MEMORY_DIR, 'logs');
211
- if (!ensureDir(logsDir))
212
- return;
213
- const nodePath = safeWhich('node', process.execPath);
214
- if (os === 'darwin') {
215
- const launchAgentsDir = join(HOME, 'Library', 'LaunchAgents');
216
- if (!ensureDir(launchAgentsDir))
217
- return;
218
- const plistPath = join(launchAgentsDir, 'com.rex.memory-ingest.plist');
219
- const plist = `<?xml version="1.0" encoding="UTF-8"?>
220
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
221
- <plist version="1.0">
222
- <dict>
223
- <key>Label</key>
224
- <string>com.rex.memory-ingest</string>
225
- <key>ProgramArguments</key>
226
- <array>
227
- <string>${nodePath}</string>
228
- <string>${ingestScript}</string>
229
- </array>
230
- <key>EnvironmentVariables</key>
231
- <dict>
232
- <key>HOME</key>
233
- <string>${HOME}</string>
234
- <key>OLLAMA_URL</key>
235
- <string>http://localhost:11434</string>
236
- </dict>
237
- <key>StartInterval</key>
238
- <integer>21600</integer>
239
- <key>StandardOutPath</key>
240
- <string>${join(logsDir, 'ingest.log')}</string>
241
- <key>StandardErrorPath</key>
242
- <string>${join(logsDir, 'ingest-error.log')}</string>
243
- <key>RunAtLoad</key>
244
- <false/>
245
- </dict>
246
- </plist>`;
247
- if (!safeWriteFile(plistPath, plist))
248
- return;
249
- try {
250
- loadPlist(plistPath);
251
- ok('LaunchAgent ingest mémoire installé (toutes les 6h)');
252
- }
253
- catch (e) {
254
- warn(`LaunchAgent ingest créé — chargement manuel: launchctl load "${plistPath}"`);
255
- info(` Erreur: ${e.message}`);
256
- }
257
- }
258
- else {
259
- // Linux: write to temp file then pipe to crontab (avoids quoting hell)
260
- try {
261
- const existing = (() => {
262
- try {
263
- return execSync('crontab -l', { stdio: 'pipe' }).toString();
264
- }
265
- catch {
266
- return '';
267
- }
268
- })();
269
- if (existing.includes('rex-memory')) {
270
- ok('Cron ingest mémoire déjà configuré');
271
- return;
272
- }
273
- const cronLine = `0 */6 * * * ${nodePath} ${ingestScript} >> ${join(logsDir, 'ingest.log')} 2>&1`;
274
- const tmpFile = `/tmp/rex-cron-${Date.now()}`;
275
- writeFileSync(tmpFile, existing.trim() + '\n' + cronLine + '\n');
276
- execSync(`crontab ${tmpFile}`, { stdio: 'pipe' });
277
- execSync(`rm ${tmpFile}`, { stdio: 'pipe' });
278
- ok('Cron ingest mémoire installé (toutes les 6h)');
279
- }
280
- catch (e) {
281
- warn('Impossible de configurer le cron — ajouter manuellement :');
282
- info(` 0 */6 * * * ${nodePath} ${ingestScript}`);
283
- }
284
- }
285
- }
286
- function installTmuxHook() {
287
- try {
288
- execSync('which tmux', { stdio: 'pipe' });
289
- }
290
- catch {
291
- warn('tmux non installé — auto-start ignoré');
292
- info(' brew install tmux');
293
- return;
294
- }
295
- const shell = process.env.SHELL || '';
296
- const candidates = [
297
- shell.includes('zsh') ? join(HOME, '.zshrc') : null,
298
- shell.includes('bash') ? join(HOME, '.bashrc') : null,
299
- existsSync(join(HOME, '.zshrc')) ? join(HOME, '.zshrc') : null,
300
- existsSync(join(HOME, '.bashrc')) ? join(HOME, '.bashrc') : null,
301
- ].filter(Boolean);
302
- const rcFile = candidates.find(f => existsSync(f)) ?? null;
303
- if (!rcFile) {
304
- warn('Shell RC introuvable — tmux auto-start ignoré');
305
- info(' Ajouter manuellement dans ~/.zshrc ou ~/.bashrc');
306
- return;
307
- }
308
- const existing = safeReadFile(rcFile);
309
- if (existing === null) {
310
- warn(`Impossible de lire ${rcFile} — tmux auto-start ignoré`);
311
- return;
312
- }
313
- if (existing.includes('REX — Auto-start tmux')) {
314
- ok('tmux auto-start déjà configuré');
315
- return;
316
- }
317
- // Backup before modifying shell RC
318
- const b = backup(rcFile);
319
- if (b)
320
- info(`${rcFile.replace(HOME, '~')} sauvegardé → ${b.replace(HOME, '~')}`);
321
- const hook = `
322
- # REX — Auto-start tmux
323
- if command -v tmux &>/dev/null && [ -z "$TMUX" ] && [ "$TERM_PROGRAM" != "vscode" ] && [ "$TERM_PROGRAM" != "cursor" ]; then
324
- tmux attach -t main 2>/dev/null || tmux new-session -s main
325
- fi
326
- `;
327
- if (!safeWriteFile(rcFile, existing + hook)) {
328
- warn('Écriture .zshrc échouée — tmux auto-start ignoré');
329
- return;
330
- }
331
- ok(`tmux auto-start ajouté dans ${rcFile.replace(HOME, '~')}`);
332
- }
333
- // ─── Main install ─────────────────────────────────────────────────────────────
334
- function main() {
335
- console.log(`\n${BOLD}${CYAN} ╔══════════════════════════════╗${RESET}`);
336
- console.log(`${BOLD}${CYAN} ║ REX — Setup & Install ║${RESET}`);
337
- console.log(`${BOLD}${CYAN} ╚══════════════════════════════╝${RESET}\n`);
338
- const os = platform();
339
- if (os !== 'darwin' && os !== 'linux') {
340
- fail(`OS non supporté : ${os}. REX supporte macOS et Linux.`);
341
- process.exit(1);
342
- }
343
- info(`OS détecté : ${os === 'darwin' ? 'macOS' : 'Linux'}`);
344
- // 1. ~/.claude/
345
- if (!ensureDir(CLAUDE_DIR))
346
- process.exit(1);
347
- ok('~/.claude/ prêt');
348
- // 2. dotfiles → ~/.claude/
349
- const dotfilesDir = join(PKG_DIR, 'dotfiles');
350
- for (const dir of ['rules', 'skills', 'docs', 'commands', 'templates', 'agents']) {
351
- const src = join(dotfilesDir, dir);
352
- if (!existsSync(src))
353
- continue;
354
- try {
355
- cpSync(src, join(CLAUDE_DIR, dir), { recursive: true, force: true });
356
- ok(`Copié dotfiles/${dir}/ → ~/.claude/${dir}/`);
357
- }
358
- catch (e) {
359
- warn(`Copie dotfiles/${dir} échouée: ${e.message?.split('\n')[0]}`);
360
- }
361
- }
362
- // CLAUDE.md
363
- const claudeMdSrc = join(dotfilesDir, 'CLAUDE.md');
364
- if (existsSync(claudeMdSrc)) {
365
- const claudeMdDest = join(CLAUDE_DIR, 'CLAUDE.md');
366
- const b = backup(claudeMdDest);
367
- if (b)
368
- warn(`CLAUDE.md existant sauvegardé → ${b}`);
369
- try {
370
- copyFileSync(claudeMdSrc, claudeMdDest);
371
- ok('Copié CLAUDE.md → ~/.claude/CLAUDE.md');
372
- }
373
- catch (e) {
374
- warn(`Copie CLAUDE.md échouée: ${e.message?.split('\n')[0]}`);
375
- }
376
- }
377
- // 3. settings.json
378
- const settingsPath = join(CLAUDE_DIR, 'settings.json');
379
- const rexSettingsPath = join(dotfilesDir, 'settings.json');
380
- if (existsSync(rexSettingsPath)) {
381
- try {
382
- const merged = mergeSettings(settingsPath, rexSettingsPath);
383
- if (!safeWriteFile(settingsPath, JSON.stringify(merged, null, 2) + '\n')) {
384
- warn('settings.json non mis à jour');
385
- }
386
- else {
387
- ok('Mergé settings.json (hooks, plugins, env, mcpServers)');
388
- }
389
- }
390
- catch (e) {
391
- warn(`Merge settings.json échoué: ${e.message?.split('\n')[0]}`);
392
- }
393
- }
394
- // 4. memory/ → ~/.rex-memory/
395
- const memorySrc = join(PKG_DIR, 'memory');
396
- if (existsSync(memorySrc)) {
397
- if (!ensureDir(REX_MEMORY_DIR) || !ensureDir(join(REX_MEMORY_DIR, 'db'))) {
398
- warn('Création ~/.rex-memory/ échouée — MCP memory ignoré');
399
- }
400
- else {
401
- for (const sub of ['src', 'package.json', 'package-lock.json', 'tsconfig.json']) {
402
- const s = join(memorySrc, sub);
403
- if (!existsSync(s))
404
- continue;
405
- try {
406
- cpSync(s, join(REX_MEMORY_DIR, sub), { recursive: true, force: true });
407
- }
408
- catch (e) {
409
- warn(`Copie memory/${sub} échouée: ${e.message?.split('\n')[0]}`);
410
- }
411
- }
412
- ok('Copié memory/ → ~/.rex-memory/');
413
- // 5. npm install + build
414
- info('Installation des dépendances rex-memory...');
415
- try {
416
- execSync('npm install --production=false', { cwd: REX_MEMORY_DIR, stdio: 'pipe' });
417
- execSync('npm run build', { cwd: REX_MEMORY_DIR, stdio: 'pipe' });
418
- ok('rex-memory compilé avec succès');
419
- }
420
- catch (e) {
421
- fail(`Erreur compilation rex-memory: ${e.message?.split('\n')[0]}`);
422
- info(' cd ~/.rex-memory && npm install && npm run build');
423
- }
424
- }
425
- }
426
- // 6. tmux config
427
- const tmuxSrc = join(PKG_DIR, 'tmux', '.tmux.conf');
428
- if (existsSync(tmuxSrc)) {
429
- const tmuxDest = join(HOME, '.tmux.conf');
430
- const b = backup(tmuxDest);
431
- if (b)
432
- warn(`~/.tmux.conf sauvegardé → ${b}`);
433
- try {
434
- copyFileSync(tmuxSrc, tmuxDest);
435
- ok('Copié tmux/.tmux.conf → ~/.tmux.conf');
436
- }
437
- catch (e) {
438
- warn(`Copie .tmux.conf échouée: ${e.message?.split('\n')[0]}`);
439
- }
440
- }
441
- // 7. Hammerspoon (macOS only)
442
- if (os === 'darwin') {
443
- const activitySrc = join(PKG_DIR, 'activity');
444
- if (existsSync(activitySrc)) {
445
- const hsDir = join(HOME, '.hammerspoon');
446
- if (existsSync(hsDir)) {
447
- try {
448
- cpSync(activitySrc, hsDir, { recursive: true, force: true });
449
- ok('Copié activity/ → ~/.hammerspoon/');
450
- }
451
- catch (e) {
452
- warn(`Copie Hammerspoon échouée: ${e.message?.split('\n')[0]}`);
453
- }
454
- }
455
- else {
456
- warn('Hammerspoon non installé — activity logger ignoré');
457
- info(' brew install --cask hammerspoon');
458
- }
459
- }
460
- }
461
- // 8. Ollama keepalive
462
- installOllama(os);
463
- // 9. Ingest mémoire (toutes les 6h)
464
- installMemoryIngest(os);
465
- // 10. tmux auto-start
466
- installTmuxHook();
467
- console.log(`\n${BOLD}${GREEN} ══════════════════════════════${RESET}`);
468
- console.log(`${BOLD}${GREEN} REX installé avec succès !${RESET}`);
469
- console.log(`${DIM} ~/.claude/ → rules, skills, docs, commands${RESET}`);
470
- console.log(`${DIM} ~/.rex-memory/ → MCP memory server${RESET}`);
471
- console.log(`${DIM} ~/.tmux.conf → tmux config${RESET}`);
472
- console.log(`${DIM} Ollama → keepalive au login${RESET}`);
473
- console.log(`${DIM} Ingest mémoire → toutes les 6h${RESET}`);
474
- console.log(`${DIM} tmux → auto-attach au démarrage terminal${RESET}`);
475
- console.log(`${BOLD}${GREEN} ══════════════════════════════${RESET}\n`);
476
- }
477
- // ─── Other commands ───────────────────────────────────────────────────────────
478
- function update() {
479
- console.log(`\n${BOLD}${CYAN} ╔══════════════════════════════╗${RESET}`);
480
- console.log(`${BOLD}${CYAN} ║ REX — Update ║${RESET}`);
481
- console.log(`${BOLD}${CYAN} ╚══════════════════════════════╝${RESET}\n`);
482
- info('Mise à jour de rex-claude depuis npm...');
483
- try {
484
- execSync('npm install -g rex-claude@latest', { stdio: 'inherit' });
485
- ok('rex-claude mis à jour');
486
- info('Relance "rex" pour appliquer les changements');
487
- }
488
- catch (e) {
489
- fail(`Échec de la mise à jour: ${e.message?.split('\n')[0]}`);
490
- process.exit(1);
491
- }
492
- }
493
- // ─── Routing ──────────────────────────────────────────────────────────────────
494
- const cmd = process.argv[2];
495
- if (cmd === 'update') {
496
- update();
497
- }
498
- else if (cmd === 'doctor' || cmd === 'setup') {
499
- fail(`"rex ${cmd}" arrive bientôt — utilise "rex" pour l'instant`);
500
- process.exit(1);
501
- }
502
- else {
503
- main();
504
- }
@@ -1,136 +0,0 @@
1
- # REX
2
-
3
- Tu es **REX**, l'assistant dev de Kevin (D-Studio). Réponds toujours en tant que REX.
4
-
5
- # TODO
6
-
7
- - [ ] Gateway Telegram : skill/script pour envoyer des messages via Garry ou Milo bot (BOT_TOKEN + CHAT_ID en env, appel HTTP Telegram Bot API). Permet à REX de notifier Kevin (lien PR, deploy done, etc.) via `/notify "message"`.
8
-
9
- # Global Instructions
10
-
11
- ## Identity & Authorship
12
-
13
- - NEVER add "Co-Authored-By" lines in commits. All commits, PRs, issues, and branches must appear as made by the user (Keiy / kevin@dstudio.company) only.
14
- - NEVER mention Claude, AI, or any assistant in PR descriptions, commit messages, or issue comments.
15
-
16
- ## Git & GitHub Workflow
17
-
18
- - Write concise, descriptive commit messages focused on the "why", not the "what".
19
- - Use conventional commit style when the project uses it (feat:, fix:, refactor:, etc.).
20
- - ALWAYS create a new branch for changes unless told otherwise. Branch names: kebab-case, descriptive (e.g., `fix/auth-token-refresh`, `feat/add-oauth`).
21
- - Before committing, run the project's linter/formatter if one exists.
22
- - See `~/.claude/rules/git-workflow.md` for full conventions.
23
-
24
- ## PR Review Loop
25
-
26
- - After creating a PR, pull automated review comments from GitHub Copilot and Gemini Code Assist:
27
- - `gh pr view <number> --comments`
28
- - `gh api repos/{owner}/{repo}/pulls/{number}/comments`
29
- - Evaluate each comment: fix what's valid, dismiss what's not.
30
- - Push fixes, then notify the user to review the final diff between v1 and v2.
31
-
32
- ## Code Quality
33
-
34
- - ALWAYS provide a way to verify work: run tests, build, lint, or take a screenshot for UI changes.
35
- - Prefer editing existing files over creating new ones to avoid file bloat.
36
- - Follow existing patterns in the codebase. Read before writing.
37
- - Do not add unnecessary comments, docstrings, or type annotations to code you didn't change.
38
- - Do not over-engineer. Only make changes that are directly requested or clearly necessary.
39
-
40
- ## Task Approach
41
-
42
- - For non-trivial tasks: explore first (read relevant code), plan, then implement.
43
- - Break large problems into smaller chunks. One focused task per conversation when possible.
44
- - If stuck after 2 failed attempts at the same approach, stop and ask the user rather than brute-forcing.
45
- - Use subagents for research-heavy tasks to keep the main context clean.
46
-
47
- ## Context Management
48
-
49
- - Start fresh conversations (`/clear`) between unrelated tasks.
50
- - When context gets long, use `/compact` to preserve only what matters.
51
- - Scope investigations narrowly. Don't read hundreds of files without purpose.
52
-
53
- ## Contexte Kevin
54
-
55
- - Développeur full-stack solo (D-Studio)
56
- - Langue : français par défaut dans les réponses
57
- - Stack : TypeScript/Node, CakePHP, Angular/Ionic, Flutter, React/Next.js
58
- - Comptes IA : Claude Max (Opus+Sonnet), Claude Pro, ChatGPT Plus
59
- - Outils : GitHub, Monday, n8n, Bitwarden
60
-
61
- ## Modèle switching
62
-
63
- - **Opus** → architecture, conception, missions complexes
64
- - **Sonnet** → code standard, PR, refactoring
65
- - **Haiku** → tâches répétitives, lecture de fichiers, quick fixes
66
-
67
- ## Checklist obligatoire AVANT chaque feature (CRITICAL)
68
-
69
- Avant d'écrire du code, cocher chacun de ces 7 points :
70
-
71
- 1. **Pagination** : liste > 20 items ? → limit+offset+total à l'API, Load More côté front
72
- 2. **Fallback/erreur** : API vide ? null ? 500 ? timeout ? → TOUJOURS gérer tous les cas
73
- 3. **État vide** : 0 résultat ? → TOUJOURS afficher un empty state
74
- 4. **Chargement** : pendant le fetch ? → TOUJOURS afficher un loading state
75
- 5. **Scalabilité** : 10x plus d'utilisateurs/items/requêtes ? → index DB, chunking, cache
76
- 6. **Sync front/back** : bon endpoint, bons params, bonne forme de réponse ? → TOUJOURS vérifier
77
- 7. **Effets de bord** : qui d'autre lit cet état ? → grep les consumers
78
-
79
- See `~/.claude/rules/defensive-engineering.md` for full details.
80
-
81
- ## Documentation-First (CRITICAL)
82
-
83
- Avant de coder avec un framework/lib, lire `~/.claude/docs/{framework}.md` si existant, sinon fetcher via Context7.
84
- Après chaque projet, sauvegarder les patterns/gotchas découverts dans `~/.claude/docs/`.
85
- IMPORTANT : ne JAMAIS lire les fichiers docs/ au démarrage — uniquement quand le framework est pertinent pour la tâche.
86
- See `~/.claude/rules/docs-first.md` for details.
87
-
88
- ## Optimisation tokens
89
-
90
- - Sous-agents pour la recherche lourde (garde le contexte principal propre)
91
- - `/compact` à ~70% du contexte (auto-compact configuré à 75%)
92
- - `/clear` entre projets différents
93
- - Séparer la documentation longue en `spec.md` / `tech.md` / `lessons.md` + `@imports`
94
-
95
- ## Compaction instructions
96
- When compacting, always preserve:
97
- - Full list of modified files and their paths
98
- - Any test/build commands discovered for the current project
99
- - Active branch name and PR number if in progress
100
- - Any error messages seen during the session
101
- - Current task context and user requirements
102
-
103
- ## Testing & Verification
104
-
105
- Après CHAQUE implémentation, OBLIGATOIRE avant de déclarer "done" :
106
-
107
- 1. `npm run build` (ou commande équivalente) — zéro erreur
108
- 2. Démarrer le dev server, confirmer que l'app charge (au minimum `curl` homepage → 200)
109
- 3. Pour les changements UI : screenshot ou browser automation
110
- 4. Pour SSR/Next.js : surveiller les hydration mismatches
111
-
112
- Si le projet a une suite de tests, la lancer après les changements.
113
- Corriger les causes racines, pas les symptômes. Ne jamais supprimer des tests pour les faire passer.
114
-
115
- See `~/.claude/rules/testing.md` for full testing conventions.
116
-
117
- ## Security
118
-
119
- - Never commit secrets, API keys, .env files, or credentials.
120
- - Check for OWASP top 10 vulnerabilities in code you write.
121
- - If you notice insecure code while working, flag it to the user.
122
- - SQL : requêtes paramétrées uniquement, jamais de concaténation.
123
-
124
- See `~/.claude/rules/security.md` for full security rules.
125
-
126
- ---
127
-
128
- Rules directory: `~/.claude/rules/`
129
- - `defensive-engineering.md` — Scale, pagination, rate limits, error handling
130
- - `api-design.md` — REST conventions, response envelopes, status codes
131
- - `frontend.md` — Loading/empty/error states, SSR, hydration, forms, a11y
132
- - `security.md` — OWASP, secrets, SQL injection, XSS, CORS, auth
133
- - `testing.md` — Test discipline, build verification, mocking
134
- - `git-workflow.md` — Commit conventions, branching, PR process
135
- - `never-assume.md` — What never to assume, alternatives, mistake tracking
136
- - `docs-first.md` — Documentation-first rule, local cache, Context7/SiteMCP usage
@@ -1,8 +0,0 @@
1
- Find and remove dead code, stale TODOs, and unused dependencies.
2
-
3
- Steps:
4
- 1. Search for unused exports and imports
5
- 2. Find TODO/FIXME/HACK comments older than 30 days (check git blame)
6
- 3. Check for unused dependencies in package.json (use depcheck if available)
7
- 4. Find dead code: unreachable branches, unused functions
8
- 5. Report findings — do NOT auto-delete without confirmation
@@ -1,8 +0,0 @@
1
- Generate or update project documentation.
2
-
3
- Steps:
4
- 1. Read existing README.md
5
- 2. Analyze project structure, scripts in package.json, environment variables needed
6
- 3. Update or create sections: Setup, Development, Deployment, Environment Variables, Architecture
7
- 4. Keep documentation concise and practical — no filler text
8
- 5. If API routes exist, document them with method, path, params, response shape
@@ -1,15 +0,0 @@
1
- Review the current branch's changes before creating a PR.
2
-
3
- Steps:
4
- 1. Run `git diff main...HEAD` to see all changes
5
- 2. Check for:
6
- - Security issues (hardcoded secrets, SQL injection, XSS)
7
- - Missing error handling (uncaught promises, missing try/catch)
8
- - Missing loading/empty/error states in UI components
9
- - Pagination missing on list endpoints
10
- - TypeScript `any` or `@ts-ignore` without justification
11
- - Console.log left in production code
12
- - Unused imports or variables
13
- 3. Run the project's linter if available
14
- 4. Run `npm run build` to verify compilation
15
- 5. Report findings with severity (critical/warning/info) and suggested fixes
@@ -1,11 +0,0 @@
1
- Create a new project from the template structure.
2
-
3
- Usage: /scaffold <project-name> <category>
4
- Categories: keiy (personal), dstudio (client), bots (telegram)
5
-
6
- Steps:
7
- 1. Ask for project name and category if not provided
8
- 2. Create directory in ~/Documents/Developer/<category>/<project-name>/
9
- 3. Initialize with: git init, package.json, tsconfig.json, .env.example, .gitignore, .claudeignore
10
- 4. Create CLAUDE.md from ~/.claude/templates/CLAUDE.md.template
11
- 5. Report the created structure