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
@@ -0,0 +1,248 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/init.ts
4
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
5
+ import { join, dirname } from "path";
6
+ import { homedir } from "os";
7
+ import { fileURLToPath } from "url";
8
+ var COLORS = {
9
+ reset: "\x1B[0m",
10
+ green: "\x1B[32m",
11
+ yellow: "\x1B[33m",
12
+ red: "\x1B[31m",
13
+ bold: "\x1B[1m",
14
+ dim: "\x1B[2m",
15
+ cyan: "\x1B[36m"
16
+ };
17
+ function log(icon, msg) {
18
+ console.log(` ${icon} ${msg}`);
19
+ }
20
+ function ok(msg) {
21
+ log(`${COLORS.green}\u2713${COLORS.reset}`, msg);
22
+ }
23
+ function skip(msg) {
24
+ log(`${COLORS.yellow}\u2192${COLORS.reset}`, `${COLORS.dim}${msg}${COLORS.reset}`);
25
+ }
26
+ function info(msg) {
27
+ log(`${COLORS.cyan}\u2139${COLORS.reset}`, msg);
28
+ }
29
+ function readJson(path) {
30
+ try {
31
+ return JSON.parse(readFileSync(path, "utf-8"));
32
+ } catch {
33
+ return null;
34
+ }
35
+ }
36
+ function writeJson(path, data) {
37
+ writeFileSync(path, JSON.stringify(data, null, 2) + "\n");
38
+ }
39
+ function ensureDir(dir) {
40
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
41
+ }
42
+ async function init() {
43
+ const claudeDir = join(homedir(), ".claude");
44
+ const line = "\u2550".repeat(45);
45
+ console.log(`
46
+ ${line}`);
47
+ console.log(`${COLORS.bold} REX INIT \u2014 Setup${COLORS.reset}`);
48
+ console.log(`${line}
49
+ `);
50
+ let memoryServerPath = null;
51
+ {
52
+ const thisDir2 = new URL(".", import.meta.url).pathname;
53
+ const candidates = [
54
+ join(thisDir2, "..", "..", "memory", "src", "server.ts"),
55
+ join(homedir(), ".rex-memory", "src", "server.ts")
56
+ ];
57
+ for (const c of candidates) {
58
+ if (existsSync(c)) {
59
+ memoryServerPath = c;
60
+ break;
61
+ }
62
+ }
63
+ }
64
+ const settingsPath = join(claudeDir, "settings.json");
65
+ ensureDir(claudeDir);
66
+ const settings = readJson(settingsPath) ?? {};
67
+ if (!settings.mcpServers) settings.mcpServers = {};
68
+ if (settings.mcpServers["rex-memory"]) {
69
+ skip("MCP server rex-memory already configured");
70
+ } else if (memoryServerPath) {
71
+ const serverDir = join(memoryServerPath, "..", "..");
72
+ settings.mcpServers["rex-memory"] = {
73
+ command: "npx",
74
+ args: ["tsx", memoryServerPath],
75
+ cwd: serverDir
76
+ };
77
+ writeJson(settingsPath, settings);
78
+ ok("MCP server rex-memory configured");
79
+ } else {
80
+ info("Memory package not found \u2014 install @rex/memory or run from monorepo");
81
+ }
82
+ if (!settings.hooks) settings.hooks = {};
83
+ const hasIngestHook = settings.hooks.SessionEnd?.some?.(
84
+ (h) => h.hooks?.some?.((hh) => hh.command?.includes("rex") && hh.command?.includes("ingest"))
85
+ );
86
+ if (hasIngestHook) {
87
+ skip("Auto-ingest hook (SessionEnd) already configured");
88
+ } else {
89
+ if (!settings.hooks.SessionEnd) settings.hooks.SessionEnd = [];
90
+ settings.hooks.SessionEnd.push({
91
+ hooks: [{
92
+ type: "command",
93
+ command: "npx rex-cli ingest 2>/dev/null &",
94
+ timeout: 5
95
+ }]
96
+ });
97
+ ok("Auto-ingest hook configured (SessionEnd)");
98
+ }
99
+ const hasContextHook = settings.hooks.SessionStart?.some?.(
100
+ (h) => h.hooks?.some?.((hh) => hh.command?.includes("rex-context"))
101
+ );
102
+ if (hasContextHook) {
103
+ skip("Context injection hook (SessionStart) already configured");
104
+ } else {
105
+ const contextScript = join(claudeDir, "rex-context.sh");
106
+ if (!existsSync(contextScript)) {
107
+ writeFileSync(contextScript, `#!/bin/bash
108
+ # REX Context Injection \u2014 runs at session start
109
+ # Outputs relevant memory context to CLAUDE_ENV_FILE
110
+
111
+ if [ -z "$CLAUDE_ENV_FILE" ]; then
112
+ exit 0
113
+ fi
114
+
115
+ # Quick check if rex-memory MCP is available
116
+ if command -v npx &>/dev/null; then
117
+ # Context will be loaded via MCP rex_context tool
118
+ # This hook just ensures the env is ready
119
+ echo "REX_MEMORY_AVAILABLE=true" >> "$CLAUDE_ENV_FILE"
120
+ fi
121
+ `, { mode: 493 });
122
+ }
123
+ if (!settings.hooks.SessionStart) settings.hooks.SessionStart = [];
124
+ settings.hooks.SessionStart.push({
125
+ hooks: [{
126
+ type: "command",
127
+ command: `bash ${contextScript}`,
128
+ timeout: 5
129
+ }]
130
+ });
131
+ ok("Context injection hook configured (SessionStart)");
132
+ }
133
+ const guardsDir = join(claudeDir, "rex-guards");
134
+ ensureDir(guardsDir);
135
+ const thisDir = dirname(fileURLToPath(import.meta.url));
136
+ const srcGuardsDir = join(thisDir, "guards");
137
+ const GUARDS = [
138
+ {
139
+ file: "completion-guard.sh",
140
+ event: "Stop",
141
+ desc: "Completion verifier (prevents 70% problem)",
142
+ matcher: void 0
143
+ },
144
+ {
145
+ file: "dangerous-cmd-guard.sh",
146
+ event: "PreToolUse",
147
+ desc: "Dangerous command blocker",
148
+ matcher: "Bash"
149
+ },
150
+ {
151
+ file: "test-protect-guard.sh",
152
+ event: "PostToolUse",
153
+ desc: "Test assertion protector",
154
+ matcher: "Edit|Write"
155
+ },
156
+ {
157
+ file: "session-summary.sh",
158
+ event: "Stop",
159
+ desc: "Auto session summary",
160
+ matcher: void 0
161
+ },
162
+ {
163
+ file: "ui-checklist-guard.sh",
164
+ event: "PostToolUse",
165
+ desc: "UI states checklist (loading/error/empty)",
166
+ matcher: "Edit|Write"
167
+ },
168
+ {
169
+ file: "scope-guard.sh",
170
+ event: "PostToolUse",
171
+ desc: "Scope creep detector",
172
+ matcher: "Edit|Write"
173
+ }
174
+ ];
175
+ let guardsInstalled = 0;
176
+ for (const guard of GUARDS) {
177
+ const destPath = join(guardsDir, guard.file);
178
+ const srcPath = join(srcGuardsDir, guard.file);
179
+ if (existsSync(srcPath)) {
180
+ writeFileSync(destPath, readFileSync(srcPath, "utf-8"), { mode: 493 });
181
+ } else if (!existsSync(destPath)) {
182
+ continue;
183
+ }
184
+ const event = guard.event;
185
+ if (!settings.hooks[event]) settings.hooks[event] = [];
186
+ const alreadyInstalled = settings.hooks[event].some(
187
+ (h) => h.hooks?.some?.((hh) => hh.command?.includes(guard.file))
188
+ );
189
+ if (!alreadyInstalled) {
190
+ const hookEntry = {
191
+ hooks: [{
192
+ type: "command",
193
+ command: `bash ${destPath}`,
194
+ timeout: 10
195
+ }]
196
+ };
197
+ if (guard.matcher) hookEntry.matcher = guard.matcher;
198
+ settings.hooks[event].push(hookEntry);
199
+ guardsInstalled++;
200
+ }
201
+ }
202
+ if (guardsInstalled > 0) {
203
+ ok(`${guardsInstalled} REX guards installed (completion, safety, UI, scope)`);
204
+ } else {
205
+ skip("All REX guards already installed");
206
+ }
207
+ let ollamaOk = false;
208
+ try {
209
+ const res = await fetch("http://localhost:11434/api/tags");
210
+ ollamaOk = res.ok;
211
+ } catch {
212
+ }
213
+ if (ollamaOk) {
214
+ ok("Ollama running");
215
+ try {
216
+ const res = await fetch("http://localhost:11434/api/tags");
217
+ const data = await res.json();
218
+ const hasNomic = data.models?.some((m) => m.name?.includes("nomic-embed-text"));
219
+ if (hasNomic) {
220
+ ok("nomic-embed-text model available");
221
+ } else {
222
+ info("Pull embedding model: ollama pull nomic-embed-text");
223
+ }
224
+ } catch {
225
+ }
226
+ } else {
227
+ info("Ollama not running \u2014 needed for memory/RAG. Install: https://ollama.ai");
228
+ }
229
+ writeJson(settingsPath, settings);
230
+ console.log(`
231
+ ${COLORS.dim}\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500${COLORS.reset}`);
232
+ console.log(`
233
+ ${COLORS.bold} REX initialized!${COLORS.reset}`);
234
+ console.log(`
235
+ Next steps:`);
236
+ if (!ollamaOk) {
237
+ console.log(` 1. Install Ollama: ${COLORS.cyan}https://ollama.ai${COLORS.reset}`);
238
+ console.log(` 2. Pull model: ${COLORS.cyan}ollama pull nomic-embed-text${COLORS.reset}`);
239
+ console.log(` 3. Ingest history: ${COLORS.cyan}rex ingest${COLORS.reset}`);
240
+ } else {
241
+ console.log(` 1. Ingest session history: ${COLORS.cyan}rex ingest${COLORS.reset}`);
242
+ }
243
+ console.log(` \u2022 Run ${COLORS.cyan}rex doctor${COLORS.reset} to verify setup`);
244
+ console.log();
245
+ }
246
+ export {
247
+ init
248
+ };
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/optimize.ts
4
+ import { readFileSync, existsSync } from "fs";
5
+ import { join } from "path";
6
+ import { homedir } from "os";
7
+ var COLORS = {
8
+ reset: "\x1B[0m",
9
+ green: "\x1B[32m",
10
+ yellow: "\x1B[33m",
11
+ red: "\x1B[31m",
12
+ bold: "\x1B[1m",
13
+ dim: "\x1B[2m",
14
+ cyan: "\x1B[36m"
15
+ };
16
+ var OLLAMA_URL = process.env.OLLAMA_URL || "http://localhost:11434";
17
+ var PREFERRED_MODELS = ["deepseek-r1:8b", "qwen2.5:1.5b", "llama3.2", "mistral"];
18
+ async function detectModel() {
19
+ if (process.env.REX_OPTIMIZE_MODEL) return process.env.REX_OPTIMIZE_MODEL;
20
+ try {
21
+ const res = await fetch(`${OLLAMA_URL}/api/tags`);
22
+ const data = await res.json();
23
+ const available = data.models.map((m) => m.name);
24
+ for (const pref of PREFERRED_MODELS) {
25
+ if (available.some((a) => a.includes(pref.split(":")[0]))) {
26
+ return available.find((a) => a.includes(pref.split(":")[0]));
27
+ }
28
+ }
29
+ return available.find((a) => !a.includes("embed")) || available[0];
30
+ } catch {
31
+ return "llama3.2";
32
+ }
33
+ }
34
+ async function llm(prompt, system, model) {
35
+ const res = await fetch(`${OLLAMA_URL}/api/generate`, {
36
+ method: "POST",
37
+ headers: { "Content-Type": "application/json" },
38
+ body: JSON.stringify({
39
+ model: model || "qwen2.5:1.5b",
40
+ prompt,
41
+ system,
42
+ stream: false
43
+ })
44
+ });
45
+ if (!res.ok) throw new Error(`Ollama generate failed: ${res.status}`);
46
+ const data = await res.json();
47
+ return data.response;
48
+ }
49
+ async function optimize() {
50
+ const line = "\u2550".repeat(45);
51
+ console.log(`
52
+ ${line}`);
53
+ console.log(`${COLORS.bold} REX OPTIMIZE${COLORS.reset}`);
54
+ console.log(`${line}
55
+ `);
56
+ try {
57
+ const res = await fetch(`${OLLAMA_URL}/api/tags`);
58
+ if (!res.ok) throw new Error();
59
+ } catch {
60
+ console.error(`${COLORS.red}Ollama not running.${COLORS.reset} Start it: ollama serve`);
61
+ process.exit(1);
62
+ }
63
+ const cwd = process.cwd();
64
+ const projectClaudeMd = join(cwd, "CLAUDE.md");
65
+ const globalClaudeMd = join(homedir(), ".claude", "CLAUDE.md");
66
+ const target = existsSync(projectClaudeMd) ? projectClaudeMd : globalClaudeMd;
67
+ if (!existsSync(target)) {
68
+ console.error(`${COLORS.red}No CLAUDE.md found.${COLORS.reset}`);
69
+ process.exit(1);
70
+ }
71
+ const content = readFileSync(target, "utf-8");
72
+ const lines = content.split("\n").length;
73
+ const chars = content.length;
74
+ const tokens = Math.ceil(chars / 4);
75
+ console.log(` ${COLORS.cyan}Target:${COLORS.reset} ${target}`);
76
+ console.log(` ${COLORS.cyan}Size:${COLORS.reset} ${lines} lines, ~${tokens} tokens`);
77
+ console.log();
78
+ const model = await detectModel();
79
+ console.log(` ${COLORS.dim}Analyzing with ${model}...${COLORS.reset}`);
80
+ const analysis = await llm(
81
+ `Analyze this CLAUDE.md file and provide specific suggestions to reduce its token count while keeping all important instructions. Focus on:
82
+ 1. Redundant or duplicate instructions
83
+ 2. Overly verbose sections that could be shortened
84
+ 3. Content that could be moved to separate files and @imported
85
+ 4. Dead or outdated references
86
+
87
+ CLAUDE.md content:
88
+ ---
89
+ ${content.slice(0, 6e3)}
90
+ ---
91
+
92
+ Provide a concise analysis with specific, actionable suggestions. Format each suggestion as:
93
+ - [SECTION] What to change and why (estimated savings: N tokens)`,
94
+ "You are a technical editor that optimizes AI instruction files. Be direct and specific. Output only the analysis, no preamble.",
95
+ model
96
+ );
97
+ console.log(`
98
+ ${COLORS.bold} Analysis:${COLORS.reset}
99
+ `);
100
+ for (const line2 of analysis.split("\n")) {
101
+ console.log(` ${line2}`);
102
+ }
103
+ console.log(`
104
+ ${COLORS.dim}\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500${COLORS.reset}`);
105
+ console.log(`
106
+ ${COLORS.dim}Tip: Run ${COLORS.cyan}rex optimize --apply${COLORS.reset}${COLORS.dim} to auto-apply suggestions${COLORS.reset}`);
107
+ console.log();
108
+ }
109
+ export {
110
+ optimize
111
+ };
package/package.json CHANGED
@@ -1,39 +1,43 @@
1
1
  {
2
2
  "name": "rex-claude",
3
- "version": "1.1.7",
4
- "description": "REX Config unifiée + MCP memory server + activity logger pour Claude Code",
3
+ "version": "2.0.0",
4
+ "description": "Claude Code sous steroides guards, health checks, memory RAG",
5
5
  "type": "module",
6
6
  "bin": {
7
- "rex": "dist/cli.js"
7
+ "rex": "./dist/index.js"
8
8
  },
9
9
  "files": [
10
- "dist/",
11
- "dotfiles/",
12
- "memory/src/",
13
- "memory/package.json",
14
- "memory/package-lock.json",
15
- "memory/tsconfig.json",
16
- "activity/",
17
- "tmux/"
10
+ "dist"
18
11
  ],
19
12
  "scripts": {
20
- "build": "tsc",
21
- "prepublishOnly": "npm run build"
22
- },
23
- "publishConfig": {
24
- "access": "public"
13
+ "build": "tsup",
14
+ "dev": "tsup --watch",
15
+ "postinstall": "node dist/index.js init 2>/dev/null || true"
25
16
  },
26
17
  "keywords": [
27
- "claude-code",
28
18
  "claude",
29
- "mcp",
30
- "dev-tools",
31
- "dotfiles"
19
+ "claude-code",
20
+ "llm",
21
+ "developer-tools",
22
+ "productivity",
23
+ "ai-assistant",
24
+ "guards",
25
+ "hooks"
32
26
  ],
33
27
  "author": "Kevin <kevin@dstudio.company>",
34
28
  "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/Keiy78120/rex"
32
+ },
33
+ "homepage": "https://github.com/Keiy78120/rex#readme",
34
+ "engines": {
35
+ "node": ">=20"
36
+ },
35
37
  "devDependencies": {
36
- "@types/node": "^25.3.3",
37
- "typescript": "^5.7.0"
38
+ "@rex/core": "workspace:*",
39
+ "tsup": "^8.0.0",
40
+ "typescript": "^5.7.0",
41
+ "@types/node": "^22.0.0"
38
42
  }
