@liriraid/agentflow-ai 1.0.10
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.
- package/LICENSE +21 -0
- package/README.md +79 -0
- package/bin/agentflow.mjs +332 -0
- package/orchestrator.js +1585 -0
- package/package.json +64 -0
- package/scripts/scaffold-agent-configs.mjs +100 -0
- package/scripts/scaffold-openspec-change.mjs +84 -0
- package/scripts/update-skill-registry.mjs +174 -0
- package/src/ink/app.mjs +240 -0
- package/src/ink/index.mjs +400 -0
- package/templates/en/.atl/skill-registry.md +27 -0
- package/templates/en/.claude/README.md +7 -0
- package/templates/en/.claude/skills/orchestrator-apply/SKILL.md +31 -0
- package/templates/en/.claude/skills/orchestrator-archive/SKILL.md +26 -0
- package/templates/en/.claude/skills/orchestrator-design/SKILL.md +27 -0
- package/templates/en/.claude/skills/orchestrator-explore/SKILL.md +29 -0
- package/templates/en/.claude/skills/orchestrator-init/SKILL.md +32 -0
- package/templates/en/.claude/skills/orchestrator-memory/SKILL.md +26 -0
- package/templates/en/.claude/skills/orchestrator-openspec/SKILL.md +35 -0
- package/templates/en/.claude/skills/orchestrator-propose/SKILL.md +26 -0
- package/templates/en/.claude/skills/orchestrator-queue-planning/SKILL.md +31 -0
- package/templates/en/.claude/skills/orchestrator-spec/SKILL.md +27 -0
- package/templates/en/.claude/skills/orchestrator-tasks/SKILL.md +27 -0
- package/templates/en/.claude/skills/orchestrator-verify/SKILL.md +27 -0
- package/templates/en/.codex/README.md +7 -0
- package/templates/en/.opencode/README.md +7 -0
- package/templates/en/AGENT-CONFIG.md +75 -0
- package/templates/en/CLAUDE.md +91 -0
- package/templates/en/ENGRAM.md +50 -0
- package/templates/en/ORCHESTRATOR.md +192 -0
- package/templates/en/PROJECT.md +70 -0
- package/templates/en/QUEUE.md +17 -0
- package/templates/en/README.md +188 -0
- package/templates/en/agents/ABACUS.md +36 -0
- package/templates/en/agents/BACKEND.md +37 -0
- package/templates/en/agents/CODEX.md +45 -0
- package/templates/en/agents/CURSOR.md +37 -0
- package/templates/en/agents/FRONTEND.md +36 -0
- package/templates/en/agents/GEMINI.md +37 -0
- package/templates/en/agents/OPENCODE.md +41 -0
- package/templates/en/docs/README.md +14 -0
- package/templates/en/docs/agents.md +33 -0
- package/templates/en/docs/architecture.md +43 -0
- package/templates/en/docs/components.md +14 -0
- package/templates/en/docs/engram.md +16 -0
- package/templates/en/docs/openspec.md +32 -0
- package/templates/en/docs/usage.md +66 -0
- package/templates/en/openspec/FLOW.md +24 -0
- package/templates/en/openspec/README.md +29 -0
- package/templates/en/openspec/changes/.gitkeep +1 -0
- package/templates/en/openspec/changes/archive/.gitkeep +1 -0
- package/templates/en/openspec/specs/.gitkeep +1 -0
- package/templates/en/openspec/templates/archive-report.md +21 -0
- package/templates/en/openspec/templates/change-metadata.yaml +9 -0
- package/templates/en/openspec/templates/design.md +26 -0
- package/templates/en/openspec/templates/proposal.md +27 -0
- package/templates/en/openspec/templates/spec.md +18 -0
- package/templates/en/openspec/templates/tasks.md +14 -0
- package/templates/en/openspec/templates/verify-report.md +21 -0
- package/templates/en/orchestrator.config.json +99 -0
- package/templates/es/.atl/skill-registry.md +133 -0
- package/templates/es/.claude/README.md +7 -0
- package/templates/es/.claude/skills/orchestrator-apply/SKILL.md +32 -0
- package/templates/es/.claude/skills/orchestrator-archive/SKILL.md +28 -0
- package/templates/es/.claude/skills/orchestrator-design/SKILL.md +32 -0
- package/templates/es/.claude/skills/orchestrator-explore/SKILL.md +31 -0
- package/templates/es/.claude/skills/orchestrator-init/SKILL.md +32 -0
- package/templates/es/.claude/skills/orchestrator-memory/SKILL.md +31 -0
- package/templates/es/.claude/skills/orchestrator-openspec/SKILL.md +55 -0
- package/templates/es/.claude/skills/orchestrator-propose/SKILL.md +33 -0
- package/templates/es/.claude/skills/orchestrator-queue-planning/SKILL.md +35 -0
- package/templates/es/.claude/skills/orchestrator-spec/SKILL.md +28 -0
- package/templates/es/.claude/skills/orchestrator-tasks/SKILL.md +32 -0
- package/templates/es/.claude/skills/orchestrator-verify/SKILL.md +31 -0
- package/templates/es/.codex/README.md +7 -0
- package/templates/es/.opencode/README.md +7 -0
- package/templates/es/AGENT-CONFIG.md +83 -0
- package/templates/es/CLAUDE.md +136 -0
- package/templates/es/ENGRAM.md +70 -0
- package/templates/es/ORCHESTRATOR.md +199 -0
- package/templates/es/PROJECT.md +237 -0
- package/templates/es/QUEUE.md +17 -0
- package/templates/es/README.md +568 -0
- package/templates/es/agents/ABACUS.md +25 -0
- package/templates/es/agents/BACKEND.md +28 -0
- package/templates/es/agents/CODEX.md +37 -0
- package/templates/es/agents/CURSOR.md +27 -0
- package/templates/es/agents/FRONTEND.md +29 -0
- package/templates/es/agents/GEMINI.md +26 -0
- package/templates/es/agents/OPENCODE.md +32 -0
- package/templates/es/docs/README.md +12 -0
- package/templates/es/docs/agents.md +57 -0
- package/templates/es/docs/architecture.md +41 -0
- package/templates/es/docs/components.md +33 -0
- package/templates/es/docs/engram.md +30 -0
- package/templates/es/docs/openspec.md +34 -0
- package/templates/es/docs/usage.md +54 -0
- package/templates/es/openspec/FLOW.md +139 -0
- package/templates/es/openspec/README.md +77 -0
- package/templates/es/openspec/changes/.gitkeep +1 -0
- package/templates/es/openspec/changes/archive/.gitkeep +1 -0
- package/templates/es/openspec/specs/.gitkeep +1 -0
- package/templates/es/openspec/templates/archive-report.md +23 -0
- package/templates/es/openspec/templates/change-metadata.yaml +9 -0
- package/templates/es/openspec/templates/design.md +33 -0
- package/templates/es/openspec/templates/proposal.md +36 -0
- package/templates/es/openspec/templates/spec.md +33 -0
- package/templates/es/openspec/templates/tasks.md +22 -0
- package/templates/es/openspec/templates/verify-report.md +24 -0
- package/templates/es/orchestrator.config.json +99 -0
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import process from 'process';
|
|
6
|
+
import {spawn} from 'child_process';
|
|
7
|
+
import {fileURLToPath} from 'url';
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import {render} from 'ink';
|
|
10
|
+
import {App} from './app.mjs';
|
|
11
|
+
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const PACKAGE_ROOT = path.resolve(path.dirname(__filename), '..', '..');
|
|
14
|
+
const ROOT = process.cwd();
|
|
15
|
+
const CONFIG_FILE = path.join(ROOT, 'orchestrator.config.json');
|
|
16
|
+
const ENGINE_FILE = path.join(PACKAGE_ROOT, 'orchestrator.js');
|
|
17
|
+
const STATE_FILE = path.join(ROOT, 'logs', 'orchestrator-state.json');
|
|
18
|
+
const LOCK_FILE = path.join(ROOT, 'logs', 'orchestrator.lock');
|
|
19
|
+
const CONTROL_FILE = path.join(ROOT, 'logs', 'orchestrator-control.json');
|
|
20
|
+
|
|
21
|
+
const argv = process.argv.slice(2);
|
|
22
|
+
const startPaused = argv.includes('--paused');
|
|
23
|
+
const TEXT = {
|
|
24
|
+
es: {
|
|
25
|
+
configMissing: root =>
|
|
26
|
+
`No se encontró orchestrator.config.json en ${root}. Ejecuta esta UI desde la raíz del proyecto.`,
|
|
27
|
+
waitingEngine: 'Esperando motor',
|
|
28
|
+
startingEngine: '[INFO] Iniciando motor del orchestrator...',
|
|
29
|
+
paused: 'Pausado',
|
|
30
|
+
running: 'Ejecutando',
|
|
31
|
+
ready: 'Listo para trabajar',
|
|
32
|
+
attached: pid => `Adjuntado a motor existente (PID ${pid})`,
|
|
33
|
+
startPaused: 'Levantando motor en modo PAUSADO',
|
|
34
|
+
startRunning: 'Levantando motor en modo EJECUTANDO',
|
|
35
|
+
engineExited: code => `Motor finalizado con código ${code ?? 0}`,
|
|
36
|
+
engineError: message => `Error iniciando motor: ${message}`,
|
|
37
|
+
resume: 'Comando enviado: REANUDAR',
|
|
38
|
+
pause: 'Comando enviado: PAUSAR',
|
|
39
|
+
reload: 'Comando enviado: RECARGAR COLA',
|
|
40
|
+
quit: 'Comando enviado: SALIR'
|
|
41
|
+
},
|
|
42
|
+
en: {
|
|
43
|
+
configMissing: root =>
|
|
44
|
+
`orchestrator.config.json was not found in ${root}. Run this UI from the project root.`,
|
|
45
|
+
waitingEngine: 'Waiting for engine',
|
|
46
|
+
startingEngine: '[INFO] Starting orchestrator engine...',
|
|
47
|
+
paused: 'Paused',
|
|
48
|
+
running: 'Running',
|
|
49
|
+
ready: 'Ready to work',
|
|
50
|
+
attached: pid => `Attached to existing engine (PID ${pid})`,
|
|
51
|
+
startPaused: 'Starting engine in PAUSED mode',
|
|
52
|
+
startRunning: 'Starting engine in RUNNING mode',
|
|
53
|
+
engineExited: code => `Engine exited with code ${code ?? 0}`,
|
|
54
|
+
engineError: message => `Error starting engine: ${message}`,
|
|
55
|
+
resume: 'Command sent: RESUME',
|
|
56
|
+
pause: 'Command sent: PAUSE',
|
|
57
|
+
reload: 'Command sent: RELOAD QUEUE',
|
|
58
|
+
quit: 'Command sent: QUIT'
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
function languageFromConfig(config) {
|
|
63
|
+
return config.workspaceLanguage === 'en' ? 'en' : 'es';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let detectedLanguage = 'en';
|
|
67
|
+
try {
|
|
68
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
69
|
+
const _cfg = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
70
|
+
detectedLanguage = languageFromConfig(_cfg);
|
|
71
|
+
}
|
|
72
|
+
} catch {}
|
|
73
|
+
|
|
74
|
+
const SYSTEM_LOCALE = Intl.DateTimeFormat().resolvedOptions().locale;
|
|
75
|
+
function getLocale() { return SYSTEM_LOCALE; }
|
|
76
|
+
|
|
77
|
+
// Limpiar control.json orphan al iniciar
|
|
78
|
+
if (fs.existsSync(CONTROL_FILE)) {
|
|
79
|
+
try {
|
|
80
|
+
const content = JSON.parse(fs.readFileSync(CONTROL_FILE, 'utf8'));
|
|
81
|
+
const age = Date.now() - (content.requestedAt || 0);
|
|
82
|
+
if (age > 5000) {
|
|
83
|
+
fs.unlinkSync(CONTROL_FILE);
|
|
84
|
+
}
|
|
85
|
+
} catch {
|
|
86
|
+
try { fs.unlinkSync(CONTROL_FILE); } catch {}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
let inkApp = null;
|
|
91
|
+
let refreshTimer = null;
|
|
92
|
+
let spawnedEngine = null;
|
|
93
|
+
let localEvents = [];
|
|
94
|
+
let quitRequested = false;
|
|
95
|
+
let resizeTimer = null;
|
|
96
|
+
let isResizing = false;
|
|
97
|
+
let lastColumns = process.stdout?.columns ?? 0;
|
|
98
|
+
|
|
99
|
+
function normalizeInlineMessage(message) {
|
|
100
|
+
return String(message ?? '')
|
|
101
|
+
.replace(/\r?\n+/g, ' ')
|
|
102
|
+
.replace(/\s{2,}/g, ' ')
|
|
103
|
+
.trim();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function pushLocalEvent(message) {
|
|
107
|
+
const normalized = normalizeInlineMessage(message);
|
|
108
|
+
if (!normalized) return;
|
|
109
|
+
const line = `[${new Date().toLocaleTimeString(getLocale(), {hour12: false})}] [INK] ${normalized}`;
|
|
110
|
+
localEvents.push(line);
|
|
111
|
+
if (localEvents.length > 20) localEvents.shift();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function loadConfig() {
|
|
115
|
+
if (!fs.existsSync(CONFIG_FILE)) {
|
|
116
|
+
throw new Error(TEXT[detectedLanguage].configMissing(ROOT));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const config = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
120
|
+
detectedLanguage = languageFromConfig(config);
|
|
121
|
+
return config;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function isPidRunning(pid) {
|
|
125
|
+
if (!pid || Number.isNaN(pid)) return false;
|
|
126
|
+
try {
|
|
127
|
+
process.kill(pid, 0);
|
|
128
|
+
return true;
|
|
129
|
+
} catch {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function readLockPid() {
|
|
135
|
+
if (!fs.existsSync(LOCK_FILE)) return null;
|
|
136
|
+
const raw = fs.readFileSync(LOCK_FILE, 'utf8').trim();
|
|
137
|
+
const pid = Number.parseInt(raw, 10);
|
|
138
|
+
return Number.isNaN(pid) ? null : pid;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function formatDuration(seconds) {
|
|
142
|
+
if (!Number.isFinite(seconds) || seconds <= 0) return '0s';
|
|
143
|
+
if (seconds < 60) return `${seconds}s`;
|
|
144
|
+
const minutes = Math.floor(seconds / 60);
|
|
145
|
+
if (minutes < 60) return `${minutes}m${seconds % 60 ? `${seconds % 60}s` : ''}`;
|
|
146
|
+
const hours = Math.floor(minutes / 60);
|
|
147
|
+
return `${hours}h${minutes % 60}m`;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function readEngineState() {
|
|
151
|
+
if (!fs.existsSync(STATE_FILE)) return null;
|
|
152
|
+
try {
|
|
153
|
+
return JSON.parse(fs.readFileSync(STATE_FILE, 'utf8'));
|
|
154
|
+
} catch {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function sendControlCommand(type) {
|
|
160
|
+
fs.mkdirSync(path.dirname(CONTROL_FILE), {recursive: true});
|
|
161
|
+
fs.writeFileSync(
|
|
162
|
+
CONTROL_FILE,
|
|
163
|
+
JSON.stringify(
|
|
164
|
+
{
|
|
165
|
+
type,
|
|
166
|
+
requestedAt: Date.now(),
|
|
167
|
+
source: 'ink'
|
|
168
|
+
},
|
|
169
|
+
null,
|
|
170
|
+
2
|
|
171
|
+
) + '\n',
|
|
172
|
+
'utf8'
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function buildFallbackSnapshot(config) {
|
|
177
|
+
const language = languageFromConfig(config);
|
|
178
|
+
const text = TEXT[language];
|
|
179
|
+
const agents = Object.keys(config.agents || {}).map(name => ({
|
|
180
|
+
name,
|
|
181
|
+
status: 'idle',
|
|
182
|
+
task: null,
|
|
183
|
+
detail: text.waitingEngine
|
|
184
|
+
}));
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
projectName: config.projectName || 'Orchestrator Multi-Agents',
|
|
188
|
+
timestamp: new Date().toLocaleString(getLocale(), {hour12: false}),
|
|
189
|
+
totalCost: '$0.00',
|
|
190
|
+
queue: [],
|
|
191
|
+
completed: [],
|
|
192
|
+
logs:
|
|
193
|
+
localEvents.length > 0
|
|
194
|
+
? localEvents.slice(-6)
|
|
195
|
+
: [text.startingEngine],
|
|
196
|
+
agents,
|
|
197
|
+
stateLabel: startPaused ? text.paused : text.running,
|
|
198
|
+
workspaceLanguage: language,
|
|
199
|
+
activeLabel: '0s',
|
|
200
|
+
startedAt: null,
|
|
201
|
+
isRunning: false
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function buildSnapshot() {
|
|
206
|
+
const config = loadConfig();
|
|
207
|
+
const language = languageFromConfig(config);
|
|
208
|
+
const text = TEXT[language];
|
|
209
|
+
const engineState = readEngineState();
|
|
210
|
+
|
|
211
|
+
if (!engineState) {
|
|
212
|
+
return buildFallbackSnapshot(config);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const busyCount = Object.values(engineState.agents || {}).filter(
|
|
216
|
+
agent => agent.status === 'busy'
|
|
217
|
+
).length;
|
|
218
|
+
|
|
219
|
+
const agents = Object.entries(config.agents || {}).map(([name]) => {
|
|
220
|
+
const agent = engineState.agents?.[name];
|
|
221
|
+
return {
|
|
222
|
+
name,
|
|
223
|
+
status: agent?.status === 'busy' ? 'busy' : 'idle',
|
|
224
|
+
task: agent?.task ? `${agent.task.id} · ${agent.task.title}` : null,
|
|
225
|
+
detail:
|
|
226
|
+
agent?.status === 'busy'
|
|
227
|
+
? `${agent.task?.priority || 'P?'} · ${agent.task?.repo || 'repo'}`
|
|
228
|
+
: agent?.lastLine || text.ready
|
|
229
|
+
};
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const activeSeconds = engineState.startTime
|
|
233
|
+
? Math.max(0, Math.round((Date.now() - engineState.startTime) / 1000))
|
|
234
|
+
: 0;
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
projectName: engineState.projectName || config.projectName || 'Orchestrator Multi-Agents',
|
|
238
|
+
timestamp: new Date().toLocaleString(getLocale(), {hour12: false}),
|
|
239
|
+
totalCost:
|
|
240
|
+
typeof engineState.totalCost === 'number'
|
|
241
|
+
? `$${engineState.totalCost.toFixed(2)}`
|
|
242
|
+
: '$0.00',
|
|
243
|
+
queue: engineState.queue || [],
|
|
244
|
+
completed: engineState.completed || [],
|
|
245
|
+
logs:
|
|
246
|
+
engineState.logs && engineState.logs.length > 0
|
|
247
|
+
? engineState.logs.slice(-6)
|
|
248
|
+
: localEvents.slice(-6),
|
|
249
|
+
agents,
|
|
250
|
+
stateLabel: engineState.paused ? text.paused : text.running,
|
|
251
|
+
workspaceLanguage: engineState.workspaceLanguage || language,
|
|
252
|
+
activeLabel: formatDuration(activeSeconds),
|
|
253
|
+
startedAt: engineState.startTime || null,
|
|
254
|
+
isRunning: busyCount > 0 || isPidRunning(engineState.pid)
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function ensureEngine() {
|
|
259
|
+
const config = loadConfig();
|
|
260
|
+
const text = TEXT[languageFromConfig(config)];
|
|
261
|
+
const runningPid = readLockPid();
|
|
262
|
+
if (runningPid && isPidRunning(runningPid)) {
|
|
263
|
+
pushLocalEvent(text.attached(runningPid));
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const childArgs = [ENGINE_FILE, '--headless'];
|
|
268
|
+
if (startPaused) childArgs.push('--paused');
|
|
269
|
+
|
|
270
|
+
pushLocalEvent(
|
|
271
|
+
startPaused ? text.startPaused : text.startRunning
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
spawnedEngine = spawn(process.execPath, childArgs, {
|
|
275
|
+
cwd: ROOT,
|
|
276
|
+
env: {
|
|
277
|
+
...process.env,
|
|
278
|
+
ORCHESTRATOR_WORKSPACE: ROOT,
|
|
279
|
+
NODE_PATH: [path.join(PACKAGE_ROOT, 'node_modules'), process.env.NODE_PATH]
|
|
280
|
+
.filter(Boolean)
|
|
281
|
+
.join(path.delimiter)
|
|
282
|
+
},
|
|
283
|
+
stdio: ['ignore', 'ignore', 'pipe'],
|
|
284
|
+
windowsHide: false
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
spawnedEngine.stderr.on('data', chunk => {
|
|
288
|
+
const text = normalizeInlineMessage(String(chunk));
|
|
289
|
+
if (text) pushLocalEvent(text);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
spawnedEngine.on('exit', code => {
|
|
293
|
+
pushLocalEvent(text.engineExited(code));
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
spawnedEngine.on('error', error => {
|
|
297
|
+
pushLocalEvent(text.engineError(error.message));
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function refresh() {
|
|
302
|
+
if (isResizing) return;
|
|
303
|
+
|
|
304
|
+
const snapshot = buildSnapshot();
|
|
305
|
+
if (!inkApp) {
|
|
306
|
+
inkApp = render(React.createElement(App, {snapshot, onAction: requestAction}), {
|
|
307
|
+
exitOnCtrlC: false,
|
|
308
|
+
patchConsole: false,
|
|
309
|
+
alternateScreen: true
|
|
310
|
+
});
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
inkApp.rerender(React.createElement(App, {snapshot, onAction: requestAction}));
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function clearTerminal() {
|
|
318
|
+
if (!process.stdout.isTTY) return;
|
|
319
|
+
process.stdout.write('\x1b[2J\x1b[3J\x1b[H');
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function requestAction(action) {
|
|
323
|
+
const config = loadConfig();
|
|
324
|
+
const text = TEXT[languageFromConfig(config)];
|
|
325
|
+
switch (action) {
|
|
326
|
+
case 'start':
|
|
327
|
+
pushLocalEvent(text.resume);
|
|
328
|
+
sendControlCommand('start');
|
|
329
|
+
break;
|
|
330
|
+
case 'pause':
|
|
331
|
+
pushLocalEvent(text.pause);
|
|
332
|
+
sendControlCommand('pause');
|
|
333
|
+
break;
|
|
334
|
+
case 'reload':
|
|
335
|
+
pushLocalEvent(text.reload);
|
|
336
|
+
sendControlCommand('reload');
|
|
337
|
+
break;
|
|
338
|
+
case 'quit':
|
|
339
|
+
quitRequested = true;
|
|
340
|
+
pushLocalEvent(text.quit);
|
|
341
|
+
sendControlCommand('quit');
|
|
342
|
+
setTimeout(() => {
|
|
343
|
+
shutdown();
|
|
344
|
+
process.exit(0);
|
|
345
|
+
}, 500);
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function shutdown() {
|
|
351
|
+
if (refreshTimer) clearInterval(refreshTimer);
|
|
352
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
353
|
+
if (spawnedEngine && !spawnedEngine.killed && quitRequested) {
|
|
354
|
+
try {
|
|
355
|
+
spawnedEngine.kill('SIGTERM');
|
|
356
|
+
} catch {}
|
|
357
|
+
}
|
|
358
|
+
if (inkApp) inkApp.unmount();
|
|
359
|
+
// Limpiar archivos de control al salir
|
|
360
|
+
try { fs.unlinkSync(CONTROL_FILE); } catch {}
|
|
361
|
+
try { fs.unlinkSync(LOCK_FILE); } catch {}
|
|
362
|
+
try { fs.unlinkSync(STATE_FILE); } catch {}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function mount() {
|
|
366
|
+
ensureEngine();
|
|
367
|
+
refresh();
|
|
368
|
+
refreshTimer = setInterval(refresh, 1000);
|
|
369
|
+
|
|
370
|
+
if (process.stdout.isTTY) {
|
|
371
|
+
process.stdout.on('resize', () => {
|
|
372
|
+
const nextColumns = process.stdout.columns ?? 0;
|
|
373
|
+
const shrinking = nextColumns > 0 && lastColumns > 0 && nextColumns < lastColumns;
|
|
374
|
+
lastColumns = nextColumns;
|
|
375
|
+
isResizing = true;
|
|
376
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
377
|
+
resizeTimer = setTimeout(() => {
|
|
378
|
+
if (shrinking) {
|
|
379
|
+
clearTerminal();
|
|
380
|
+
if (inkApp) {
|
|
381
|
+
inkApp.unmount();
|
|
382
|
+
inkApp = null;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
isResizing = false;
|
|
386
|
+
refresh();
|
|
387
|
+
}, 180);
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
process.on('SIGINT', () => {
|
|
393
|
+
requestAction('quit');
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
process.on('SIGTERM', () => {
|
|
397
|
+
requestAction('quit');
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
mount();
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Skill Registry
|
|
2
|
+
|
|
3
|
+
**Project-local only.** This registry prioritizes skills inside `./.claude/skills/` so the workflow does not depend on global installations.
|
|
4
|
+
|
|
5
|
+
## User Skills
|
|
6
|
+
|
|
7
|
+
| Trigger | Skill | Path |
|
|
8
|
+
|---------|-------|------|
|
|
9
|
+
| manual | orchestrator-apply | `.claude/skills/orchestrator-apply/SKILL.md` |
|
|
10
|
+
| manual | orchestrator-archive | `.claude/skills/orchestrator-archive/SKILL.md` |
|
|
11
|
+
| manual | orchestrator-design | `.claude/skills/orchestrator-design/SKILL.md` |
|
|
12
|
+
| manual | orchestrator-explore | `.claude/skills/orchestrator-explore/SKILL.md` |
|
|
13
|
+
| manual | orchestrator-init | `.claude/skills/orchestrator-init/SKILL.md` |
|
|
14
|
+
| manual | orchestrator-memory | `.claude/skills/orchestrator-memory/SKILL.md` |
|
|
15
|
+
| manual | orchestrator-openspec | `.claude/skills/orchestrator-openspec/SKILL.md` |
|
|
16
|
+
| manual | orchestrator-propose | `.claude/skills/orchestrator-propose/SKILL.md` |
|
|
17
|
+
| manual | orchestrator-queue-planning | `.claude/skills/orchestrator-queue-planning/SKILL.md` |
|
|
18
|
+
| manual | orchestrator-spec | `.claude/skills/orchestrator-spec/SKILL.md` |
|
|
19
|
+
| manual | orchestrator-tasks | `.claude/skills/orchestrator-tasks/SKILL.md` |
|
|
20
|
+
| manual | orchestrator-verify | `.claude/skills/orchestrator-verify/SKILL.md` |
|
|
21
|
+
|
|
22
|
+
## Resolution Policy
|
|
23
|
+
|
|
24
|
+
- Always prefer local skills from `./.claude/skills/`.
|
|
25
|
+
- Do not depend on global skills for the main orchestrator workflow.
|
|
26
|
+
- If a global skill has the same name, the project-local skill wins.
|
|
27
|
+
- Regenerate this file after creating, deleting, or changing local skills.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: orchestrator-apply
|
|
3
|
+
description: >
|
|
4
|
+
Guide the implementation phase by translating ready work into queued worker tasks.
|
|
5
|
+
license: MIT
|
|
6
|
+
metadata:
|
|
7
|
+
owner: agentflow
|
|
8
|
+
version: "1.0"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Skill: orchestrator-apply
|
|
12
|
+
|
|
13
|
+
## Purpose
|
|
14
|
+
|
|
15
|
+
Run implementation through the orchestrator, not through the interactive Claude session.
|
|
16
|
+
|
|
17
|
+
## Critical Rules
|
|
18
|
+
|
|
19
|
+
- Read proposal, spec, design, tasks, and queue state when present.
|
|
20
|
+
- Respect `QUEUE.md` as the execution boundary.
|
|
21
|
+
- Do not implement code directly as Claude-Orchestrator.
|
|
22
|
+
- Add or update TASKs so workers can implement.
|
|
23
|
+
- Use Codex and OpenCode first when they fit the task.
|
|
24
|
+
- Use Claude-Worker for fallback, extra capacity, broad implementation, or explicit user request.
|
|
25
|
+
- Keep Claude as final reviewer.
|
|
26
|
+
- Do not commit or push.
|
|
27
|
+
- If implementation is partial, leave clear state for verify or the next apply pass.
|
|
28
|
+
|
|
29
|
+
## Expected Result
|
|
30
|
+
|
|
31
|
+
Implementation work is queued for workers and remains reviewable by Claude-Orchestrator.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: orchestrator-archive
|
|
3
|
+
description: >
|
|
4
|
+
Close and archive a completed OpenSpec change after implementation and verification.
|
|
5
|
+
license: MIT
|
|
6
|
+
metadata:
|
|
7
|
+
owner: agentflow
|
|
8
|
+
version: "1.0"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Skill: orchestrator-archive
|
|
12
|
+
|
|
13
|
+
## Purpose
|
|
14
|
+
|
|
15
|
+
Close a change with a durable summary of what was done and what remains.
|
|
16
|
+
|
|
17
|
+
## Critical Rules
|
|
18
|
+
|
|
19
|
+
- Confirm proposal, spec, design, tasks, and verify report are coherent.
|
|
20
|
+
- Write or update `archive-report.md`.
|
|
21
|
+
- Note completed work, remaining risks, and follow-ups.
|
|
22
|
+
- Do not archive incomplete work as complete.
|
|
23
|
+
|
|
24
|
+
## Expected Result
|
|
25
|
+
|
|
26
|
+
A closed change with a useful archive report.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: orchestrator-design
|
|
3
|
+
description: >
|
|
4
|
+
Create or update the technical design for a change.
|
|
5
|
+
license: MIT
|
|
6
|
+
metadata:
|
|
7
|
+
owner: agentflow
|
|
8
|
+
version: "1.0"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Skill: orchestrator-design
|
|
12
|
+
|
|
13
|
+
## Purpose
|
|
14
|
+
|
|
15
|
+
Document the technical approach, tradeoffs, affected files, risks, and rollout plan.
|
|
16
|
+
|
|
17
|
+
## Critical Rules
|
|
18
|
+
|
|
19
|
+
- Use `openspec/changes/<change-name>/design.md`.
|
|
20
|
+
- Prefer existing project patterns.
|
|
21
|
+
- Capture tradeoffs and risks clearly.
|
|
22
|
+
- Keep design aligned with the proposal and spec.
|
|
23
|
+
- Do not implement code directly.
|
|
24
|
+
|
|
25
|
+
## Expected Result
|
|
26
|
+
|
|
27
|
+
A technical design that can be broken into executable tasks.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: orchestrator-explore
|
|
3
|
+
description: >
|
|
4
|
+
Explore, analyze, or investigate the project before proposing or delegating implementation.
|
|
5
|
+
license: MIT
|
|
6
|
+
metadata:
|
|
7
|
+
owner: agentflow
|
|
8
|
+
version: "1.0"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Skill: orchestrator-explore
|
|
12
|
+
|
|
13
|
+
## Purpose
|
|
14
|
+
|
|
15
|
+
Gather useful context before creating TASKs or OpenSpec artifacts.
|
|
16
|
+
|
|
17
|
+
## Critical Rules
|
|
18
|
+
|
|
19
|
+
- Understand the user's exact scope first.
|
|
20
|
+
- Prefer exploration before implementation when context is unclear.
|
|
21
|
+
- Use OpenCode as the first support worker for broad reading, audits, and structured findings when appropriate.
|
|
22
|
+
- Do not fill `QUEUE.md` with implementation tasks until enough context exists.
|
|
23
|
+
- Summarize findings in actionable terms: what exists, what is missing, what risks exist, and what tasks follow.
|
|
24
|
+
- If the change is large or multi-phase, move toward OpenSpec.
|
|
25
|
+
- If work is clear, convert findings into concrete TASKs.
|
|
26
|
+
|
|
27
|
+
## Expected Result
|
|
28
|
+
|
|
29
|
+
The orchestrator can decide whether to plan TASKs or continue investigation.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: orchestrator-init
|
|
3
|
+
description: >
|
|
4
|
+
Initialize the orchestrator session: read ORCHESTRATOR.md, config, queue, progress, handoffs, and visible state before asking for the next priority.
|
|
5
|
+
license: MIT
|
|
6
|
+
metadata:
|
|
7
|
+
owner: agentflow
|
|
8
|
+
version: "1.0"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Skill: orchestrator-init
|
|
12
|
+
|
|
13
|
+
Trigger examples: "start", "start orchestrator", "read ORCHESTRATOR.md and start", "lee ORCHESTRATOR.md y arranca".
|
|
14
|
+
|
|
15
|
+
## Purpose
|
|
16
|
+
|
|
17
|
+
Prepare a new orchestrator session without executing project work directly.
|
|
18
|
+
|
|
19
|
+
## Critical Rules
|
|
20
|
+
|
|
21
|
+
- Read `ORCHESTRATOR.md` completely before responding.
|
|
22
|
+
- Read `orchestrator.config.json` to understand repos, agents, and models.
|
|
23
|
+
- Read `QUEUE.md` to detect pending, active, and completed work.
|
|
24
|
+
- Read the newest handoff if present.
|
|
25
|
+
- Read progress files if present.
|
|
26
|
+
- Use `PROJECT.md` and `openspec/` as context when available.
|
|
27
|
+
- Do not implement code during startup.
|
|
28
|
+
- Reply that the orchestrator is ready and ask what the user wants to prioritize.
|
|
29
|
+
|
|
30
|
+
## Expected Result
|
|
31
|
+
|
|
32
|
+
Claude is ready as Claude-Orchestrator and has not performed project implementation directly.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: orchestrator-memory
|
|
3
|
+
description: >
|
|
4
|
+
Use persistent memory for decisions, discoveries, bugs, setup notes, and session summaries.
|
|
5
|
+
license: MIT
|
|
6
|
+
metadata:
|
|
7
|
+
owner: agentflow
|
|
8
|
+
version: "1.0"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Skill: orchestrator-memory
|
|
12
|
+
|
|
13
|
+
## Purpose
|
|
14
|
+
|
|
15
|
+
Preserve durable context for future sessions.
|
|
16
|
+
|
|
17
|
+
## Critical Rules
|
|
18
|
+
|
|
19
|
+
- Follow `ENGRAM.md`.
|
|
20
|
+
- Save decisions, bug fixes, discoveries, setup changes, and session summaries.
|
|
21
|
+
- Do not save secrets, credentials, API keys, or private customer data.
|
|
22
|
+
- Memory complements `QUEUE.md`, OpenSpec, and handoffs. It does not replace them.
|
|
23
|
+
|
|
24
|
+
## Expected Result
|
|
25
|
+
|
|
26
|
+
Future sessions can resume with useful context instead of rediscovering everything.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: orchestrator-openspec
|
|
3
|
+
description: >
|
|
4
|
+
Create or update OpenSpec artifacts for large or multi-phase changes.
|
|
5
|
+
license: MIT
|
|
6
|
+
metadata:
|
|
7
|
+
owner: agentflow
|
|
8
|
+
version: "1.0"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Skill: orchestrator-openspec
|
|
12
|
+
|
|
13
|
+
## Purpose
|
|
14
|
+
|
|
15
|
+
Use `openspec/` as the durable planning layer before delegating larger implementation work.
|
|
16
|
+
|
|
17
|
+
## When To Use
|
|
18
|
+
|
|
19
|
+
- Multi-phase changes
|
|
20
|
+
- Multi-agent changes
|
|
21
|
+
- User explicitly asks for proposal, spec, design, or tasks
|
|
22
|
+
- The change needs durable traceability
|
|
23
|
+
|
|
24
|
+
## Critical Rules
|
|
25
|
+
|
|
26
|
+
- Create changes under `openspec/changes/<change-name>/`.
|
|
27
|
+
- Use clear kebab-case change names.
|
|
28
|
+
- Keep proposal, spec, design, tasks, verify report, and archive report consistent.
|
|
29
|
+
- `tasks.md` should be translatable into `QUEUE.md`.
|
|
30
|
+
- Do not queue large implementation work before the OpenSpec artifacts are clear.
|
|
31
|
+
- Do not force OpenSpec for tiny direct changes.
|
|
32
|
+
|
|
33
|
+
## Expected Result
|
|
34
|
+
|
|
35
|
+
A coherent OpenSpec change that can feed the live queue.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: orchestrator-propose
|
|
3
|
+
description: >
|
|
4
|
+
Create or update the proposal for a significant change before implementation.
|
|
5
|
+
license: MIT
|
|
6
|
+
metadata:
|
|
7
|
+
owner: agentflow
|
|
8
|
+
version: "1.0"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Skill: orchestrator-propose
|
|
12
|
+
|
|
13
|
+
## Purpose
|
|
14
|
+
|
|
15
|
+
Define what the change is, why it matters, what is in scope, and what is explicitly out of scope.
|
|
16
|
+
|
|
17
|
+
## Critical Rules
|
|
18
|
+
|
|
19
|
+
- Read the user's request and current project context.
|
|
20
|
+
- Use `openspec/changes/<change-name>/proposal.md`.
|
|
21
|
+
- Keep the proposal short, actionable, and durable.
|
|
22
|
+
- Do not implement code while writing the proposal.
|
|
23
|
+
|
|
24
|
+
## Expected Result
|
|
25
|
+
|
|
26
|
+
A proposal that can move into spec, design, tasks, and queue planning.
|