sinapse-ai 1.25.0 → 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/.claude/settings.json +170 -0
- package/.codex/catalog.json +1 -1
- package/.codex/scripts/sinapse-codex.js +0 -5
- package/.codex/scripts/sync-codex-native.js +4 -37
- package/.codex/scripts/validate-codex-native.js +13 -23
- package/.codex/tasks/onboard-sinapse-codex.md +1 -1
- package/.sinapse-ai/data/entity-registry.yaml +44 -18
- package/.sinapse-ai/install-manifest.yaml +3 -3
- package/CHANGELOG.md +8 -14
- package/README.en.md +38 -30
- package/README.md +33 -25
- package/bin/cli.js +8 -1
- package/bin/commands/help.js +3 -2
- package/bin/commands/install.js +25 -14
- package/bin/commands/status.js +4 -3
- package/bin/commands/uninstall.js +216 -51
- package/bin/commands/update.js +8 -4
- package/bin/lib/global-provider-adapters.js +73 -10
- package/bin/lib/provider-parity.js +22 -0
- package/bin/postinstall.js +11 -11
- package/docs/framework/codex-parity/codex-integration-process.md +6 -7
- package/docs/framework/codex-parity/codex-native-runtime-v2.md +8 -8
- package/docs/framework/codex-parity/codex-parity-program.md +4 -4
- package/docs/framework/codex-parity/codex-total-parity-orchestration-plan.md +1 -1
- package/docs/getting-started.md +13 -5
- package/docs/guides/codex-config.md +35 -51
- package/docs/guides/development-setup.md +1 -2
- package/docs/guides/ide-integration.md +28 -29
- package/docs/guides/project-status-feature.md +35 -55
- package/docs/guides/quality-gates.md +2 -2
- package/docs/guides/user-guide.md +21 -10
- package/docs/ide-integration.md +2 -2
- 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 +11 -5
- package/docs/installation/v4-quick-start.md +14 -14
- package/docs/installation/windows.md +11 -15
- package/docs/pt/contributing.md +1 -1
- package/docs/pt/guides/development-setup.md +1 -2
- package/docs/pt/guides/project-status-feature.md +35 -55
- package/docs/pt/guides/quality-gates.md +2 -2
- package/docs/pt/guides/user-guide.md +21 -11
- package/docs/pt/ide-integration.md +6 -6
- 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 +11 -10
- package/docs/pt/installation/v4-quick-start.md +17 -18
- package/docs/pt/installation/windows.md +8 -21
- package/docs/pt/platforms/claude-code.md +4 -4
- package/docs/sinapse-agent-flows/analyst-system.md +1 -1
- package/docs/sinapse-agent-flows/architect-system.md +1 -1
- package/docs/sinapse-agent-flows/data-engineer-system.md +1 -1
- package/docs/sinapse-agent-flows/dev-system.md +1 -1
- package/docs/sinapse-agent-flows/pm-system.md +1 -1
- package/docs/sinapse-agent-flows/qa-system.md +1 -1
- package/docs/sinapse-agent-flows/sm-system.md +1 -1
- package/docs/sinapse-agent-flows/snps-orqx-system.md +1 -1
- package/docs/sinapse-agent-flows/squad-creator-system.md +2 -2
- package/docs/sinapse-agent-flows/ux-design-expert-system.md +1 -1
- package/docs/troubleshooting.md +9 -7
- package/package.json +21 -16
- package/packages/installer/src/config/ide-configs.js +1 -1
- package/packages/installer/src/installer/sinapse-ai-installer.js +282 -10
- package/packages/installer/src/migrations/legacy-claude-agent-command-hashes.json +36 -0
- package/packages/installer/src/migrations/legacy-codex-native-skill-hashes.json +42 -0
- package/packages/installer/src/updater/index.js +24 -7
- package/packages/installer/src/wizard/ide-config-generator.js +4 -0
- package/packages/installer/src/wizard/index.js +6 -2
- package/scripts/validate-article-vii.js +305 -20
- package/scripts/validate-codex-command-registry.js +101 -0
- package/scripts/validate-install-docs.js +87 -3
- package/scripts/validate-provider-adapters.js +117 -1
- package/squads/claude-code-mastery/agents/skill-craftsman.md +2 -2
- package/squads/claude-code-mastery/knowledge-base/skill-creation-patterns.md +1 -1
- package/squads/squad-design/agents/ux-designer.md +1 -1
- package/.codex/skills/sinapse/SKILL.md +0 -10
- package/.codex/skills/sinapse-agent/SKILL.md +0 -22
- package/.codex/skills/sinapse-analyst/SKILL.md +0 -29
- package/.codex/skills/sinapse-animations/SKILL.md +0 -28
- package/.codex/skills/sinapse-architect/SKILL.md +0 -31
- package/.codex/skills/sinapse-brand/SKILL.md +0 -28
- package/.codex/skills/sinapse-claude/SKILL.md +0 -28
- package/.codex/skills/sinapse-cloning/SKILL.md +0 -28
- package/.codex/skills/sinapse-commercial/SKILL.md +0 -28
- package/.codex/skills/sinapse-content/SKILL.md +0 -28
- package/.codex/skills/sinapse-copy/SKILL.md +0 -28
- package/.codex/skills/sinapse-council/SKILL.md +0 -28
- package/.codex/skills/sinapse-courses/SKILL.md +0 -28
- package/.codex/skills/sinapse-cyber/SKILL.md +0 -28
- package/.codex/skills/sinapse-data-engineer/SKILL.md +0 -31
- package/.codex/skills/sinapse-design/SKILL.md +0 -28
- package/.codex/skills/sinapse-dev/SKILL.md +0 -31
- package/.codex/skills/sinapse-devops/SKILL.md +0 -31
- package/.codex/skills/sinapse-finance/SKILL.md +0 -28
- package/.codex/skills/sinapse-growth/SKILL.md +0 -28
- package/.codex/skills/sinapse-loop/SKILL.md +0 -35
- package/.codex/skills/sinapse-orqx/SKILL.md +0 -44
- package/.codex/skills/sinapse-paidmedia/SKILL.md +0 -28
- package/.codex/skills/sinapse-pm/SKILL.md +0 -31
- package/.codex/skills/sinapse-po/SKILL.md +0 -31
- package/.codex/skills/sinapse-product/SKILL.md +0 -28
- package/.codex/skills/sinapse-qa/SKILL.md +0 -31
- package/.codex/skills/sinapse-research/SKILL.md +0 -28
- package/.codex/skills/sinapse-sm/SKILL.md +0 -27
- package/.codex/skills/sinapse-spec-driven/SKILL.md +0 -35
- package/.codex/skills/sinapse-squad-creator/SKILL.md +0 -31
- package/.codex/skills/sinapse-storytelling/SKILL.md +0 -28
- package/.codex/skills/sinapse-swarm/SKILL.md +0 -28
- package/.codex/skills/sinapse-ux-design-expert/SKILL.md +0 -24
- package/.codex/skills/snps/SKILL.md +0 -10
- package/.codex/skills/snps-orqx/SKILL.md +0 -10
- /package/{.codex → .agents}/skills/react-bits-frontend/SKILL.md +0 -0
- /package/{.codex → .agents}/skills/react-bits-frontend/agents/openai.yaml +0 -0
- /package/{.codex → .agents}/skills/react-bits-frontend/references/corpus-map.md +0 -0
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const legacy = require('../.sinapse-ai/infrastructure/scripts/validate-codex-command-registry');
|
|
8
|
+
|
|
9
|
+
function resolveRegistryPath(projectRoot, declaredPath) {
|
|
10
|
+
if (typeof declaredPath !== 'string' || !declaredPath.trim() || path.isAbsolute(declaredPath)) return null;
|
|
11
|
+
const resolved = path.resolve(projectRoot, declaredPath);
|
|
12
|
+
const relative = path.relative(path.resolve(projectRoot), resolved);
|
|
13
|
+
if (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) return null;
|
|
14
|
+
return resolved;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function validateCodexCommandRegistry(options = {}) {
|
|
18
|
+
const projectRoot = options.projectRoot || process.cwd();
|
|
19
|
+
const { registryPath, registry, error } = legacy.loadRegistry(projectRoot);
|
|
20
|
+
const errors = [];
|
|
21
|
+
const requiredCoverage = options.requiredCoverage === false
|
|
22
|
+
? null
|
|
23
|
+
: options.requiredCoverage || legacy.REQUIRED_COMMAND_COVERAGE;
|
|
24
|
+
|
|
25
|
+
if (error) return { ok: false, errors: [error], warnings: [], metrics: { agents: 0, commands: 0 } };
|
|
26
|
+
|
|
27
|
+
let commandCount = 0;
|
|
28
|
+
const seenAgentAliases = new Map();
|
|
29
|
+
for (const [agentId, agentSpec] of Object.entries(registry.agents || {})) {
|
|
30
|
+
const skillPath = path.join(projectRoot, '.agents', 'skills', agentSpec.skillId || agentId, 'SKILL.md');
|
|
31
|
+
if (!fs.existsSync(skillPath)) {
|
|
32
|
+
errors.push(`${agentId}: missing skill file ${path.relative(projectRoot, skillPath)}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const sourceOfTruth = resolveRegistryPath(projectRoot, agentSpec.sourceOfTruth);
|
|
36
|
+
if (!sourceOfTruth) {
|
|
37
|
+
errors.push(`${agentId}: invalid or missing source of truth`);
|
|
38
|
+
} else if (!fs.existsSync(sourceOfTruth)) {
|
|
39
|
+
errors.push(`${agentId}: missing source of truth ${path.relative(projectRoot, sourceOfTruth)}`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for (const alias of legacy.collectAgentAliases(agentId, agentSpec)) {
|
|
43
|
+
const owner = seenAgentAliases.get(alias);
|
|
44
|
+
if (owner && owner !== agentId) errors.push(`duplicate agent alias "${alias}" claimed by ${owner} and ${agentId}`);
|
|
45
|
+
else seenAgentAliases.set(alias, agentId);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const seenCommandAliases = new Map();
|
|
49
|
+
for (const [commandId, commandSpec] of Object.entries(agentSpec.commands || {})) {
|
|
50
|
+
commandCount += 1;
|
|
51
|
+
const targetPath = resolveRegistryPath(projectRoot, commandSpec.target);
|
|
52
|
+
if (!targetPath) {
|
|
53
|
+
errors.push(`${agentId}.${commandId}: invalid or missing target`);
|
|
54
|
+
} else if (!fs.existsSync(targetPath)) {
|
|
55
|
+
errors.push(`${agentId}.${commandId}: missing target ${path.relative(projectRoot, targetPath)}`);
|
|
56
|
+
}
|
|
57
|
+
for (const resource of commandSpec.resources || []) {
|
|
58
|
+
const resourcePath = resolveRegistryPath(projectRoot, resource);
|
|
59
|
+
if (!resourcePath) {
|
|
60
|
+
errors.push(`${agentId}.${commandId}: invalid or missing resource`);
|
|
61
|
+
} else if (!fs.existsSync(resourcePath)) {
|
|
62
|
+
errors.push(`${agentId}.${commandId}: missing resource ${path.relative(projectRoot, resourcePath)}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (const alias of legacy.collectCommandAliases(commandId, commandSpec)) {
|
|
66
|
+
const owner = seenCommandAliases.get(alias);
|
|
67
|
+
if (owner && owner !== commandId) errors.push(`duplicate command alias "${alias}" claimed by ${owner} and ${commandId}`);
|
|
68
|
+
else seenCommandAliases.set(alias, commandId);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
legacy.validateRequiredCoverage(registry, requiredCoverage, errors);
|
|
74
|
+
return {
|
|
75
|
+
ok: errors.length === 0,
|
|
76
|
+
errors,
|
|
77
|
+
warnings: [],
|
|
78
|
+
metrics: {
|
|
79
|
+
agents: Object.keys(registry.agents || {}).length,
|
|
80
|
+
commands: commandCount,
|
|
81
|
+
registryPath: path.relative(projectRoot, registryPath),
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function main() {
|
|
87
|
+
const args = legacy.parseArgs();
|
|
88
|
+
const result = validateCodexCommandRegistry(args);
|
|
89
|
+
if (!args.quiet) {
|
|
90
|
+
console.log(args.json ? JSON.stringify(result, null, 2) : legacy.formatHumanReport(result));
|
|
91
|
+
}
|
|
92
|
+
if (!result.ok) process.exitCode = 1;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (require.main === module) main();
|
|
96
|
+
|
|
97
|
+
module.exports = {
|
|
98
|
+
...legacy,
|
|
99
|
+
resolveRegistryPath,
|
|
100
|
+
validateCodexCommandRegistry,
|
|
101
|
+
};
|
|
@@ -116,6 +116,76 @@ const FORBIDDEN_PATTERNS = [
|
|
|
116
116
|
reason:
|
|
117
117
|
'Internal script — must be invoked internally by `npx sinapse-ai install`, never shown as a user-facing command.',
|
|
118
118
|
},
|
|
119
|
+
{
|
|
120
|
+
id: 'legacy-codex-skills-flow',
|
|
121
|
+
regex: /(?:(?<![.:\w])codex\b[^\n]{0,80}(?<![A-Za-z0-9._-])\/skills\b|(?<![A-Za-z0-9._-])\/skills\b[^\n]{0,40}(?:flow|activation|ativacao|ativação|activate|ativar|agent))/i,
|
|
122
|
+
reason: 'Codex activation uses `$snps` or `$sinapse-agent <id>`, not `/skills`.',
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: 'legacy-custom-agent-slash-command',
|
|
126
|
+
regex: /\/my-agent\b/,
|
|
127
|
+
reason: 'Do not document `/my-agent`; use the provider-native SINAPSE activator.',
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
id: 'legacy-dev-slash-activation',
|
|
131
|
+
regex: /(?:^\s*\/dev\s*$|(?:activate|ativar|activation|ativacao|ativação|agent commands?|comandos? de agentes)[^\n]{0,80}\/dev\b)/i,
|
|
132
|
+
reason: 'Use `@developer` in Claude Code or `$sinapse-agent developer` in Codex.',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
id: 'legacy-dev-at-activation',
|
|
136
|
+
regex: /(?:^\s*(?:\|\s*)?`?@dev\b|(?:activate|ativar|activation|ativacao|ativação|agent commands?|comandos? de agentes)[^\n]{0,80}@dev\b)/i,
|
|
137
|
+
reason: 'Use `@developer`; the short `@dev` activation is obsolete.',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: 'legacy-codex-at-activation',
|
|
141
|
+
regex: /codex[^\n]{0,100}(?:activate|ativar|activation|ativacao|ativação|shortcut|atalho|use)[^\n]{0,50}@(?:<[^>]+>|[a-z][\w-]*)/i,
|
|
142
|
+
reason: 'Codex activation uses `$snps` or `$sinapse-agent <id>`, not `@agent`.',
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
id: 'unresolvable-init-project-status',
|
|
146
|
+
regex: /\*init-project-status\b/i,
|
|
147
|
+
reason: '`init-project-status` has no public resolvable task pointer; project status loads automatically.',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: 'legacy-sinapse-fullstack-name',
|
|
151
|
+
regex: /\bSINAPSE-FullStack\b/i,
|
|
152
|
+
reason: 'The current public framework name is SINAPSE AI.',
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
id: 'legacy-developer-codename',
|
|
156
|
+
regex: /(?:\bDex\s*(?:\(|the\s+)Builder\b|\b(?:developer agent|agente desenvolvedor)\s*\(\s*Dex\s*\)|@developer\s*\(\s*Dex\s*\))/i,
|
|
157
|
+
reason: 'The current developer persona is Pixel the Builder.',
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
id: 'unsupported-provider-full-support',
|
|
161
|
+
regex: /\b(?:Gemini\s+CLI|GitHub\s+Copilot)\b/i,
|
|
162
|
+
reason: 'Current public installation support is limited to Claude Code and Codex.',
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
id: 'unsupported-cursor-provider',
|
|
166
|
+
regex: /\bCursor\b/i,
|
|
167
|
+
reason: 'Current public installation support is limited to Claude Code and Codex.',
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
id: 'legacy-cursor-install-option',
|
|
171
|
+
regex: /--ide\s+cursor\b/i,
|
|
172
|
+
reason: 'The current installer generates Claude Code and Codex adapters; do not document the retired Cursor selector.',
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
id: 'legacy-cursor-rules-path',
|
|
176
|
+
regex: /\.cursor[\\/]rules[\\/]/i,
|
|
177
|
+
reason: 'Current provider adapter paths are `.claude/agents/`, `.codex/agents/`, and `.agents/skills/`.',
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
id: 'claude-commands-as-agent-config',
|
|
181
|
+
regex: /(?:\.claude[\\/]commands[\\/](?:SINAPSE[\\/]|[^\n]{0,60}(?:agent\s+configuration|configura(?:ç|c)ão\s+de\s+agentes|para\s+Claude\s+Code))|Claude\s+Code\s+(?:uses|usa)[^\n]{0,60}\.claude[\\/]commands[\\/])/i,
|
|
182
|
+
reason: 'Claude Code agent adapters live in `.claude/agents/`; `.claude/commands/` is not the agent configuration path.',
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: 'legacy-agent-name-slash-activation',
|
|
186
|
+
regex: /\/(?:agent-name|nome-do-agente)\b/i,
|
|
187
|
+
reason: 'Use `@agent-id` in Claude Code or `$sinapse-agent <id>` in Codex.',
|
|
188
|
+
},
|
|
119
189
|
];
|
|
120
190
|
|
|
121
191
|
// ── Paths ────────────────────────────────────────────────────────────────────
|
|
@@ -124,7 +194,7 @@ const FORBIDDEN_PATTERNS = [
|
|
|
124
194
|
* Directories whose `.md` files are public user-facing installation docs.
|
|
125
195
|
* Everything in these trees is scanned.
|
|
126
196
|
*/
|
|
127
|
-
const PUBLIC_DOC_DIRS = ['docs/installation'];
|
|
197
|
+
const PUBLIC_DOC_DIRS = ['docs/installation', 'docs/pt/installation'];
|
|
128
198
|
|
|
129
199
|
/**
|
|
130
200
|
* Additional top-level public doc files (relative to root).
|
|
@@ -133,7 +203,18 @@ const PUBLIC_DOC_DIRS = ['docs/installation'];
|
|
|
133
203
|
* Quick Start commands (including `agents`/`ideate`) and are exactly where
|
|
134
204
|
* the drift was found; bring them under the same guard as README.
|
|
135
205
|
*/
|
|
136
|
-
const PUBLIC_DOC_FILES = [
|
|
206
|
+
const PUBLIC_DOC_FILES = [
|
|
207
|
+
'README.md',
|
|
208
|
+
'README.en.md',
|
|
209
|
+
'docs/getting-started.md',
|
|
210
|
+
'docs/troubleshooting.md',
|
|
211
|
+
'docs/guides/user-guide.md',
|
|
212
|
+
'docs/pt/guides/user-guide.md',
|
|
213
|
+
'docs/guides/codex-config.md',
|
|
214
|
+
'docs/guides/ide-integration.md',
|
|
215
|
+
'docs/guides/project-status-feature.md',
|
|
216
|
+
'docs/pt/guides/project-status-feature.md',
|
|
217
|
+
];
|
|
137
218
|
|
|
138
219
|
/**
|
|
139
220
|
* Path fragments that identify historical / release notes. Any file whose
|
|
@@ -276,7 +357,10 @@ function scanFile(rootDir, relPath) {
|
|
|
276
357
|
if (allowed.has(i)) continue;
|
|
277
358
|
const line = lines[i];
|
|
278
359
|
for (const rule of FORBIDDEN_PATTERNS) {
|
|
279
|
-
const
|
|
360
|
+
const candidate = rule.id === 'legacy-codex-skills-flow'
|
|
361
|
+
? line.replace(/https?:\/\/[^\s)>]+/gi, (url) => ' '.repeat(url.length))
|
|
362
|
+
: line;
|
|
363
|
+
const match = candidate.match(rule.regex);
|
|
280
364
|
if (match) {
|
|
281
365
|
violations.push({
|
|
282
366
|
file: relPath,
|