39
43
  }
package/README.md DELETED
@@ -1,163 +0,0 @@
1
- # REX — Senior Dev Companion
2
-
3
- Config unifiée Claude Code + MCP memory server + activity logger pour Kevin (D-Studio).
4
-
5
- ## Architecture
6
-
7
- ```
8
- rex/
9
- ├── dotfiles/ # Claude Code config (symlinked → ~/.claude/)
10
- │ ├── CLAUDE.md # Instructions globales REX
11
- │ ├── settings.json # MCP servers, hooks, plugins
12
- │ ├── commands/ # Slash commands custom
13
- │ ├── rules/ # Règles auto-chargées au boot (7 fichiers)
14
- │ ├── skills/ # Skills on-demand (8 skills)
15
- │ ├── agents/ # Vide — migré vers skills
16
- │ ├── docs/ # Cache docs frameworks (chargé on-demand)
17
- │ └── templates/ # Templates de projets
18
- ├── memory/ # MCP Server REX-Memory
19
- │ ├── src/
20
- │ │ ├── server.ts # 3 tools MCP : rex_search, rex_learn, rex_context
21
- │ │ ├── ingest.ts # Parse sessions JSONL → SQLite + embeddings
22
- │ │ ├── embed.ts # Embeddings via Ollama (qwen3-embedding:4b)
23
- │ │ └── search.ts # Recherche sémantique sqlite-vec
24
- │ ├── db/ # SQLite DB (gitignored)
25
- │ ├── package.json
26
- │ └── tsconfig.json
27
- ├── activity/ # Hammerspoon activity logger
28
- │ ├── init.lua # Log app switches → JSONL
29
- │ └── config.lua # Config (chemin de log, intervalle)
30
- ├── install.sh # Setup complet en 1 commande
31
- ├── package.json
32
- └── .gitignore
33
- ```
34
-
35
- ## Installation
36
-
37
- ```bash
38
- cd ~/Documents/Developer/_config/rex
39
- ./install.sh
40
- ```
41
-
42
- Le script :
43
- 1. Crée les symlinks `dotfiles/*` → `~/.claude/`
44
- 2. `npm install` dans memory/
45
- 3. Build le MCP server (`npm run build`)
46
- 4. Copie la config Hammerspoon
47
- 5. Enregistre le MCP server dans `~/.claude/settings.json`
48
-
49
- ## MCP Server — REX Memory
50
-
51
- ### Tools disponibles
52
-
53
- | Tool | Usage |
54
- |------|-------|
55
- | `rex_search(query)` | Recherche sémantique dans les sessions passées et faits mémorisés |
56
- | `rex_learn(fact, category)` | Mémorise un pattern, debug insight, ou préférence |
57
- | `rex_context(project_path)` | Retourne le contexte pertinent pour le projet courant |
58
-
59
- ### Stack technique
60
-
61
- - **DB** : SQLite + [sqlite-vec](https://github.com/asg017/sqlite-vec) pour la recherche vectorielle
62
- - **Embeddings** : Ollama local avec `qwen3-embedding:4b` (2560 dimensions)
63
- - **Ingestion** : parse les JSONL de `~/.claude/projects/`, extrait messages + tool_use + metadata
64
- - **Fix notable** : `CAST(? AS INTEGER)` pour contourner un bug sqlite-vec avec les BigInt rowid
65
-
66
- ### Ingestion manuelle
67
-
68
- ```bash
69
- cd memory && npm run ingest
70
- ```
71
-
72
- ### Ingestion automatique
73
-
74
- Un LaunchAgent macOS tourne toutes les heures :
75
- - Fichier : `~/Library/LaunchAgents/com.dstudio.rex-ingest.plist`
76
- - Logs : `/tmp/rex-ingest.log`
77
- - RunAtLoad : oui (se lance au démarrage du Mac)
78
-
79
- ```bash
80
- # Vérifier le status
81
- launchctl list | grep rex
82
-
83
- # Forcer une exécution
84
- launchctl kickstart gui/$(id -u)/com.dstudio.rex-ingest
85
-
86
- # Voir les logs
87
- tail -f /tmp/rex-ingest.log
88
- ```
89
-
90
- ## Activity Logger (Hammerspoon)
91
-
92
- Log les changements d'app active en JSONL :
93
- - **Quoi** : app name, durée, timestamps
94
- - **Pas de keylogger** (privacy)
95
- - **Fichier** : `rex/activity/activity.jsonl`
96
- - **Chargé via** : `~/.hammerspoon/init.lua` → `rex/activity/init.lua`
97
-
98
- ## Skills (chargés on-demand)
99
-
100
- | Skill | Description |
101
- |-------|-------------|
102
- | `rex-boot` | Briefing de session — auto-détecte projet, git, PRs, demande l'objectif |
103
- | `context-loader` | Charge docs + CLAUDE.md + mémoire REX avant de bosser |
104
- | `debug-assist` | Debugging systématique — parse erreur, cherche dans mémoire, root cause |
105
- | `token-guard` | Audit du contexte — fichiers redondants, sorties trop longues, suggestions /compact |
106
- | `project-init` | Init un nouveau projet avec CLAUDE.md, git, docs cache |
107
- | `build-validate` | Vérifie build, lint, tests, dev server — reporte sans modifier |
108
- | `code-review` | Review de code : logique, sécu, perf, TypeScript strictness |
109
- | `one-shot` | Génère un projet complet Next.js + Shadcn en une passe |
110
-
111
- ## Rules (chargées au boot, ~370 lignes total)
112
-
113
- | Fichier | Contenu |
114
- |---------|---------|
115
- | `defensive-engineering.md` | Scale, pagination, rate limits, error handling |
116
- | `api-design.md` | REST conventions, response envelopes, status codes |
117
- | `frontend.md` | Loading/empty/error states, SSR, hydration, forms, a11y |
118
- | `security.md` | OWASP, secrets, SQL injection, XSS, CORS, auth |
119
- | `testing.md` | Test discipline, build verification, mocking |
120
- | `git-workflow.md` | Commit conventions, branching, PR process |
121
- | `never-assume.md` | Règles anti-erreurs, alternatives obligatoires |
122
- | `docs-first.md` | Documentation-first, cache local, Context7 |
123
-
124
- ## Docs Cache (~/.claude/docs/)
125
-
126
- Fichiers de patterns/gotchas pré-chargés (lus on-demand uniquement) :
127
-
128
- - `nextjs.md` — App Router, SSR, caching, middleware
129
- - `react.md` — Hooks, patterns, performance
130
- - `cloudflare.md` — Workers, D1, KV, limites
131
- - `telegram-bot.md` — Bot API, rate limits, webhooks
132
- - `tailwind.md` — Classes utilitaires, responsive, dark mode
133
-
134
- ## Plugins Claude Code
135
-
136
- | Plugin | Status | Notes |
137
- |--------|--------|-------|
138
- | Playwright | Actif | Browser automation, tests E2E |
139
- | Frontend Design | Actif | UI/design quality |
140
- | Figma | **Désactivé** | Réactiver manuellement quand besoin (auth pénible) |
141
- | Superpowers | Actif | Capacités étendues |
142
- | Trail of Bits (x4) | Actif | Sécurité : static analysis, semgrep, audit, insecure defaults |
143
- | Vercel | Désactivé | Pas utilisé |
144
- | Ralph Loop | Désactivé | Pas utilisé |
145
-
146
- Pour activer/désactiver : éditer `~/.claude/settings.json` > `enabledPlugins`.
147
-
148
- ## Services auto-start au boot Mac
149
-
150
- | Service | Méthode | Vérification |
151
- |---------|---------|-------------|
152
- | Ollama | Login Items macOS | `pgrep ollama` |
153
- | Hammerspoon | Login Items macOS | Icône menubar |
154
- | REX Ingest | LaunchAgent (hourly) | `launchctl list \| grep rex` |
155
- | MCP Server | Claude Code (auto) | Démarre avec Claude |
156
-
157
- ## Historique des décisions
158
-
159
- 1. **agents → skills** : les agents se chargent entièrement au boot (~500 tokens chacun), les skills ne chargent que les métadonnées (~700 tokens pour les 8). Économie significative.
160
- 2. **docs on-demand** : les fichiers `~/.claude/docs/` ne sont jamais lus au boot, seulement quand le framework est pertinent pour la tâche en cours.
161
- 3. **sqlite-vec CAST workaround** : le rowid en BigInt de `better-sqlite3` est rejeté par sqlite-vec. Fix : `CAST(? AS INTEGER)` dans le SQL.
162
- 4. **Figma désactivé par défaut** : re-auth fréquente, activé manuellement quand besoin.
163
- 5. **qwen3-embedding:4b** : modèle d'embedding local via Ollama, 2560 dimensions, déjà installé.