sinapse-ai 1.25.1 → 1.25.2
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/.sinapse-ai/install-manifest.yaml +1 -1
- package/CHANGELOG.md +10 -8
- package/README.en.md +38 -30
- package/README.md +33 -25
- package/docs/getting-started.md +13 -5
- package/docs/guides/codex-config.md +35 -51
- package/docs/guides/ide-integration.md +22 -23
- package/docs/guides/project-status-feature.md +35 -55
- package/docs/guides/user-guide.md +21 -10
- package/docs/installation/README.md +4 -4
- package/docs/installation/faq.md +84 -70
- package/docs/installation/linux.md +11 -14
- package/docs/installation/macos.md +10 -4
- package/docs/installation/troubleshooting.md +10 -4
- package/docs/installation/v4-quick-start.md +13 -13
- package/docs/installation/windows.md +11 -15
- package/docs/pt/guides/project-status-feature.md +35 -55
- package/docs/pt/guides/user-guide.md +21 -11
- package/docs/pt/installation/README.md +2 -4
- package/docs/pt/installation/faq.md +54 -89
- package/docs/pt/installation/linux.md +9 -27
- package/docs/pt/installation/macos.md +8 -12
- package/docs/pt/installation/troubleshooting.md +10 -8
- package/docs/pt/installation/v4-quick-start.md +16 -16
- package/docs/pt/installation/windows.md +8 -21
- package/docs/troubleshooting.md +9 -7
- package/package.json +1 -1
- package/scripts/validate-article-vii.js +305 -20
- package/scripts/validate-install-docs.js +87 -3
|
@@ -109,24 +109,24 @@ Digite *help para ver comandos disponíveis.
|
|
|
109
109
|
|
|
110
110
|
## Passo 4: Explorar Agentes Disponíveis
|
|
111
111
|
|
|
112
|
-
|
|
|
112
|
+
| Ativação | Papel | Propósito |
|
|
113
113
|
| ------------------- | -------------------- | ---------------------------------- |
|
|
114
|
-
| `@
|
|
115
|
-
| `@
|
|
116
|
-
| `@architect` (
|
|
117
|
-
| `@
|
|
118
|
-
| `@devops` (
|
|
119
|
-
| `@
|
|
120
|
-
| `@
|
|
121
|
-
| `@analyst` (
|
|
114
|
+
| `@developer` (Pixel) | Desenvolvimento | Implementação de código, debugging |
|
|
115
|
+
| `@quality-gate` (Litmus) | Qualidade | Testes e validação |
|
|
116
|
+
| `@architect` (Stratum) | Arquitetura | Design de sistema e documentação |
|
|
117
|
+
| `@project-lead` (Beacon) | Product Manager | Requisitos e planejamento |
|
|
118
|
+
| `@devops` (Pipeline) | DevOps | Git push, criação de PR, CI/CD |
|
|
119
|
+
| `@product-lead` (Axis) | Product Owner | Validação de stories e backlog |
|
|
120
|
+
| `@sprint-lead` (Sync) | Scrum Master | Gerenciamento de sprint |
|
|
121
|
+
| `@analyst` (Scope) | Analista de Negócios | Análise de requisitos |
|
|
122
122
|
|
|
123
123
|
### Exemplo: Ativar Agente Desenvolvedor
|
|
124
124
|
|
|
125
|
-
```
|
|
126
|
-
@
|
|
125
|
+
```text
|
|
126
|
+
@developer
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
O agente desenvolvedor (
|
|
129
|
+
O agente desenvolvedor (Pixel) será ativado com uma saudação mostrando:
|
|
130
130
|
|
|
131
131
|
- Status do projeto
|
|
132
132
|
- Comandos rápidos
|
|
@@ -190,7 +190,7 @@ seu-projeto/
|
|
|
190
190
|
│ │ └── quality-gates/ # Camadas de validação de qualidade
|
|
191
191
|
│ ├── development/ # Assets de desenvolvimento
|
|
192
192
|
│ │ ├── agents/ # Definições de agentes (12 agentes)
|
|
193
|
-
│ │ ├── tasks/ # Workflows de
|
|
193
|
+
│ │ ├── tasks/ # Workflows de development (211 development tasks)
|
|
194
194
|
│ │ └── workflows/ # Workflows multi-etapa
|
|
195
195
|
│ ├── product/ # Assets de produto
|
|
196
196
|
│ │ ├── templates/ # Templates de documentos
|
|
@@ -232,9 +232,9 @@ npm cache clean --force
|
|
|
232
232
|
|
|
233
233
|
### Agente não responde
|
|
234
234
|
|
|
235
|
-
1. Certifique-se de estar
|
|
236
|
-
2.
|
|
237
|
-
3. Verifique
|
|
235
|
+
1. Certifique-se de estar usando Claude Code ou Codex CLI.
|
|
236
|
+
2. No Claude Code, use `@developer`; no Codex, use `$sinapse-agent developer` ou `$snps`.
|
|
237
|
+
3. Verifique `.claude/agents/` para Claude Code ou `.codex/agents/` e `.agents/skills/` para Codex.
|
|
238
238
|
|
|
239
239
|
### Erros de permissão
|
|
240
240
|
|
|
@@ -141,8 +141,8 @@ O instalador automaticamente:
|
|
|
141
141
|
- ✅ Detecta Windows e aplica configurações específicas da plataforma
|
|
142
142
|
- ✅ Cria diretórios necessários com permissões apropriadas
|
|
143
143
|
- ✅ Configura caminhos de IDE para localizações Windows:
|
|
144
|
-
-
|
|
145
|
-
-
|
|
144
|
+
- Agentes do Claude Code: `.claude\agents\`
|
|
145
|
+
- Agentes e skills do Codex: `.codex\agents\` e `.agents\skills\`
|
|
146
146
|
- ✅ Lida com separadores de caminho Windows (barras invertidas)
|
|
147
147
|
- ✅ Configura terminações de linha corretamente (CRLF para batch, LF para scripts)
|
|
148
148
|
- ✅ Configura scripts npm compatíveis com cmd.exe e PowerShell
|
|
@@ -151,28 +151,15 @@ O instalador automaticamente:
|
|
|
151
151
|
|
|
152
152
|
## Configuração Específica por IDE
|
|
153
153
|
|
|
154
|
-
###
|
|
154
|
+
### Claude Code
|
|
155
155
|
|
|
156
|
-
1.
|
|
157
|
-
2.
|
|
158
|
-
3. Regras da IDE são instaladas em `.cursor\rules\`
|
|
159
|
-
4. Atalho de teclado: `Ctrl+L` para abrir chat
|
|
160
|
-
5. Use `@nome-do-agente` para ativar agentes
|
|
156
|
+
1. Os adapters de agentes são instalados em `.claude\agents\`.
|
|
157
|
+
2. Use `@developer` ou outro ID canônico para ativar um agente.
|
|
161
158
|
|
|
162
|
-
###
|
|
159
|
+
### Codex
|
|
163
160
|
|
|
164
|
-
1.
|
|
165
|
-
|
|
166
|
-
```powershell
|
|
167
|
-
npm install -g @anthropic-ai/claude-code
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
2. Comandos são instalados em `.claude\commands\SINAPSE\`
|
|
171
|
-
3. Use `/nome-do-agente` para ativar agentes
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
2. Execute o instalador
|
|
175
|
-
4. Use `@nome-do-agente` para ativar agentes
|
|
161
|
+
1. Os descritores são instalados em `.codex\agents\`, com skills em `.agents\skills\`.
|
|
162
|
+
2. Use `$snps` para roteamento ou `$sinapse-agent developer` para ativação direta.
|
|
176
163
|
|
|
177
164
|
---
|
|
178
165
|
|
package/docs/troubleshooting.md
CHANGED
|
@@ -40,10 +40,11 @@ npx sinapse-ai install --target "C:\Users\My User\projeto"
|
|
|
40
40
|
|
|
41
41
|
## Problemas de ativação de agentes
|
|
42
42
|
|
|
43
|
-
###
|
|
44
|
-
1.
|
|
45
|
-
2.
|
|
46
|
-
3.
|
|
43
|
+
### O agente não ativa
|
|
44
|
+
1. Confirme a sintaxe do provider: `@developer` no Claude Code; `$snps` ou `$sinapse-agent developer` no Codex.
|
|
45
|
+
2. Verifique a configuração instalada: `.claude/settings.json` no Claude Code ou `.codex/config.toml` no Codex.
|
|
46
|
+
3. Re-sincronize: `npx sinapse-ai@latest install --reconfigure`.
|
|
47
|
+
4. Reinicie o provider.
|
|
47
48
|
|
|
48
49
|
### Agente ativa mas sem comandos
|
|
49
50
|
```bash
|
|
@@ -59,12 +60,13 @@ Cheque qual hook bloqueou (mensagem de erro tem o nome). Exemplos:
|
|
|
59
60
|
- **enforce-git-push-authority**: só `@devops` pode push. Delegue: `@devops *push`.
|
|
60
61
|
- **secret-scanning**: detectou secret. Verifique e remova OU mova pra `.env` (gitignored).
|
|
61
62
|
|
|
62
|
-
|
|
63
|
+
Claude Code registra 20 hooks em `.claude/settings.json`. Codex registra 9 eventos
|
|
64
|
+
de lifecycle em `.codex/hooks.json` e os encaminha pelo bridge de compatibilidade.
|
|
63
65
|
|
|
64
66
|
### Hook não está rodando
|
|
65
67
|
```bash
|
|
66
|
-
cat .claude/settings.json | grep hooks # confirma registro
|
|
67
|
-
|
|
68
|
+
cat .claude/settings.json | grep hooks # Claude Code: confirma registro
|
|
69
|
+
cat .codex/hooks.json # Codex: confirma eventos registrados
|
|
68
70
|
```
|
|
69
71
|
|
|
70
72
|
## Problemas de CI
|
package/package.json
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* @story GA-1.5 (Article gates VII/VIII/XI automated)
|
|
6
6
|
*
|
|
7
7
|
* Verifica que TODOS os documentos publicos referem aos MESMOS numeros de
|
|
8
|
-
* squads/agentes/orqx/tasks
|
|
9
|
-
*
|
|
8
|
+
* squads/agentes/orqx/tasks medidos pelas fontes canonicas em disco. Contagens
|
|
9
|
+
* gerais reutilizam `sync-counts`; o detalhamento resolvivel usa o ativador
|
|
10
|
+
* parametrico do Codex.
|
|
10
11
|
*
|
|
11
12
|
* Documentos verificados:
|
|
12
13
|
* - README.md
|
|
@@ -27,11 +28,14 @@
|
|
|
27
28
|
|
|
28
29
|
const fs = require('fs');
|
|
29
30
|
const path = require('path');
|
|
31
|
+
const { execFileSync } = require('child_process');
|
|
30
32
|
|
|
31
33
|
const { collectCounts } = require('./sync-counts.js');
|
|
34
|
+
const { validateProviderAdapters } = require('./validate-provider-adapters.js');
|
|
32
35
|
|
|
33
36
|
const ROOT = path.resolve(__dirname, '..');
|
|
34
37
|
const CONSTITUTION = path.join(ROOT, '.sinapse-ai', 'constitution.md');
|
|
38
|
+
const CODEX_RESOLVER = path.join(ROOT, '.codex', 'scripts', 'resolve-codex-agent.js');
|
|
35
39
|
|
|
36
40
|
/**
|
|
37
41
|
* Count Constitution articles + NON-NEGOTIABLE ones from the canonical source.
|
|
@@ -56,37 +60,189 @@ function collectConstitutionCounts() {
|
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
const TARGETS = [
|
|
59
|
-
{ file: 'README.md', label: 'README PT' },
|
|
60
|
-
{ file: 'README.en.md', label: 'README EN' },
|
|
63
|
+
{ file: 'README.md', label: 'README PT', requireTaskBreakdown: true },
|
|
64
|
+
{ file: 'README.en.md', label: 'README EN', requireTaskBreakdown: true },
|
|
61
65
|
{ file: 'AGENTS.md', label: 'AGENTS guide' },
|
|
66
|
+
{ file: 'docs/getting-started.md', label: 'Getting started' },
|
|
67
|
+
{ file: 'docs/troubleshooting.md', label: 'Troubleshooting' },
|
|
68
|
+
{ file: 'docs/guides/user-guide.md', label: 'User guide EN', requireAgentTotal: true },
|
|
69
|
+
{ file: 'docs/pt/guides/user-guide.md', label: 'User guide PT', requireAgentTotal: true },
|
|
70
|
+
{ file: 'docs/guides/codex-config.md', label: 'Codex configuration guide' },
|
|
71
|
+
{ file: 'docs/guides/ide-integration.md', label: 'IDE integration guide', requireProviderBreakdown: true },
|
|
72
|
+
{ file: 'docs/guides/project-status-feature.md', label: 'Project status guide EN', requireAgentTotal: true },
|
|
73
|
+
{ file: 'docs/pt/guides/project-status-feature.md', label: 'Project status guide PT', requireAgentTotal: true },
|
|
74
|
+
{ file: 'docs/installation/README.md', label: 'Installation index' },
|
|
75
|
+
{ file: 'docs/installation/faq.md', label: 'Installation FAQ' },
|
|
76
|
+
{ file: 'docs/installation/troubleshooting.md', label: 'Installation troubleshooting' },
|
|
77
|
+
{ file: 'docs/installation/v4-quick-start.md', label: 'Installation quick start' },
|
|
78
|
+
{ file: 'docs/pt/installation/README.md', label: 'Installation index PT' },
|
|
79
|
+
{ file: 'docs/pt/installation/faq.md', label: 'Installation FAQ PT' },
|
|
80
|
+
{ file: 'docs/pt/installation/troubleshooting.md', label: 'Installation troubleshooting PT' },
|
|
81
|
+
{ file: 'docs/pt/installation/v4-quick-start.md', label: 'Installation quick start PT' },
|
|
62
82
|
{ file: 'package.json', label: 'package.json description', jsonField: 'description' },
|
|
63
83
|
{ file: 'packages/installer/src/wizard/feedback.js', label: 'wizard feedback' },
|
|
64
84
|
];
|
|
65
85
|
|
|
86
|
+
function collectRuntimeTaskCounts(options = {}) {
|
|
87
|
+
const execute = options.execFileSync || execFileSync;
|
|
88
|
+
const resolverPath = options.resolverPath || CODEX_RESOLVER;
|
|
89
|
+
const timeout = options.timeoutMs ?? 10_000;
|
|
90
|
+
if (!Number.isInteger(timeout) || timeout <= 0) {
|
|
91
|
+
throw new Error('parametric resolver timeout must be a positive integer');
|
|
92
|
+
}
|
|
93
|
+
let raw;
|
|
94
|
+
try {
|
|
95
|
+
raw = execute(process.execPath, [resolverPath, '--stats'], {
|
|
96
|
+
cwd: ROOT,
|
|
97
|
+
encoding: 'utf8',
|
|
98
|
+
timeout,
|
|
99
|
+
});
|
|
100
|
+
} catch (error) {
|
|
101
|
+
throw new Error(`cannot execute the parametric resolver: ${error.message}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let stats;
|
|
105
|
+
try {
|
|
106
|
+
stats = JSON.parse(raw);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
throw new Error(`parametric resolver returned malformed JSON: ${error.message}`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const fields = {
|
|
112
|
+
squadTasks: stats.squadTaskFiles,
|
|
113
|
+
developmentTasks: stats.devTaskFiles,
|
|
114
|
+
totalTasks: stats.totalTaskFiles,
|
|
115
|
+
resolvableTasks: stats.resolvableTaskPointers,
|
|
116
|
+
};
|
|
117
|
+
for (const [name, value] of Object.entries(fields)) {
|
|
118
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
119
|
+
throw new Error(`parametric resolver field ${name} must be a positive integer`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (fields.totalTasks !== fields.squadTasks + fields.developmentTasks) {
|
|
123
|
+
throw new Error('parametric resolver totalTaskFiles does not equal squadTaskFiles + devTaskFiles');
|
|
124
|
+
}
|
|
125
|
+
if (fields.resolvableTasks > fields.totalTasks) {
|
|
126
|
+
throw new Error('parametric resolver resolvableTaskPointers exceeds totalTaskFiles');
|
|
127
|
+
}
|
|
128
|
+
if (
|
|
129
|
+
options.expectedSquadTasks !== undefined &&
|
|
130
|
+
fields.squadTasks !== options.expectedSquadTasks
|
|
131
|
+
) {
|
|
132
|
+
throw new Error(
|
|
133
|
+
`parametric resolver squadTaskFiles ${fields.squadTasks} does not match ` +
|
|
134
|
+
`sync-counts tasks ${options.expectedSquadTasks}`,
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
return fields;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function countHookRegistrations(settings, label) {
|
|
141
|
+
if (!settings || typeof settings !== 'object' || Array.isArray(settings)) {
|
|
142
|
+
throw new Error(`${label} hook settings must be an object`);
|
|
143
|
+
}
|
|
144
|
+
const hooks = settings.hooks;
|
|
145
|
+
if (!hooks || typeof hooks !== 'object' || Array.isArray(hooks)) {
|
|
146
|
+
throw new Error(`${label} hook settings are missing hooks`);
|
|
147
|
+
}
|
|
148
|
+
let count = 0;
|
|
149
|
+
for (const groups of Object.values(hooks)) {
|
|
150
|
+
if (!Array.isArray(groups)) throw new Error(`${label} hook groups must be arrays`);
|
|
151
|
+
for (const group of groups) {
|
|
152
|
+
if (!group || !Array.isArray(group.hooks)) {
|
|
153
|
+
throw new Error(`${label} hook registration is malformed`);
|
|
154
|
+
}
|
|
155
|
+
count += group.hooks.length;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (count === 0) throw new Error(`${label} hook settings contain no registrations`);
|
|
159
|
+
return count;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function collectProviderSurfaceCounts(options = {}) {
|
|
163
|
+
const validateProviders = options.validateProviderAdapters || validateProviderAdapters;
|
|
164
|
+
const readJson = options.readJson || ((filePath) => JSON.parse(fs.readFileSync(filePath, 'utf8')));
|
|
165
|
+
const result = validateProviders(ROOT);
|
|
166
|
+
if (!result || result.ok !== true || !result.metrics) {
|
|
167
|
+
const detail = result && Array.isArray(result.errors) ? result.errors.join('; ') : 'invalid result';
|
|
168
|
+
throw new Error(`provider adapter validation failed: ${detail}`);
|
|
169
|
+
}
|
|
170
|
+
const claudeSkills = result.metrics.claudeSkills;
|
|
171
|
+
const codexSkills = result.metrics.codexSkills;
|
|
172
|
+
for (const [name, value] of Object.entries({ claudeSkills, codexSkills })) {
|
|
173
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
174
|
+
throw new Error(`provider metric ${name} must be a positive integer`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const claudeHooks = countHookRegistrations(
|
|
178
|
+
readJson(path.join(ROOT, '.claude', 'settings.json')),
|
|
179
|
+
'Claude',
|
|
180
|
+
);
|
|
181
|
+
const codexSettings = readJson(path.join(ROOT, '.codex', 'hooks.json'));
|
|
182
|
+
if (
|
|
183
|
+
!codexSettings ||
|
|
184
|
+
typeof codexSettings !== 'object' ||
|
|
185
|
+
!codexSettings.hooks ||
|
|
186
|
+
typeof codexSettings.hooks !== 'object' ||
|
|
187
|
+
Array.isArray(codexSettings.hooks) ||
|
|
188
|
+
Object.values(codexSettings.hooks).some((groups) => !Array.isArray(groups))
|
|
189
|
+
) {
|
|
190
|
+
throw new Error('Codex hook settings are malformed');
|
|
191
|
+
}
|
|
192
|
+
const codexHookEvents = Object.keys(codexSettings.hooks).length;
|
|
193
|
+
if (codexHookEvents === 0) {
|
|
194
|
+
throw new Error('Codex hook settings contain no lifecycle events');
|
|
195
|
+
}
|
|
196
|
+
return { claudeSkills, codexSkills, claudeHooks, codexHookEvents };
|
|
197
|
+
}
|
|
198
|
+
|
|
66
199
|
/**
|
|
67
200
|
* Build the set of expected numeric tokens that MUST appear consistently.
|
|
68
201
|
* Returns an object describing canonical counts and a regex helper.
|
|
69
202
|
*/
|
|
70
|
-
function buildExpectations(
|
|
203
|
+
function buildExpectations(
|
|
204
|
+
counts,
|
|
205
|
+
constitution = { articles: 0, nonNegotiable: 0 },
|
|
206
|
+
runtimeTasks = {},
|
|
207
|
+
providerSurfaces = {},
|
|
208
|
+
) {
|
|
71
209
|
return {
|
|
72
210
|
squads: counts.squads,
|
|
73
211
|
agents: counts.totalAgents,
|
|
74
212
|
orqx: counts.totalOrqx,
|
|
75
213
|
tasks: counts.tasks,
|
|
214
|
+
squadTasks: runtimeTasks.squadTasks ?? counts.tasks,
|
|
215
|
+
developmentTasks: runtimeTasks.developmentTasks ?? 0,
|
|
216
|
+
totalTasks: runtimeTasks.totalTasks ?? counts.tasks,
|
|
217
|
+
resolvableTasks: runtimeTasks.resolvableTasks ?? 0,
|
|
218
|
+
claudeSkills: providerSurfaces.claudeSkills ?? 0,
|
|
219
|
+
codexSkills: providerSurfaces.codexSkills ?? 0,
|
|
220
|
+
claudeHooks: providerSurfaces.claudeHooks ?? 0,
|
|
221
|
+
codexHookEvents: providerSurfaces.codexHookEvents ?? 0,
|
|
76
222
|
articles: constitution.articles,
|
|
77
223
|
nonNegotiable: constitution.nonNegotiable,
|
|
78
224
|
};
|
|
79
225
|
}
|
|
80
226
|
|
|
227
|
+
function parseMetric(raw) {
|
|
228
|
+
return parseInt(String(raw).replace(/[.,]/g, ''), 10);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function metricPattern(value) {
|
|
232
|
+
const digits = String(value);
|
|
233
|
+
if (digits.length <= 3) return digits;
|
|
234
|
+
return `${digits}|${digits.slice(0, -3)}[.,]${digits.slice(-3)}`;
|
|
235
|
+
}
|
|
236
|
+
|
|
81
237
|
/**
|
|
82
238
|
* Extract numeric counts that look like squads/agents/orqx/tasks claims.
|
|
83
239
|
* Returns drift findings (what the doc claims vs what is canonical).
|
|
84
240
|
*/
|
|
85
|
-
function findDrift(content, expected) {
|
|
241
|
+
function findDrift(content, expected, options = {}) {
|
|
86
242
|
const findings = [];
|
|
87
243
|
|
|
88
244
|
// Squads: "<N> squads" or "<N> squad"
|
|
89
|
-
const squadsRe =
|
|
245
|
+
const squadsRe = /(?<![\d.,])(\d{1,4})\s+squads?\b/gi;
|
|
90
246
|
for (const m of content.matchAll(squadsRe)) {
|
|
91
247
|
const n = parseInt(m[1], 10);
|
|
92
248
|
if (n !== expected.squads && n >= 5) {
|
|
@@ -96,7 +252,7 @@ function findDrift(content, expected) {
|
|
|
96
252
|
}
|
|
97
253
|
|
|
98
254
|
// Agents/agentes: "<N> agentes" or "<N> agents"
|
|
99
|
-
const agentsRe =
|
|
255
|
+
const agentsRe = /(?<![\d.,])(\d{1,4})\s+(agentes|agents)\b/gi;
|
|
100
256
|
for (const m of content.matchAll(agentsRe)) {
|
|
101
257
|
const n = parseInt(m[1], 10);
|
|
102
258
|
if (n !== expected.agents && n >= 50) {
|
|
@@ -104,13 +260,115 @@ function findDrift(content, expected) {
|
|
|
104
260
|
}
|
|
105
261
|
}
|
|
106
262
|
|
|
107
|
-
|
|
108
|
-
|
|
263
|
+
const scopedTaskPatterns = [
|
|
264
|
+
{ kind: 'squad tasks', expected: expected.squadTasks, re: /(?<![\d.,])(\d{1,3}(?:[.,]\d{3})?|\d{4,5})\s+squad\s+tasks\b/gi },
|
|
265
|
+
{ kind: 'development tasks', expected: expected.developmentTasks, re: /(?<![\d.,])(\d{1,3}(?:[.,]\d{3})?|\d{4,5})\s+development\s+tasks\b/gi },
|
|
266
|
+
{ kind: 'total task files', expected: expected.totalTasks, re: /(?<![\d.,])(\d{1,3}(?:[.,]\d{3})?|\d{4,5})\s+task\s+files\b/gi },
|
|
267
|
+
{ kind: 'resolvable task pointers', expected: expected.resolvableTasks, re: /(?<![\d.,])(\d{1,3}(?:[.,]\d{3})?|\d{4,5})\s+(?:ponteiros|pointers)[^.\n]{0,30}resolv/gi },
|
|
268
|
+
];
|
|
269
|
+
for (const metric of scopedTaskPatterns) {
|
|
270
|
+
if (!metric.expected) continue;
|
|
271
|
+
for (const m of content.matchAll(metric.re)) {
|
|
272
|
+
const n = parseMetric(m[1]);
|
|
273
|
+
if (n !== metric.expected) {
|
|
274
|
+
findings.push({ kind: metric.kind, found: n, expected: metric.expected, snippet: m[0].trim() });
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Generic task claims may refer to squad, development, total, or resolvable
|
|
280
|
+
// files. Scoped phrases above enforce the meaning of each metric.
|
|
281
|
+
const tasksRe = /(?<![\d.,])(\d{1,3}(?:[.,]\d{3})?|\d{4,5})\s+tasks\b/gi;
|
|
282
|
+
const acceptedTaskCounts = new Set([
|
|
283
|
+
expected.squadTasks,
|
|
284
|
+
expected.developmentTasks,
|
|
285
|
+
expected.totalTasks,
|
|
286
|
+
expected.resolvableTasks,
|
|
287
|
+
].filter(Boolean));
|
|
109
288
|
for (const m of content.matchAll(tasksRe)) {
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
289
|
+
const n = parseMetric(m[1]);
|
|
290
|
+
if (!acceptedTaskCounts.has(n) && n >= 100) {
|
|
291
|
+
findings.push({ kind: 'tasks', found: n, expected: expected.totalTasks, snippet: m[0] });
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (options.requireTaskBreakdown) {
|
|
296
|
+
const required = [
|
|
297
|
+
['squad tasks', expected.squadTasks, 'squad\\s+tasks'],
|
|
298
|
+
['development tasks', expected.developmentTasks, 'development\\s+tasks'],
|
|
299
|
+
['total task files', expected.totalTasks, 'task\\s+files'],
|
|
300
|
+
['resolvable task pointers', expected.resolvableTasks, '(?:ponteiros|pointers)[^.\\n]{0,30}resolv'],
|
|
301
|
+
];
|
|
302
|
+
for (const [kind, value, suffix] of required) {
|
|
303
|
+
if (!value) continue;
|
|
304
|
+
const re = new RegExp(`\\b(?:${metricPattern(value)})\\s+${suffix}`, 'i');
|
|
305
|
+
if (!re.test(content)) {
|
|
306
|
+
findings.push({ kind: `${kind} (missing)`, found: null, expected: value, snippet: 'claim ausente' });
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const skillsClaim = content.match(/(?:Skills\s+instaladas|Installed\s+skills)\s*\|\s*(\d+)\s*\|\s*(\d+)/i);
|
|
312
|
+
if (skillsClaim) {
|
|
313
|
+
for (const [kind, found, wanted] of [
|
|
314
|
+
['Claude skills', Number(skillsClaim[1]), expected.claudeSkills],
|
|
315
|
+
['Codex skills', Number(skillsClaim[2]), expected.codexSkills],
|
|
316
|
+
]) {
|
|
317
|
+
if (wanted && found !== wanted) findings.push({ kind, found, expected: wanted, snippet: skillsClaim[0] });
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
const hooksClaim = content.match(/(?:Hooks\s+registrados|Registered\s+hooks)\s*\|\s*(\d+)\s+(?:registros|native\s+registrations)[^|]*\|\s*(\d+)\s+(?:eventos|lifecycle\s+events)/i);
|
|
321
|
+
if (hooksClaim) {
|
|
322
|
+
for (const [kind, found, wanted] of [
|
|
323
|
+
['Claude hook registrations', Number(hooksClaim[1]), expected.claudeHooks],
|
|
324
|
+
['Codex hook events', Number(hooksClaim[2]), expected.codexHookEvents],
|
|
325
|
+
]) {
|
|
326
|
+
if (wanted && found !== wanted) findings.push({ kind, found, expected: wanted, snippet: hooksClaim[0] });
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
const hookProseRe = /(?<![\d.,])(\d{1,3})\s+(?:Claude\s+Code\s+hook\s+registrations?|hooks?\s+(?:registrados?|ativos?)|(?:(?:active|registered|enforcement)\s+)(?:(?:Claude(?:\s+Code)?|native(?:\s+Claude(?:\s+Code)?)?)\s+)?hooks|hooks)\b/gi;
|
|
330
|
+
for (const claim of content.matchAll(hookProseRe)) {
|
|
331
|
+
const found = Number(claim[1]);
|
|
332
|
+
if (expected.claudeHooks && found !== expected.claudeHooks) {
|
|
333
|
+
findings.push({
|
|
334
|
+
kind: 'Claude hook registrations',
|
|
335
|
+
found,
|
|
336
|
+
expected: expected.claudeHooks,
|
|
337
|
+
snippet: claim[0],
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
const codexLifecycleProseRe = /(?<![\d.,])(\d{1,3})\s+(?:(?:Codex\s+)?lifecycle\s+events?|eventos\s+de\s+lifecycle)\b/gi;
|
|
342
|
+
for (const claim of content.matchAll(codexLifecycleProseRe)) {
|
|
343
|
+
const found = Number(claim[1]);
|
|
344
|
+
if (expected.codexHookEvents && found !== expected.codexHookEvents) {
|
|
345
|
+
findings.push({
|
|
346
|
+
kind: 'Codex hook events',
|
|
347
|
+
found,
|
|
348
|
+
expected: expected.codexHookEvents,
|
|
349
|
+
snippet: claim[0],
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
if (options.requireProviderBreakdown) {
|
|
354
|
+
if (!skillsClaim) findings.push({ kind: 'provider skills (missing)', found: null, expected: `${expected.claudeSkills}/${expected.codexSkills}`, snippet: 'claim ausente' });
|
|
355
|
+
if (!hooksClaim) findings.push({ kind: 'provider hooks (missing)', found: null, expected: `${expected.claudeHooks}/${expected.codexHookEvents}`, snippet: 'claim ausente' });
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (options.requireAgentTotal) {
|
|
359
|
+
const expectedAgentPattern = metricPattern(expected.agents);
|
|
360
|
+
const agentClaim = new RegExp(
|
|
361
|
+
'(?:SINAPSE\\s+(?:includes|inclui)|O\\s+SINAPSE\\s+inclui)[^.\\n]{0,40}' +
|
|
362
|
+
`\\b(?:${expectedAgentPattern})\\s+(?:specialized\\s+agents|agentes\\s+especializados)`,
|
|
363
|
+
'i',
|
|
364
|
+
);
|
|
365
|
+
if (!agentClaim.test(content)) {
|
|
366
|
+
findings.push({
|
|
367
|
+
kind: 'global agent total (missing)',
|
|
368
|
+
found: null,
|
|
369
|
+
expected: expected.agents,
|
|
370
|
+
snippet: 'claim ausente',
|
|
371
|
+
});
|
|
114
372
|
}
|
|
115
373
|
}
|
|
116
374
|
|
|
@@ -171,14 +429,28 @@ function main() {
|
|
|
171
429
|
|
|
172
430
|
const counts = collectCounts();
|
|
173
431
|
const constitution = collectConstitutionCounts();
|
|
174
|
-
|
|
432
|
+
let runtimeTasks;
|
|
433
|
+
let providerSurfaces;
|
|
434
|
+
try {
|
|
435
|
+
runtimeTasks = collectRuntimeTaskCounts({ expectedSquadTasks: counts.tasks });
|
|
436
|
+
providerSurfaces = collectProviderSurfaceCounts();
|
|
437
|
+
} catch (error) {
|
|
438
|
+
console.error(`FALHA - nao foi possivel medir as metricas canonicas: ${error.message}`);
|
|
439
|
+
process.exit(1);
|
|
440
|
+
}
|
|
441
|
+
const expected = buildExpectations(counts, constitution, runtimeTasks, providerSurfaces);
|
|
175
442
|
|
|
176
443
|
console.log('Article VII (Metrics Accuracy) — validacao de drift');
|
|
177
|
-
console.log('Numeros canonicos (
|
|
444
|
+
console.log('Numeros canonicos (medidos das fontes em disco):');
|
|
178
445
|
console.log(` squads ${expected.squads}`);
|
|
179
446
|
console.log(` agentes ${expected.agents}`);
|
|
180
447
|
console.log(` orqx ${expected.orqx}`);
|
|
181
|
-
console.log(` tasks
|
|
448
|
+
console.log(` squad tasks ${expected.squadTasks}`);
|
|
449
|
+
console.log(` dev tasks ${expected.developmentTasks}`);
|
|
450
|
+
console.log(` task files ${expected.totalTasks}`);
|
|
451
|
+
console.log(` resolvable ${expected.resolvableTasks}`);
|
|
452
|
+
console.log(` skills C/Codex ${expected.claudeSkills}/${expected.codexSkills}`);
|
|
453
|
+
console.log(` hooks C/Codex ${expected.claudeHooks}/${expected.codexHookEvents}`);
|
|
182
454
|
console.log(` artigos ${expected.articles}`);
|
|
183
455
|
console.log(` NON-NEGOTIABLE ${expected.nonNegotiable}`);
|
|
184
456
|
console.log('');
|
|
@@ -191,7 +463,12 @@ function main() {
|
|
|
191
463
|
console.log(` [skip] ${target.file} nao encontrado`);
|
|
192
464
|
continue;
|
|
193
465
|
}
|
|
194
|
-
const drift = findDrift(content, expected
|
|
466
|
+
const drift = findDrift(content, expected, {
|
|
467
|
+
requireTaskBreakdown: target.requireTaskBreakdown === true,
|
|
468
|
+
requireProviderBreakdown:
|
|
469
|
+
target.requireTaskBreakdown === true || target.requireProviderBreakdown === true,
|
|
470
|
+
requireAgentTotal: target.requireAgentTotal === true,
|
|
471
|
+
});
|
|
195
472
|
if (drift.length === 0) {
|
|
196
473
|
console.log(` [ok] ${target.file}`);
|
|
197
474
|
} else {
|
|
@@ -214,7 +491,7 @@ function main() {
|
|
|
214
491
|
console.log('');
|
|
215
492
|
console.log('Acao corretiva (Article VII NON-NEGOTIABLE):');
|
|
216
493
|
console.log(' 1. Atualize cada arquivo listado acima com os numeros canonicos.');
|
|
217
|
-
console.log(' 2.
|
|
494
|
+
console.log(' 2. Se o inventario mudou, rode `npm run sync:counts`.');
|
|
218
495
|
console.log(' 3. Rode `npm run validate:article-vii` novamente para confirmar.');
|
|
219
496
|
|
|
220
497
|
if (fixMode) {
|
|
@@ -234,4 +511,12 @@ if (require.main === module) {
|
|
|
234
511
|
main();
|
|
235
512
|
}
|
|
236
513
|
|
|
237
|
-
module.exports = {
|
|
514
|
+
module.exports = {
|
|
515
|
+
findDrift,
|
|
516
|
+
buildExpectations,
|
|
517
|
+
collectConstitutionCounts,
|
|
518
|
+
collectRuntimeTaskCounts,
|
|
519
|
+
collectProviderSurfaceCounts,
|
|
520
|
+
countHookRegistrations,
|
|
521
|
+
TARGETS,
|
|
522
|
+
};
|