mode Orchestrateur multi-sites : 1 session Claude Code sur M3U96a qui coordonne des modifs sur les 13 apps via SSH, avec contexte complet (workspace ~/ka-orchestrator + CLAUDE.md table app→nœud→dir, ORCH_SYSTEM)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
7 changed files +43 −5
modified
data/audit.jsonl
+7 −0
@@ -792,3 +792,10 @@ | ||
| 792 | 792 | {"ts":"2026-08-21T16:40:17.848Z","kind":"result","chatId":"216855a50e0cb8e8","subtype":"success","cost":0.317378,"duration_ms":9175,"turns":2} |
| 793 | 793 | {"ts":"2026-08-21T16:40:19.058Z","kind":"result","chatId":"7013b58a64caa8c7","subtype":"success","cost":0.3702575,"duration_ms":10406,"turns":2} |
| 794 | 794 | {"ts":"2026-08-21T16:40:20.540Z","kind":"result","chatId":"05e031db939b2426","subtype":"success","cost":0.3163415,"duration_ms":11917,"turns":2} |
| 795 | +{"ts":"2026-08-21T16:48:36.872Z","kind":"prompt","chatId":"747405bac0551176","project":"ORCH","node":"M3U96a","dir":"/Users/simon-pierreboucher/ka-orchestrator","model":"fable","permMode":"bypass","prompt":"Tâche multi-sites (LECTURE SEULE, ne modifie rien): donne le dernier commit (hash court + sujet) de lou-ka, immo-ka et vrai-prix. Rappelle-toi que lou-ka et immo-ka sont sur d autres nœuds (SSH) et vrai-prix est local sur M3U96a. Présente un petit tableau."} | |
| 796 | +{"ts":"2026-08-21T16:48:43.698Z","kind":"tool_use","chatId":"747405bac0551176","tool":"Bash","input":"{\"command\":\"ssh M3U96b 'cd ~/apps/lou-ka && git log -1 --format=\\\"%h %s\\\"'\",\"description\":\"Dernier commit de lou-ka sur M3U96b\"}"} | |
| 797 | +{"ts":"2026-08-21T16:48:44.395Z","kind":"tool_use","chatId":"747405bac0551176","tool":"Bash","input":"{\"command\":\"ssh M4M64a 'cd ~/apps/immo-ka && git log -1 --format=\\\"%h %s\\\"'\",\"description\":\"Dernier commit d'immo-ka sur M4M64a\"}"} | |
| 798 | +{"ts":"2026-08-21T16:48:45.540Z","kind":"tool_use","chatId":"747405bac0551176","tool":"Bash","input":"{\"command\":\"cd ~/apps/vrai-prix && git log -1 --format=\\\"%h %s\\\"\",\"description\":\"Dernier commit de vrai-prix en local\"}"} | |
| 799 | +{"ts":"2026-08-21T16:48:51.697Z","kind":"result","chatId":"747405bac0551176","subtype":"success","cost":0.36772950000000004,"duration_ms":14568,"turns":4} | |
| 800 | +{"ts":"2026-08-21T16:49:00.431Z","kind":"prompt","chatId":"747405bac0551176","project":"ORCH","node":"M3U96a","dir":"/Users/simon-pierreboucher/ka-orchestrator","model":"fable","permMode":"bypass","prompt":"Parmi les 3 apps que tu viens de vérifier, laquelle a le commit le plus ancien ? Réponds en une phrase, sans relancer de commande."} | |
| 801 | +{"ts":"2026-08-21T16:49:12.651Z","kind":"result","chatId":"747405bac0551176","subtype":"success","cost":0.0698985,"duration_ms":11945,"turns":1} | |
modified
data/backend.log
+1 −0
@@ -20,3 +20,4 @@ admin-ka v2 sur port 3300 (dual-stack) | ||
| 20 | 20 | admin-ka v2 sur port 3300 (dual-stack) |
| 21 | 21 | admin-ka v2 sur port 3300 (dual-stack) |
| 22 | 22 | admin-ka v2 sur port 3300 (dual-stack) |
| 23 | +admin-ka v2 sur port 3300 (dual-stack) | |
modified
data/chats.json
+2 −1
@@ -81,6 +81,7 @@ | ||
| 81 | 81 | "batch": "21 août, 12 h 40", |
| 82 | 82 | "created": 1787330408310, |
| 83 | 83 | "updated": 1787330421004, |
| 84 | − "lastModel": "claude-fable-5" | |
| 84 | + "lastModel": "claude-fable-5", | |
| 85 | + "autoAllowAll": false | |
| 85 | 86 | } |
| 86 | 87 | ] |
| \ No newline at end of file | ||
modified
data/eco.sqlite
+0 −0
Binary file not shown.
modified
data/ngrok.log
+12 −0
@@ -1211,3 +1211,15 @@ t=2026-08-21T12:40:39-0400 lvl=info msg="join connections" obj=join id=0c4e1dcdc | ||
| 1211 | 1211 | t=2026-08-21T12:40:39-0400 lvl=info msg="join connections" obj=join id=0489655aa9c3 l=[::1]:3300 r=[2605:b100:149:21ca:b509:761e:2e8d:6cfc]:63948 |
| 1212 | 1212 | t=2026-08-21T12:40:39-0400 lvl=info msg="join connections" obj=join id=a40da0d08b5d l=[::1]:3300 r=[2605:b100:149:21ca:b509:761e:2e8d:6cfc]:63949 |
| 1213 | 1213 | t=2026-08-21T12:40:40-0400 lvl=info msg="join connections" obj=join id=9243997478cc l=[::1]:3300 r=[2605:b100:149:21ca:b509:761e:2e8d:6cfc]:63950 |
| 1214 | +t=2026-08-21T12:43:13-0400 lvl=info msg="join connections" obj=join id=ba5b5dca466d l=[::1]:3300 r=[2605:b100:149:21ca:b509:761e:2e8d:6cfc]:64027 | |
| 1215 | +t=2026-08-21T12:43:14-0400 lvl=info msg="join connections" obj=join id=780680b5c1a0 l=[::1]:3300 r=[2605:b100:149:21ca:b509:761e:2e8d:6cfc]:64028 | |
| 1216 | +t=2026-08-21T12:43:14-0400 lvl=info msg="join connections" obj=join id=b2fda2bd99f6 l=[::1]:3300 r=[2605:b100:149:21ca:b509:761e:2e8d:6cfc]:64029 | |
| 1217 | +t=2026-08-21T12:43:14-0400 lvl=info msg="join connections" obj=join id=b239b3bc1667 l=[::1]:3300 r=[2605:b100:149:21ca:b509:761e:2e8d:6cfc]:64030 | |
| 1218 | +t=2026-08-21T12:43:14-0400 lvl=info msg="join connections" obj=join id=a25b7a02d5be l=[::1]:3300 r=[2605:b100:149:21ca:b509:761e:2e8d:6cfc]:64031 | |
| 1219 | +t=2026-08-21T12:46:22-0400 lvl=info msg="join connections" obj=join id=bb1fb1d5a4fb l=[::1]:3300 r=[2605:b100:149:21ca:d0a1:55e:1003:f5f2]:60975 | |
| 1220 | +t=2026-08-21T12:46:23-0400 lvl=info msg="join connections" obj=join id=8fe3211c4b3c l=[::1]:3300 r=[2605:b100:149:21ca:d0a1:55e:1003:f5f2]:60979 | |
| 1221 | +t=2026-08-21T12:46:23-0400 lvl=info msg="join connections" obj=join id=88a3612eacb6 l=[::1]:3300 r=[2605:b100:149:21ca:d0a1:55e:1003:f5f2]:60981 | |
| 1222 | +t=2026-08-21T12:48:30-0400 lvl=info msg="join connections" obj=join id=83c9dc233bb9 l=[::1]:3300 r=[2605:b100:149:21ca:b509:761e:2e8d:6cfc]:64149 | |
| 1223 | +t=2026-08-21T12:48:36-0400 lvl=info msg="join connections" obj=join id=3b11b9c96058 l=[::1]:3300 r=76.70.60.50:58039 | |
| 1224 | +t=2026-08-21T12:49:00-0400 lvl=info msg="join connections" obj=join id=0708eaa6cb08 l=[::1]:3300 r=76.70.60.50:58239 | |
| 1225 | +t=2026-08-21T12:49:13-0400 lvl=info msg="join connections" obj=join id=48c8268e85e6 l=[::1]:3300 r=[2605:b100:149:21ca:b509:761e:2e8d:6cfc]:64166 | |
modified
public/app.js
+6 −1
@@ -1249,7 +1249,12 @@ | ||
| 1249 | 1249 | projectSel.appendChild(o); |
| 1250 | 1250 | } |
| 1251 | 1251 | if (settings.projectId) projectSel.value = settings.projectId; |
| 1252 | − projectSel.onchange = () => { settings.projectId = projectSel.value; saveStore(); refreshChips(); if (projectSel.value === 'ALL') inputEl.placeholder = 'Prompt pour TOUTES les apps KA…'; else inputEl.placeholder = 'Demander à Claude Code…'; }; | |
| 1252 | + projectSel.onchange = () => { | |
| 1253 | + settings.projectId = projectSel.value; saveStore(); refreshChips(); | |
| 1254 | + inputEl.placeholder = projectSel.value === 'ALL' ? 'Prompt diffusé à TOUTES les apps KA…' | |
| 1255 | + : projectSel.value === 'ORCH' ? 'Tâche multi-sites — 1 session qui coordonne tout…' | |
| 1256 | + : 'Demander à Claude Code…'; | |
| 1257 | + }; | |
| 1253 | 1258 | refreshChips(); |
| 1254 | 1259 | refreshSettingsView(); |
| 1255 | 1260 | // reprise automatique : on rouvre la dernière conversation (historique + |
modified
server/server.js
+15 −3
@@ -218,10 +218,19 @@ const PROJECTS = [ | ||
| 218 | 218 | { id: 'job-ka@M3U96a', name: 'Job·Ka', node: null, dir: path.join(HOME, 'apps', 'job-ka') }, |
| 219 | 219 | { id: 'trouve-ka@M2M32', name: 'Trouve·Ka', node: 'M2M32', dir: '~/trouve-ka' }, |
| 220 | 220 | ]; |
| 221 | +// Orchestrateur : une seule session sur M3U96a qui pilote les 13 apps via SSH, | |
| 222 | +// en gardant le contexte complet de la tâche. | |
| 223 | +const ORCH_PROJECT = { id: 'ORCH', name: '🎛️ Orchestrateur multi-sites', node: null, dir: path.join(HOME, 'ka-orchestrator') }; | |
| 221 | 224 | function listProjects() { |
| 222 | − return PROJECTS.map(p => ({ id: p.id, name: p.name, node: p.node || SELF_NODE, dir: p.dir })); | |
| 225 | + return [ | |
| 226 | + { id: ORCH_PROJECT.id, name: ORCH_PROJECT.name, node: SELF_NODE, dir: ORCH_PROJECT.dir }, | |
| 227 | + ...PROJECTS.map(p => ({ id: p.id, name: p.name, node: p.node || SELF_NODE, dir: p.dir })), | |
| 228 | + ]; | |
| 229 | +} | |
| 230 | +function findProject(id) { | |
| 231 | + if (id === 'ORCH') return ORCH_PROJECT; | |
| 232 | + return PROJECTS.find(p => p.id === id) || null; | |
| 223 | 233 | } |
| 224 | −function findProject(id) { return PROJECTS.find(p => p.id === id) || null; } | |
| 225 | 234 | |
| 226 | 235 | // ---------- exécution Claude Code ---------- |
| 227 | 236 | const MODELS = ['fable', 'opus', 'sonnet', 'haiku']; |
@@ -233,6 +242,8 @@ const ALLOWED_READONLY = 'Read,Glob,Grep,LS,WebFetch,WebSearch,TodoWrite,Noteboo | ||
| 233 | 242 | |
| 234 | 243 | const SYSTEM_APPEND = `RÈGLE OBLIGATOIRE (console administration-ka) : si tu as modifié des fichiers du projet pendant ce tour, tu DOIS avant de conclure : (1) rebuild si le projet a une étape de build ; (2) redéployer — pm2 restart <app> (ou le mécanisme en place) — et VÉRIFIER que l'app répond (healthcheck/port/site) ; (3) committer et pousser : git add + git commit + git push origin main — le remote origin est spbgit (git perso git.spboucher.ai), PAS GitHub. Ne termine jamais en laissant des modifications non commitées ou non redéployées. Si aucun fichier n'a été modifié, ignore cette règle.`; |
| 235 | 244 | |
| 245 | +const ORCH_SYSTEM = `Tu es la session ORCHESTRATRICE multi-sites du Groupe KA, lancée sur M3U96a. La tâche demandée peut concerner PLUSIEURS apps KA à la fois — tu gardes le contexte complet du début à la fin. Le fichier CLAUDE.md de ton répertoire (~/ka-orchestrator) contient la table app→nœud→répertoire de prod et la méthode : lis-le et suis-le. Tu modifies les repos de PROD à distance via SSH (ssh <nœud> 'cd <dir> && …') ; les apps sur M3U96a se font en local. Planifie avec TodoWrite, explore le pattern commun avant d'agir, applique app par app, et pour CHAQUE app modifiée : build si besoin + pm2 restart + healthcheck + git add/commit/push origin main (spbgit). Termine par un bilan (apps modifiées, commits, restes). Ne laisse aucune app en état incohérent.`; | |
| 246 | + | |
| 236 | 247 | const shq = (s) => `'` + String(s).replace(/'/g, `'\\''`) + `'`; |
| 237 | 248 | |
| 238 | 249 | // chatId -> { proc, permToken, stderr, remote } |
@@ -280,8 +291,9 @@ function startClaude(chat, prompt) { | ||
| 280 | 291 | const permMode = PERM_MODES.includes(chat.permMode) ? chat.permMode : 'default'; |
| 281 | 292 | let proc; |
| 282 | 293 | |
| 294 | + const sysAppend = chat.projectId === 'ORCH' ? ORCH_SYSTEM : SYSTEM_APPEND; | |
| 283 | 295 | const baseArgs = ['-p', '--output-format', 'stream-json', '--verbose', '--include-partial-messages', |
| 284 | − '--model', CLI_MODEL[model], '--append-system-prompt', SYSTEM_APPEND]; | |
| 296 | + '--model', CLI_MODEL[model], '--append-system-prompt', sysAppend]; | |
| 285 | 297 | if (chat.claudeSessionId) baseArgs.push('--resume', chat.claudeSessionId); |
| 286 | 298 | |
| 287 | 299 | if (!chat.node) { |
| 288 | 300 | |