expxagents 0.16.2 → 0.17.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.
- package/assets/core/solution-architect.agent.md +16 -10
- package/dist/cli/src/commands/list.js +100 -28
- package/dist/cli/src/commands/reorganize.d.ts +1 -0
- package/dist/cli/src/commands/reorganize.js +296 -0
- package/dist/cli/src/commands/run.js +5 -4
- package/dist/cli/src/commands/stop.js +4 -3
- package/dist/cli/src/index.js +5 -0
- package/dist/core/squad-loader.d.ts +5 -0
- package/dist/core/squad-loader.js +53 -0
- package/dist/server/api/squads-routes.d.ts.map +1 -1
- package/dist/server/api/squads-routes.js +107 -46
- package/dist/server/api/squads-routes.js.map +1 -1
- package/dist/server/watcher/__tests__/file-watcher.test.js +31 -0
- package/dist/server/watcher/__tests__/file-watcher.test.js.map +1 -1
- package/dist/server/watcher/file-watcher.js +1 -1
- package/dist/server/watcher/file-watcher.js.map +1 -1
- package/package.json +1 -1
|
@@ -19,16 +19,20 @@ You are the Solution Architect of ExpxAgents. You design AI agent squads that ex
|
|
|
19
19
|
- **Role:** Design squads by understanding user needs, researching context, and generating complete configurations
|
|
20
20
|
- **Communication:** Clear, structured, asks precise questions
|
|
21
21
|
|
|
22
|
-
## Discovery Phase (max
|
|
22
|
+
## Discovery Phase (max 7 questions)
|
|
23
23
|
|
|
24
24
|
Before designing, gather requirements through focused questions:
|
|
25
25
|
|
|
26
|
-
1. **
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
1. **Hierarquia:** Qual o Setor, Grupo e Sessão desta squad?
|
|
27
|
+
- Setores comuns: marketing, comercial, desenvolvimento, suporte, financeiro, rh, operações, estrategia, design, juridico, administrativo
|
|
28
|
+
- Se a descrição da squad já deixa claro, infira e apresente como sugestão para confirmação.
|
|
29
|
+
- Exemplo: "Esta squad parece ser de **marketing > redes-sociais > instagram**. Confirma?"
|
|
30
|
+
- A resposta definirá o diretório: `squads/<setor>/<grupo>/<sessao>/<code>/`
|
|
31
|
+
2. **Objetivo:** Qual resultado específico esta squad deve produzir?
|
|
32
|
+
3. **Contexto:** Quem é o público-alvo e qual plataforma/formato?
|
|
33
|
+
4. **Processo:** Há etapas ou fases específicas que você quer no fluxo?
|
|
34
|
+
5. **Qualidade:** Quais são os critérios de qualidade para o output final?
|
|
35
|
+
6. **Referências:** Há perfis de referência, concorrentes ou exemplos para investigar?
|
|
32
36
|
|
|
33
37
|
If the user provides reference URLs, delegate to the **Insight Hunter** to investigate before designing.
|
|
34
38
|
|
|
@@ -48,8 +52,10 @@ After discovery, generate the complete squad structure:
|
|
|
48
52
|
|
|
49
53
|
```yaml
|
|
50
54
|
squad:
|
|
51
|
-
code: <
|
|
52
|
-
|
|
55
|
+
code: <sessao>-<squad-name> # e.g., instagram-publicador
|
|
56
|
+
setor: <setor> # e.g., marketing
|
|
57
|
+
grupo: <grupo> # e.g., redes-sociais
|
|
58
|
+
sessao: <sessao> # e.g., instagram
|
|
53
59
|
name: <Human Readable Name>
|
|
54
60
|
description: <What this squad produces>
|
|
55
61
|
icon: <emoji-name>
|
|
@@ -197,4 +203,4 @@ Before presenting the design to the user:
|
|
|
197
203
|
|
|
198
204
|
Present the complete structure to the user and ask for confirmation before writing files.
|
|
199
205
|
|
|
200
|
-
After confirmation, create all files in the `squads/<code>/` directory.
|
|
206
|
+
After confirmation, create all files in the `squads/<setor>/<grupo>/<sessao>/<code>/` directory.
|
|
@@ -1,49 +1,121 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import
|
|
3
|
+
import yaml from 'js-yaml';
|
|
4
4
|
import { loadSkills } from '../../../core/skills-loader.js';
|
|
5
5
|
import { readState } from '../../../core/state-manager.js';
|
|
6
|
+
function walkSquads(squadsDir) {
|
|
7
|
+
if (!fs.existsSync(squadsDir))
|
|
8
|
+
return [];
|
|
9
|
+
const entries = [];
|
|
10
|
+
function walk(dir) {
|
|
11
|
+
let dirEntries;
|
|
12
|
+
try {
|
|
13
|
+
dirEntries = fs.readdirSync(dir, { withFileTypes: true });
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
for (const entry of dirEntries) {
|
|
19
|
+
if (!entry.isDirectory())
|
|
20
|
+
continue;
|
|
21
|
+
if (entry.name.startsWith('.') || entry.name.startsWith('_'))
|
|
22
|
+
continue;
|
|
23
|
+
const fullPath = path.join(dir, entry.name);
|
|
24
|
+
const yamlPath = path.join(fullPath, 'squad.yaml');
|
|
25
|
+
if (fs.existsSync(yamlPath)) {
|
|
26
|
+
try {
|
|
27
|
+
const raw = fs.readFileSync(yamlPath, 'utf-8');
|
|
28
|
+
const parsed = yaml.load(raw);
|
|
29
|
+
const s = parsed?.squad;
|
|
30
|
+
if (s) {
|
|
31
|
+
const state = readState(fullPath);
|
|
32
|
+
entries.push({
|
|
33
|
+
code: s.code ?? entry.name,
|
|
34
|
+
name: s.name ?? entry.name,
|
|
35
|
+
description: s.description ?? '',
|
|
36
|
+
setor: s.setor,
|
|
37
|
+
grupo: s.grupo,
|
|
38
|
+
sessao: s.sessao,
|
|
39
|
+
agentCount: Array.isArray(s.agents) ? s.agents.length : 0,
|
|
40
|
+
stepCount: Array.isArray(s.pipeline?.steps) ? s.pipeline.steps.length : 0,
|
|
41
|
+
status: state?.status ?? 'idle',
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
entries.push({
|
|
47
|
+
code: entry.name,
|
|
48
|
+
name: entry.name,
|
|
49
|
+
description: `error loading: ${err.message}`,
|
|
50
|
+
agentCount: 0,
|
|
51
|
+
stepCount: 0,
|
|
52
|
+
status: 'error',
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
// Do NOT recurse into squad directories
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
walk(fullPath);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
walk(squadsDir);
|
|
63
|
+
return entries;
|
|
64
|
+
}
|
|
65
|
+
function capitalize(s) {
|
|
66
|
+
return s
|
|
67
|
+
.split('-')
|
|
68
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
69
|
+
.join(' ');
|
|
70
|
+
}
|
|
6
71
|
export async function listCommand() {
|
|
7
72
|
const cwd = process.cwd();
|
|
8
73
|
const squadsDir = path.join(cwd, 'squads');
|
|
9
74
|
const skillsDir = path.join(cwd, 'skills');
|
|
10
|
-
// List squads
|
|
11
75
|
console.log('Squads:');
|
|
12
76
|
console.log('-------');
|
|
13
77
|
if (fs.existsSync(squadsDir)) {
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
78
|
+
const allSquads = walkSquads(squadsDir);
|
|
79
|
+
if (allSquads.length === 0) {
|
|
80
|
+
console.log(' No squads found. Run `expxagents create` to create one.\n');
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const hierarchical = allSquads
|
|
84
|
+
.filter((s) => s.setor)
|
|
85
|
+
.sort((a, b) => {
|
|
86
|
+
const ak = `${a.setor}/${a.grupo}/${a.sessao}/${a.code}`;
|
|
87
|
+
const bk = `${b.setor}/${b.grupo}/${b.sessao}/${b.code}`;
|
|
88
|
+
return ak.localeCompare(bk);
|
|
89
|
+
});
|
|
90
|
+
const flat = allSquads.filter((s) => !s.setor);
|
|
91
|
+
// Render hierarchical squads
|
|
92
|
+
let lastHeader = '';
|
|
93
|
+
for (const s of hierarchical) {
|
|
94
|
+
const header = `${capitalize(s.setor)} > ${capitalize(s.grupo ?? '')} > ${capitalize(s.sessao ?? '')}`;
|
|
95
|
+
if (header !== lastHeader) {
|
|
96
|
+
console.log(`\n ${header}`);
|
|
97
|
+
lastHeader = header;
|
|
98
|
+
}
|
|
99
|
+
console.log(` ${s.name} (${s.code})`);
|
|
100
|
+
console.log(` Status: ${s.status} | Agents: ${s.agentCount} | Steps: ${s.stepCount}`);
|
|
101
|
+
console.log(` ${s.description}`);
|
|
34
102
|
}
|
|
35
|
-
|
|
36
|
-
|
|
103
|
+
// Render flat (legacy) squads
|
|
104
|
+
if (flat.length > 0) {
|
|
105
|
+
console.log('\n [sem hierarquia]');
|
|
106
|
+
for (const s of flat) {
|
|
107
|
+
console.log(` ${s.name} (${s.code})`);
|
|
108
|
+
console.log(` Status: ${s.status} | Agents: ${s.agentCount} | Steps: ${s.stepCount}`);
|
|
109
|
+
console.log(` ${s.description}`);
|
|
110
|
+
}
|
|
37
111
|
}
|
|
38
|
-
|
|
39
|
-
if (!found) {
|
|
40
|
-
console.log(' No squads found. Run `expxagents create` to create one.\n');
|
|
112
|
+
console.log('');
|
|
41
113
|
}
|
|
42
114
|
}
|
|
43
115
|
else {
|
|
44
116
|
console.log(' No squads directory. Run `expxagents init` first.\n');
|
|
45
117
|
}
|
|
46
|
-
// List skills
|
|
118
|
+
// List skills (unchanged)
|
|
47
119
|
console.log('Skills:');
|
|
48
120
|
console.log('-------');
|
|
49
121
|
const skills = loadSkills(skillsDir);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function reorganizeCommand(): Promise<void>;
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { spawn } from 'child_process';
|
|
4
|
+
import * as readline from 'readline';
|
|
5
|
+
import yaml from 'js-yaml';
|
|
6
|
+
// Walk squadsDir recursively, return all squad summaries
|
|
7
|
+
function discoverAllSquads(squadsDir) {
|
|
8
|
+
const result = [];
|
|
9
|
+
function walk(dir) {
|
|
10
|
+
let entries;
|
|
11
|
+
try {
|
|
12
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
for (const entry of entries) {
|
|
18
|
+
if (!entry.isDirectory())
|
|
19
|
+
continue;
|
|
20
|
+
if (entry.name.startsWith('.') || entry.name.startsWith('_'))
|
|
21
|
+
continue;
|
|
22
|
+
const fullPath = path.join(dir, entry.name);
|
|
23
|
+
const yamlPath = path.join(fullPath, 'squad.yaml');
|
|
24
|
+
if (fs.existsSync(yamlPath)) {
|
|
25
|
+
try {
|
|
26
|
+
const raw = fs.readFileSync(yamlPath, 'utf-8');
|
|
27
|
+
const parsed = yaml.load(raw);
|
|
28
|
+
const s = parsed?.squad;
|
|
29
|
+
if (s) {
|
|
30
|
+
result.push({
|
|
31
|
+
code: s.code ?? entry.name,
|
|
32
|
+
name: s.name ?? entry.name,
|
|
33
|
+
description: s.description ?? '',
|
|
34
|
+
setor: s.setor,
|
|
35
|
+
grupo: s.grupo,
|
|
36
|
+
sessao: s.sessao,
|
|
37
|
+
dir: fullPath,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Skip malformed YAML
|
|
43
|
+
}
|
|
44
|
+
// Don't recurse into squad directories
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
walk(fullPath);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
walk(squadsDir);
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
// Call Claude to infer hierarchy for a list of squads
|
|
55
|
+
async function inferHierarchyWithClaude(squads) {
|
|
56
|
+
const squadList = squads
|
|
57
|
+
.map((s) => `- code: ${s.code}, name: "${s.name}", description: "${s.description}"`)
|
|
58
|
+
.join('\n');
|
|
59
|
+
const prompt = `Você é um classificador de squads de IA para uma software house.
|
|
60
|
+
Para cada squad abaixo, identifique o Setor, Grupo e Sessão mais adequados.
|
|
61
|
+
|
|
62
|
+
Setores comuns: marketing, comercial, desenvolvimento, suporte, financeiro, rh, operações, estrategia, design, juridico, administrativo
|
|
63
|
+
|
|
64
|
+
Retorne APENAS um JSON válido (sem markdown, sem explicações), no seguinte formato:
|
|
65
|
+
[
|
|
66
|
+
{
|
|
67
|
+
"code": "<squad-code>",
|
|
68
|
+
"setor": "<setor-em-lowercase-sem-acentos>",
|
|
69
|
+
"grupo": "<grupo-em-lowercase-sem-acentos>",
|
|
70
|
+
"sessao": "<sessao-em-lowercase-sem-acentos>",
|
|
71
|
+
"confidence": "high"
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
Use "confidence": "low" quando não tiver certeza da classificação.
|
|
76
|
+
Use hifens em vez de espaços (ex: "redes-sociais", não "redes sociais").
|
|
77
|
+
|
|
78
|
+
Squads para classificar:
|
|
79
|
+
${squadList}`;
|
|
80
|
+
return new Promise((resolve, reject) => {
|
|
81
|
+
let output = '';
|
|
82
|
+
const child = spawn('claude', ['-p', prompt], { stdio: ['pipe', 'pipe', 'pipe'] });
|
|
83
|
+
child.stdout?.on('data', (d) => { output += d.toString(); });
|
|
84
|
+
child.on('error', reject);
|
|
85
|
+
child.on('exit', (code) => {
|
|
86
|
+
if (code !== 0) {
|
|
87
|
+
reject(new Error(`Claude exited with code ${code}`));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
// Extract JSON from output (Claude may include reasoning text)
|
|
92
|
+
const jsonMatch = output.match(/\[[\s\S]*\]/);
|
|
93
|
+
if (!jsonMatch) {
|
|
94
|
+
reject(new Error('No JSON array found in Claude output'));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
resolve(JSON.parse(jsonMatch[0]));
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
reject(new Error(`Failed to parse Claude output: ${err.message}`));
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function ask(rl, question) {
|
|
106
|
+
return new Promise((resolve) => rl.question(question, resolve));
|
|
107
|
+
}
|
|
108
|
+
// Update squad.yaml with new hierarchy fields, remove old 'group' field
|
|
109
|
+
function updateSquadYaml(squadDir, setor, grupo, sessao) {
|
|
110
|
+
const yamlPath = path.join(squadDir, 'squad.yaml');
|
|
111
|
+
const raw = fs.readFileSync(yamlPath, 'utf-8');
|
|
112
|
+
const parsed = yaml.load(raw);
|
|
113
|
+
parsed.squad.setor = setor;
|
|
114
|
+
parsed.squad.grupo = grupo;
|
|
115
|
+
parsed.squad.sessao = sessao;
|
|
116
|
+
delete parsed.squad.group; // remove deprecated field
|
|
117
|
+
fs.writeFileSync(yamlPath, yaml.dump(parsed), 'utf-8');
|
|
118
|
+
}
|
|
119
|
+
// Update cross-squad path references in ALL squad.yaml files after a squad moved
|
|
120
|
+
function updateCrossReferences(squadsDir, oldPath, newPath) {
|
|
121
|
+
const crossFields = ['design_system', 'brand_guidelines', 'assets_path'];
|
|
122
|
+
// Get the old relative path from project root (e.g., "squads/design-system/...")
|
|
123
|
+
// oldPath is absolute; we need relative from cwd
|
|
124
|
+
const cwd = process.cwd();
|
|
125
|
+
const oldRel = path.relative(cwd, oldPath).replace(/\\/g, '/');
|
|
126
|
+
const newRel = path.relative(cwd, newPath).replace(/\\/g, '/');
|
|
127
|
+
function walkForYaml(dir) {
|
|
128
|
+
let entries;
|
|
129
|
+
try {
|
|
130
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
for (const entry of entries) {
|
|
136
|
+
if (!entry.isDirectory())
|
|
137
|
+
continue;
|
|
138
|
+
if (entry.name.startsWith('.') || entry.name.startsWith('_'))
|
|
139
|
+
continue;
|
|
140
|
+
const fullPath = path.join(dir, entry.name);
|
|
141
|
+
const yamlPath = path.join(fullPath, 'squad.yaml');
|
|
142
|
+
if (fs.existsSync(yamlPath)) {
|
|
143
|
+
try {
|
|
144
|
+
const raw = fs.readFileSync(yamlPath, 'utf-8');
|
|
145
|
+
const parsed = yaml.load(raw);
|
|
146
|
+
let changed = false;
|
|
147
|
+
for (const field of crossFields) {
|
|
148
|
+
const val = parsed.squad?.[field];
|
|
149
|
+
if (typeof val === 'string' && val.startsWith(oldRel)) {
|
|
150
|
+
parsed.squad[field] = val.replace(oldRel, newRel);
|
|
151
|
+
changed = true;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (changed) {
|
|
155
|
+
fs.writeFileSync(yamlPath, yaml.dump(parsed), 'utf-8');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
// Skip
|
|
160
|
+
}
|
|
161
|
+
// Don't recurse into squad dirs
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
walkForYaml(fullPath);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
walkForYaml(squadsDir);
|
|
169
|
+
}
|
|
170
|
+
export async function reorganizeCommand() {
|
|
171
|
+
const cwd = process.cwd();
|
|
172
|
+
const squadsDir = path.join(cwd, 'squads');
|
|
173
|
+
if (!fs.existsSync(squadsDir)) {
|
|
174
|
+
console.error('No squads directory found. Run `expxagents init` first.');
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
console.log('Escaneando squads...\n');
|
|
178
|
+
const allSquads = discoverAllSquads(squadsDir);
|
|
179
|
+
if (allSquads.length === 0) {
|
|
180
|
+
console.log('Nenhuma squad encontrada.');
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
// Separate squads that already have hierarchy
|
|
184
|
+
const alreadyClassified = allSquads.filter((s) => s.setor && s.grupo && s.sessao);
|
|
185
|
+
const needClassification = allSquads.filter((s) => !s.setor || !s.grupo || !s.sessao);
|
|
186
|
+
if (alreadyClassified.length > 0) {
|
|
187
|
+
console.log(`${alreadyClassified.length} squad(s) já classificada(s) — sem alterações necessárias.`);
|
|
188
|
+
}
|
|
189
|
+
if (needClassification.length === 0) {
|
|
190
|
+
console.log('Todas as squads já estão classificadas!');
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
console.log(`\n${needClassification.length} squad(s) precisam de classificação. Consultando IA...\n`);
|
|
194
|
+
let inferences = [];
|
|
195
|
+
try {
|
|
196
|
+
inferences = await inferHierarchyWithClaude(needClassification);
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
console.error(`Falha ao consultar IA: ${err.message}`);
|
|
200
|
+
console.log('Você precisará classificar manualmente cada squad.');
|
|
201
|
+
inferences = [];
|
|
202
|
+
}
|
|
203
|
+
// Map inferences by code
|
|
204
|
+
const inferenceMap = new Map(inferences.map((i) => [i.code, i]));
|
|
205
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
206
|
+
const highConfidence = [];
|
|
207
|
+
const lowConfidence = [];
|
|
208
|
+
for (const squad of needClassification) {
|
|
209
|
+
const inference = inferenceMap.get(squad.code);
|
|
210
|
+
if (inference && inference.confidence === 'high') {
|
|
211
|
+
highConfidence.push({ squad, setor: inference.setor, grupo: inference.grupo, sessao: inference.sessao });
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
lowConfidence.push(squad);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Show high-confidence inferences
|
|
218
|
+
if (highConfidence.length > 0) {
|
|
219
|
+
console.log('Inferências com alta confiança:');
|
|
220
|
+
for (const c of highConfidence) {
|
|
221
|
+
const newDir = `${c.setor}/${c.grupo}/${c.sessao}/${c.squad.code}`;
|
|
222
|
+
console.log(` ${c.squad.code} → ${newDir}`);
|
|
223
|
+
}
|
|
224
|
+
const confirm = await ask(rl, '\nConfirmar movimentações acima? [s/n]: ');
|
|
225
|
+
if (confirm.trim().toLowerCase() !== 's') {
|
|
226
|
+
console.log('Cancelado.');
|
|
227
|
+
rl.close();
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// Collect manual classifications for low-confidence squads
|
|
232
|
+
const manualClassifications = [];
|
|
233
|
+
for (const squad of lowConfidence) {
|
|
234
|
+
const inference = inferenceMap.get(squad.code);
|
|
235
|
+
const suggestion = inference
|
|
236
|
+
? ` (sugestão: ${inference.setor}/${inference.grupo}/${inference.sessao})`
|
|
237
|
+
: '';
|
|
238
|
+
console.log(`\nClassificação necessária para: ${squad.code}${suggestion}`);
|
|
239
|
+
console.log(` Descrição: ${squad.description}`);
|
|
240
|
+
const setor = (await ask(rl, ' Setor (ex: marketing, desenvolvimento, rh...): ')).trim();
|
|
241
|
+
const grupo = (await ask(rl, ' Grupo: ')).trim();
|
|
242
|
+
const sessao = (await ask(rl, ' Sessão: ')).trim();
|
|
243
|
+
if (!setor || !grupo || !sessao) {
|
|
244
|
+
console.log(` Pulando ${squad.code} — classificação incompleta.`);
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
manualClassifications.push({ squad, setor, grupo, sessao });
|
|
248
|
+
}
|
|
249
|
+
rl.close();
|
|
250
|
+
const allClassified = [...highConfidence, ...manualClassifications];
|
|
251
|
+
if (allClassified.length === 0) {
|
|
252
|
+
console.log('\nNenhuma squad para mover.');
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
// Show dry-run summary
|
|
256
|
+
console.log('\nPlano de reorganização:');
|
|
257
|
+
for (const c of allClassified) {
|
|
258
|
+
console.log(` ${path.relative(squadsDir, c.squad.dir)} → ${c.setor}/${c.grupo}/${c.sessao}/${c.squad.code}`);
|
|
259
|
+
}
|
|
260
|
+
const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
261
|
+
const finalConfirm = await ask(rl2, '\nExecutar reorganização? [s/n]: ');
|
|
262
|
+
rl2.close();
|
|
263
|
+
if (finalConfirm.trim().toLowerCase() !== 's') {
|
|
264
|
+
console.log('Cancelado.');
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
// Execute moves
|
|
268
|
+
console.log('\nMovendo squads...');
|
|
269
|
+
const moved = [];
|
|
270
|
+
for (const c of allClassified) {
|
|
271
|
+
const newDir = path.join(squadsDir, c.setor, c.grupo, c.sessao, c.squad.code);
|
|
272
|
+
if (c.squad.dir === newDir) {
|
|
273
|
+
console.log(` ${c.squad.code} — já está no local correto.`);
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
try {
|
|
277
|
+
fs.mkdirSync(path.dirname(newDir), { recursive: true });
|
|
278
|
+
fs.renameSync(c.squad.dir, newDir);
|
|
279
|
+
updateSquadYaml(newDir, c.setor, c.grupo, c.sessao);
|
|
280
|
+
moved.push({ squad: c.squad, newDir });
|
|
281
|
+
console.log(` ✓ ${c.squad.code} → ${c.setor}/${c.grupo}/${c.sessao}/${c.squad.code}`);
|
|
282
|
+
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
console.error(` ✗ ${c.squad.code} — falha ao mover: ${err.message}`);
|
|
285
|
+
console.error(' Squads movidas até agora foram mantidas. Corrija o erro e reexecute.');
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
// Update cross-references for moved squads
|
|
289
|
+
if (moved.length > 0) {
|
|
290
|
+
console.log('\nAtualizando referências cruzadas...');
|
|
291
|
+
for (const { squad, newDir } of moved) {
|
|
292
|
+
updateCrossReferences(squadsDir, squad.dir, newDir);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
console.log('\nReorganização concluída!');
|
|
296
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { spawn } from 'child_process';
|
|
4
|
-
import { loadSquad } from '../../../core/squad-loader.js';
|
|
4
|
+
import { loadSquad, findSquadDir } from '../../../core/squad-loader.js';
|
|
5
5
|
import { createInitialState, readState, writeState, updateAgentStatus, updateStep, setHandoff, setSquadStatus, HANDOFF_DELAY_MS, } from '../../../core/state-manager.js';
|
|
6
6
|
import { loadSkills } from '../../../core/skills-loader.js';
|
|
7
7
|
import { getCoreAsset } from '../utils/config.js';
|
|
@@ -130,10 +130,11 @@ function spawnClaudeCode(prompt, cwd) {
|
|
|
130
130
|
}
|
|
131
131
|
export async function runCommand(name) {
|
|
132
132
|
const cwd = process.cwd();
|
|
133
|
-
const
|
|
133
|
+
const squadsDir = path.join(cwd, 'squads');
|
|
134
|
+
const squadDir = findSquadDir(squadsDir, name);
|
|
134
135
|
const skillsDir = path.join(cwd, 'skills');
|
|
135
|
-
if (!
|
|
136
|
-
console.error(`Squad "${name}" not found
|
|
136
|
+
if (!squadDir) {
|
|
137
|
+
console.error(`Squad "${name}" not found. Run \`expxagents list\` to see available squads.`);
|
|
137
138
|
process.exit(1);
|
|
138
139
|
}
|
|
139
140
|
let config;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
1
|
import path from 'path';
|
|
2
|
+
import { findSquadDir } from '../../../core/squad-loader.js';
|
|
3
3
|
import { readState, writeState, setSquadStatus } from '../../../core/state-manager.js';
|
|
4
4
|
export async function stopCommand(name) {
|
|
5
5
|
const cwd = process.cwd();
|
|
6
|
-
const
|
|
7
|
-
|
|
6
|
+
const squadsDir = path.join(cwd, 'squads');
|
|
7
|
+
const squadDir = findSquadDir(squadsDir, name);
|
|
8
|
+
if (!squadDir) {
|
|
8
9
|
console.error(`Squad "${name}" not found.`);
|
|
9
10
|
process.exit(1);
|
|
10
11
|
}
|
package/dist/cli/src/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import { onboardingCommand } from './commands/onboarding.js';
|
|
|
13
13
|
import { virtualOfficeCommand } from './commands/virtual-office.js';
|
|
14
14
|
import { jarvisCommand } from './commands/jarvis.js';
|
|
15
15
|
import { schedulerCommand } from './commands/scheduler.js';
|
|
16
|
+
import { reorganizeCommand } from './commands/reorganize.js';
|
|
16
17
|
import { findPackageRoot } from './utils/config.js';
|
|
17
18
|
function getVersion() {
|
|
18
19
|
try {
|
|
@@ -50,6 +51,10 @@ program
|
|
|
50
51
|
.command('list')
|
|
51
52
|
.description('List squads and skills')
|
|
52
53
|
.action(listCommand);
|
|
54
|
+
program
|
|
55
|
+
.command('reorganize')
|
|
56
|
+
.description('Reorganize squads into Setor > Grupo > Sessão > Squad hierarchy')
|
|
57
|
+
.action(reorganizeCommand);
|
|
53
58
|
program
|
|
54
59
|
.command('install <skill>')
|
|
55
60
|
.description('Install skill from registry')
|
|
@@ -22,6 +22,10 @@ export interface ScheduleConfig {
|
|
|
22
22
|
export interface SquadConfig {
|
|
23
23
|
squad: {
|
|
24
24
|
code: string;
|
|
25
|
+
setor?: string;
|
|
26
|
+
grupo?: string;
|
|
27
|
+
sessao?: string;
|
|
28
|
+
/** @deprecated Use setor/grupo/sessao instead. Kept for backwards compatibility. */
|
|
25
29
|
group?: string;
|
|
26
30
|
name: string;
|
|
27
31
|
description: string;
|
|
@@ -36,3 +40,4 @@ export interface SquadConfig {
|
|
|
36
40
|
};
|
|
37
41
|
}
|
|
38
42
|
export declare function loadSquad(squadDir: string): SquadConfig;
|
|
43
|
+
export declare function findSquadDir(squadsDir: string, code: string): string | null;
|
|
@@ -73,9 +73,15 @@ export function loadSquad(squadDir) {
|
|
|
73
73
|
schedule = { ...rawSchedule, enabled: false };
|
|
74
74
|
}
|
|
75
75
|
const group = squad.group;
|
|
76
|
+
const setor = squad.setor;
|
|
77
|
+
const grupo = squad.grupo;
|
|
78
|
+
const sessao = squad.sessao;
|
|
76
79
|
return {
|
|
77
80
|
squad: {
|
|
78
81
|
code: squad.code,
|
|
82
|
+
setor,
|
|
83
|
+
grupo,
|
|
84
|
+
sessao,
|
|
79
85
|
group,
|
|
80
86
|
name: squad.name,
|
|
81
87
|
description: squad.description,
|
|
@@ -88,3 +94,50 @@ export function loadSquad(squadDir) {
|
|
|
88
94
|
},
|
|
89
95
|
};
|
|
90
96
|
}
|
|
97
|
+
export function findSquadDir(squadsDir, code) {
|
|
98
|
+
if (!fs.existsSync(squadsDir))
|
|
99
|
+
return null;
|
|
100
|
+
const matches = [];
|
|
101
|
+
function walk(dir, depth) {
|
|
102
|
+
if (depth > 4)
|
|
103
|
+
return;
|
|
104
|
+
const yamlPath = path.join(dir, 'squad.yaml');
|
|
105
|
+
if (fs.existsSync(yamlPath)) {
|
|
106
|
+
// This is a squad directory — check its code, don't recurse further
|
|
107
|
+
try {
|
|
108
|
+
const raw = fs.readFileSync(yamlPath, 'utf-8');
|
|
109
|
+
const parsed = yaml.load(raw);
|
|
110
|
+
const squadCode = parsed?.squad?.code;
|
|
111
|
+
if (squadCode === code) {
|
|
112
|
+
matches.push(dir);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// Invalid YAML — skip
|
|
117
|
+
}
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
// No squad.yaml here — recurse into subdirectories
|
|
121
|
+
let entries;
|
|
122
|
+
try {
|
|
123
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
for (const entry of entries) {
|
|
129
|
+
if (!entry.isDirectory())
|
|
130
|
+
continue;
|
|
131
|
+
if (entry.name.startsWith('.') || entry.name.startsWith('_'))
|
|
132
|
+
continue;
|
|
133
|
+
walk(path.join(dir, entry.name), depth + 1);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
walk(squadsDir, 0);
|
|
137
|
+
if (matches.length === 0)
|
|
138
|
+
return null;
|
|
139
|
+
if (matches.length > 1) {
|
|
140
|
+
process.stderr.write(`Warning: duplicate squad code "${code}" found in: ${matches.join(', ')}. Using first match.\n`);
|
|
141
|
+
}
|
|
142
|
+
return matches[0];
|
|
143
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"squads-routes.d.ts","sourceRoot":"","sources":["../../src/api/squads-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"squads-routes.d.ts","sourceRoot":"","sources":["../../src/api/squads-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAIrE,UAAU,mBAAoB,SAAQ,oBAAoB;IACxD,SAAS,EAAE,MAAM,CAAC;CACnB;AA8HD,wBAAsB,YAAY,CAChC,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,IAAI,CAAC,CA8Df"}
|
|
@@ -1,61 +1,118 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { parse as parseYaml } from 'yaml';
|
|
4
|
-
function
|
|
4
|
+
function findSquadDir(squadsDir, code) {
|
|
5
5
|
if (!fs.existsSync(squadsDir))
|
|
6
|
-
return
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (entry.name.startsWith('.') || entry.name.startsWith('_'))
|
|
13
|
-
continue;
|
|
14
|
-
const yamlPath = path.join(squadsDir, entry.name, 'squad.yaml');
|
|
6
|
+
return null;
|
|
7
|
+
const matches = [];
|
|
8
|
+
function walk(dir, depth) {
|
|
9
|
+
if (depth > 4)
|
|
10
|
+
return;
|
|
11
|
+
const yamlPath = path.join(dir, 'squad.yaml');
|
|
15
12
|
if (fs.existsSync(yamlPath)) {
|
|
16
13
|
try {
|
|
17
14
|
const raw = fs.readFileSync(yamlPath, 'utf-8');
|
|
18
15
|
const parsed = parseYaml(raw);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
16
|
+
if (parsed?.squad?.code === code)
|
|
17
|
+
matches.push(dir);
|
|
18
|
+
}
|
|
19
|
+
catch { /* skip */ }
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
let entries;
|
|
23
|
+
try {
|
|
24
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
for (const entry of entries) {
|
|
30
|
+
if (!entry.isDirectory())
|
|
31
|
+
continue;
|
|
32
|
+
if (entry.name.startsWith('.') || entry.name.startsWith('_'))
|
|
33
|
+
continue;
|
|
34
|
+
walk(path.join(dir, entry.name), depth + 1);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
walk(squadsDir, 0);
|
|
38
|
+
return matches[0] ?? null;
|
|
39
|
+
}
|
|
40
|
+
function discoverSquads(squadsDir) {
|
|
41
|
+
if (!fs.existsSync(squadsDir))
|
|
42
|
+
return [];
|
|
43
|
+
const squads = [];
|
|
44
|
+
function walk(dir, depth) {
|
|
45
|
+
if (depth > 4)
|
|
46
|
+
return;
|
|
47
|
+
let entries;
|
|
48
|
+
try {
|
|
49
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
for (const entry of entries) {
|
|
55
|
+
if (!entry.isDirectory())
|
|
56
|
+
continue;
|
|
57
|
+
if (entry.name.startsWith('.') || entry.name.startsWith('_'))
|
|
58
|
+
continue;
|
|
59
|
+
const fullPath = path.join(dir, entry.name);
|
|
60
|
+
const yamlPath = path.join(fullPath, 'squad.yaml');
|
|
61
|
+
if (fs.existsSync(yamlPath)) {
|
|
62
|
+
// Squad directory — parse and push, don't recurse further
|
|
63
|
+
try {
|
|
64
|
+
const raw = fs.readFileSync(yamlPath, 'utf-8');
|
|
65
|
+
const parsed = parseYaml(raw);
|
|
66
|
+
const s = parsed?.squad;
|
|
67
|
+
if (s) {
|
|
68
|
+
const rawSteps = s.pipeline?.steps;
|
|
69
|
+
const steps = Array.isArray(rawSteps)
|
|
70
|
+
? rawSteps.map((st) => ({
|
|
71
|
+
id: st.id || '',
|
|
72
|
+
agent: st.agent || '',
|
|
73
|
+
label: st.label || '',
|
|
74
|
+
...(st.deliverFrom ? { deliverFrom: st.deliverFrom } : {}),
|
|
75
|
+
}))
|
|
76
|
+
: [];
|
|
77
|
+
squads.push({
|
|
78
|
+
code: typeof s.code === 'string' ? s.code : entry.name,
|
|
79
|
+
...(typeof s.setor === 'string' ? { setor: s.setor } : {}),
|
|
80
|
+
...(typeof s.grupo === 'string' ? { grupo: s.grupo } : {}),
|
|
81
|
+
...(typeof s.sessao === 'string' ? { sessao: s.sessao } : {}),
|
|
82
|
+
...(typeof s.group === 'string' ? { group: s.group } : {}),
|
|
83
|
+
name: typeof s.name === 'string' ? s.name : entry.name,
|
|
84
|
+
description: typeof s.description === 'string' ? s.description : '',
|
|
85
|
+
icon: typeof s.icon === 'string' ? s.icon : '📋',
|
|
86
|
+
agents: Array.isArray(s.agents)
|
|
87
|
+
? s.agents.map((a) => ({
|
|
88
|
+
id: a.id || a,
|
|
89
|
+
name: a.name || a.id || a,
|
|
90
|
+
icon: a.icon || 'robot',
|
|
91
|
+
}))
|
|
92
|
+
: [],
|
|
93
|
+
pipeline: { steps },
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
30
98
|
squads.push({
|
|
31
|
-
code:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
id: a.id || a,
|
|
38
|
-
name: a.name || a.id || a,
|
|
39
|
-
icon: a.icon || 'robot',
|
|
40
|
-
})) : [],
|
|
41
|
-
pipeline: { steps },
|
|
99
|
+
code: entry.name,
|
|
100
|
+
name: entry.name,
|
|
101
|
+
description: '',
|
|
102
|
+
icon: '📋',
|
|
103
|
+
agents: [],
|
|
104
|
+
pipeline: { steps: [] },
|
|
42
105
|
});
|
|
43
|
-
continue;
|
|
44
106
|
}
|
|
107
|
+
// Do NOT recurse into squad dirs
|
|
45
108
|
}
|
|
46
|
-
|
|
47
|
-
//
|
|
109
|
+
else {
|
|
110
|
+
// Not a squad dir — recurse to find nested squads
|
|
111
|
+
walk(fullPath, depth + 1);
|
|
48
112
|
}
|
|
49
113
|
}
|
|
50
|
-
squads.push({
|
|
51
|
-
code: entry.name,
|
|
52
|
-
name: entry.name,
|
|
53
|
-
description: '',
|
|
54
|
-
icon: '📋',
|
|
55
|
-
agents: [],
|
|
56
|
-
pipeline: { steps: [] },
|
|
57
|
-
});
|
|
58
114
|
}
|
|
115
|
+
walk(squadsDir, 0);
|
|
59
116
|
return squads;
|
|
60
117
|
}
|
|
61
118
|
export async function squadsRoutes(app, opts) {
|
|
@@ -67,8 +124,8 @@ export async function squadsRoutes(app, opts) {
|
|
|
67
124
|
// GET /api/squads/:name
|
|
68
125
|
app.get('/api/squads/:name', { preHandler: [app.requireAuth] }, async (request, reply) => {
|
|
69
126
|
const { name } = request.params;
|
|
70
|
-
const squadDir =
|
|
71
|
-
if (!
|
|
127
|
+
const squadDir = findSquadDir(squadsDir, name);
|
|
128
|
+
if (!squadDir) {
|
|
72
129
|
return reply.code(404).send({ error: 'Squad not found' });
|
|
73
130
|
}
|
|
74
131
|
const squads = discoverSquads(squadsDir);
|
|
@@ -88,7 +145,11 @@ export async function squadsRoutes(app, opts) {
|
|
|
88
145
|
// GET /api/squads/:name/state
|
|
89
146
|
app.get('/api/squads/:name/state', { preHandler: [app.requireAuth] }, async (request, reply) => {
|
|
90
147
|
const { name } = request.params;
|
|
91
|
-
const
|
|
148
|
+
const squadDir = findSquadDir(squadsDir, name);
|
|
149
|
+
if (!squadDir) {
|
|
150
|
+
return reply.code(404).send({ error: 'Squad not found' });
|
|
151
|
+
}
|
|
152
|
+
const statePath = path.join(squadDir, 'state.json');
|
|
92
153
|
if (!fs.existsSync(statePath)) {
|
|
93
154
|
return reply.code(404).send({ error: 'State not found' });
|
|
94
155
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"squads-routes.js","sourceRoot":"","sources":["../../src/api/squads-routes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"squads-routes.js","sourceRoot":"","sources":["../../src/api/squads-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -29,5 +29,36 @@ describe('file-watcher squad.yaml', () => {
|
|
|
29
29
|
expect(configEvents.length).toBeGreaterThanOrEqual(1);
|
|
30
30
|
expect(configEvents[0].squadName).toBe('test-squad');
|
|
31
31
|
});
|
|
32
|
+
it('should detect state.json changes in a 4-level nested squad directory', async () => {
|
|
33
|
+
const nestedDir = path.join(squadsDir, 'marketing', 'redes-sociais', 'instagram', 'publicador');
|
|
34
|
+
fs.mkdirSync(nestedDir, { recursive: true });
|
|
35
|
+
const stateFile = path.join(nestedDir, 'state.json');
|
|
36
|
+
fs.writeFileSync(stateFile, JSON.stringify({
|
|
37
|
+
squad: 'publicador',
|
|
38
|
+
status: 'idle',
|
|
39
|
+
step: { current: 0, total: 1, label: '' },
|
|
40
|
+
agents: [],
|
|
41
|
+
handoff: null,
|
|
42
|
+
startedAt: null,
|
|
43
|
+
updatedAt: new Date().toISOString(),
|
|
44
|
+
}));
|
|
45
|
+
const events = [];
|
|
46
|
+
const watcher = createFileWatcher(squadsDir, (event) => events.push(event));
|
|
47
|
+
await watcher.ready;
|
|
48
|
+
fs.writeFileSync(stateFile, JSON.stringify({
|
|
49
|
+
squad: 'publicador',
|
|
50
|
+
status: 'running',
|
|
51
|
+
step: { current: 1, total: 1, label: 'Working' },
|
|
52
|
+
agents: [],
|
|
53
|
+
handoff: null,
|
|
54
|
+
startedAt: new Date().toISOString(),
|
|
55
|
+
updatedAt: new Date().toISOString(),
|
|
56
|
+
}));
|
|
57
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
58
|
+
watcher.stop();
|
|
59
|
+
const stateEvents = events.filter((e) => e.type !== 'squad:inactive');
|
|
60
|
+
expect(stateEvents.length).toBeGreaterThanOrEqual(1);
|
|
61
|
+
expect(stateEvents.some((e) => e.squadName === 'publicador')).toBe(true);
|
|
62
|
+
});
|
|
32
63
|
});
|
|
33
64
|
//# sourceMappingURL=file-watcher.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-watcher.test.js","sourceRoot":"","sources":["../../../src/watcher/__tests__/file-watcher.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAM,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,IAAI,SAAiB,CAAC;IAEtB,UAAU,CAAC,GAAG,EAAE;QACd,SAAS,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QACpD,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,EAAE,wBAAwB,CAAC,CAAC;QAE9E,MAAM,MAAM,GAAU,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,iBAAiB,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;YACrD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;QAEH,MAAM,OAAO,CAAC,KAAK,CAAC;QAEpB,oBAAoB;QACpB,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,EAAE,yCAAyC,CAAC,CAAC;QAE/F,+BAA+B;QAC/B,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAE7C,OAAO,CAAC,IAAI,EAAE,CAAC;QAEf,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,sBAAsB,CAAC,CAAC;QAC7E,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QACtD,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"file-watcher.test.js","sourceRoot":"","sources":["../../../src/watcher/__tests__/file-watcher.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@ export function createFileWatcher(squadsDir, onEvent) {
|
|
|
8
8
|
// Watch entire squadsDir (chokidar v4 on macOS doesn't support glob patterns well)
|
|
9
9
|
const watcher = chokidar.watch(squadsDir, {
|
|
10
10
|
ignoreInitial: true,
|
|
11
|
-
depth:
|
|
11
|
+
depth: 5, // supports setor/grupo/sessao/code/state.json (4 levels below squadsDir)
|
|
12
12
|
});
|
|
13
13
|
function handleStateChange(filePath) {
|
|
14
14
|
const squadName = path.basename(path.dirname(filePath));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-watcher.js","sourceRoot":"","sources":["../../src/watcher/file-watcher.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAoC,MAAM,mBAAmB,CAAC;AAShF,MAAM,UAAU,iBAAiB,CAC/B,SAAiB,EACjB,OAAsB;IAEtB,MAAM,UAAU,GAAG,IAAI,GAAG,EAAsB,CAAC;IACjD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAyC,CAAC;IAExE,mFAAmF;IACnF,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,EAAE;QACxC,aAAa,EAAE,IAAI;QACnB,KAAK,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"file-watcher.js","sourceRoot":"","sources":["../../src/watcher/file-watcher.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAoC,MAAM,mBAAmB,CAAC;AAShF,MAAM,UAAU,iBAAiB,CAC/B,SAAiB,EACjB,OAAsB;IAEtB,MAAM,UAAU,GAAG,IAAI,GAAG,EAAsB,CAAC;IACjD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAyC,CAAC;IAExE,mFAAmF;IACnF,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,EAAE;QACxC,aAAa,EAAE,IAAI;QACnB,KAAK,EAAE,CAAC,EAAG,yEAAyE;KACrF,CAAC,CAAC;IAEH,SAAS,iBAAiB,CAAC,QAAgB;QACzC,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;QAExD,qBAAqB;QACrB,YAAY,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;QAC5C,cAAc,CAAC,GAAG,CAChB,SAAS,EACT,UAAU,CAAC,GAAG,EAAE;YACd,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7B,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBAC7B,OAAO,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,SAAS,EAAE,CAAC,CAAC;gBAC/C,OAAO;YACT,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBAC/C,MAAM,KAAK,GAAe,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC1C,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;gBAC/C,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;gBACjD,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;gBAEjC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;oBAC3B,OAAO,CAAC,KAAK,CAAC,CAAC;gBACjB,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,gDAAgD;YAClD,CAAC;QACH,CAAC,EAAE,EAAE,CAAC,CACP,CAAC;IACJ,CAAC;IAED,SAAS,WAAW,CAAC,QAAgB;QACnC,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,YAAY,CAAC;IAClD,CAAC;IAED,SAAS,WAAW,CAAC,QAAgB;QACnC,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,YAAY,CAAC;IAClD,CAAC;IAED,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE;QAChC,IAAI,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAC9B,CAAC;QACD,IAAI,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;YACxD,OAAO,CAAC,EAAE,IAAI,EAAE,sBAAsB,EAAE,SAAS,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,EAAE;QAC7B,IAAI,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAC9B,CAAC;QACD,IAAI,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;YACxD,OAAO,CAAC,EAAE,IAAI,EAAE,sBAAsB,EAAE,SAAS,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE;QAChC,IAAI,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;YACxD,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAC7B,OAAO,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,SAAS,EAAE,CAAC,CAAC;QACjD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAC1C,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,GAAG,EAAE;QAChB,KAAK,MAAM,KAAK,IAAI,cAAc,CAAC,MAAM,EAAE;YAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QACjE,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC"}
|