aios-core 4.2.3 → 4.2.5
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/.aios-core/core/registry/service-registry.json +6466 -6586
- package/.aios-core/core-config.yaml +10 -5
- package/.aios-core/data/aios-kb.md +19 -25
- package/.aios-core/data/entity-registry.yaml +311 -204
- package/.aios-core/data/registry-update-log.jsonl +14 -0
- package/.aios-core/development/tasks/db-squad-integration.md +3 -3
- package/.aios-core/development/tasks/dev-develop-story.md +1 -1
- package/.aios-core/development/tasks/integrate-squad.md +1 -1
- package/.aios-core/development/tasks/pr-automation.md +3 -3
- package/.aios-core/development/tasks/squad-creator-migrate.md +1 -1
- package/.aios-core/development/tasks/squad-creator-sync-ide-command.md +0 -2
- package/.aios-core/development/tasks/update-aios.md +2 -2
- package/.aios-core/development/tasks/validate-next-story.md +2 -99
- package/.aios-core/development/workflows/README.md +0 -4
- package/.aios-core/docs/standards/AIOS-COLOR-PALETTE-V2.1.md +0 -1
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-COMPLETE.md +3 -3
- package/.aios-core/docs/standards/QUALITY-GATES-SPECIFICATION.md +1 -1
- package/.aios-core/docs/standards/STANDARDS-INDEX.md +4 -4
- package/.aios-core/docs/standards/STORY-TEMPLATE-V2-SPECIFICATION.md +2 -2
- package/.aios-core/framework-config.yaml +8 -4
- package/.aios-core/infrastructure/scripts/ide-sync/README.md +29 -5
- package/.aios-core/infrastructure/scripts/ide-sync/gemini-commands.js +205 -0
- package/.aios-core/infrastructure/scripts/ide-sync/index.js +48 -11
- package/.aios-core/infrastructure/scripts/ide-sync/redirect-generator.js +1 -1
- package/.aios-core/infrastructure/scripts/test-utilities.js +1 -1
- package/.aios-core/infrastructure/scripts/tool-resolver.js +2 -2
- package/.aios-core/infrastructure/scripts/validate-claude-integration.js +101 -0
- package/.aios-core/infrastructure/scripts/validate-codex-integration.js +141 -0
- package/.aios-core/infrastructure/scripts/validate-gemini-integration.js +151 -0
- package/.aios-core/infrastructure/scripts/validate-parity.js +119 -0
- package/.aios-core/infrastructure/templates/aios-sync.yaml.template +0 -11
- package/.aios-core/install-manifest.yaml +83 -71
- package/.aios-core/local-config.yaml.template +2 -1
- package/.aios-core/presets/README.md +0 -1
- package/.aios-core/product/data/integration-patterns.md +1 -1
- package/.aios-core/product/templates/ide-rules/gemini-rules.md +87 -233
- package/.aios-core/product/templates/statusline/statusline-script.js +188 -0
- package/.aios-core/product/templates/statusline/track-agent.sh +68 -0
- package/.aios-core/user-guide.md +14 -19
- package/LICENSE +0 -27
- package/README.md +42 -6
- package/bin/aios-init.js +98 -54
- package/bin/modules/env-config.js +0 -1
- package/package.json +19 -5
- package/packages/gemini-aios-extension/README.md +13 -8
- package/packages/gemini-aios-extension/commands/aios-agent.js +7 -0
- package/packages/gemini-aios-extension/commands/aios-agents.js +2 -1
- package/packages/gemini-aios-extension/commands/aios-analyst.js +6 -0
- package/packages/gemini-aios-extension/commands/aios-architect.js +6 -0
- package/packages/gemini-aios-extension/commands/aios-data-engineer.js +6 -0
- package/packages/gemini-aios-extension/commands/aios-dev.js +6 -0
- package/packages/gemini-aios-extension/commands/aios-devops.js +6 -0
- package/packages/gemini-aios-extension/commands/aios-master.js +6 -0
- package/packages/gemini-aios-extension/commands/aios-menu.js +6 -0
- package/packages/gemini-aios-extension/commands/aios-pm.js +6 -0
- package/packages/gemini-aios-extension/commands/aios-po.js +6 -0
- package/packages/gemini-aios-extension/commands/aios-qa.js +6 -0
- package/packages/gemini-aios-extension/commands/aios-sm.js +6 -0
- package/packages/gemini-aios-extension/commands/aios-squad-creator.js +6 -0
- package/packages/gemini-aios-extension/commands/aios-ux-design-expert.js +6 -0
- package/packages/gemini-aios-extension/commands/lib/agent-launcher.js +138 -0
- package/packages/gemini-aios-extension/extension.json +70 -0
- package/packages/gemini-aios-extension/gemini-extension.json +147 -0
- package/packages/gemini-aios-extension/hooks/hooks.json +67 -65
- package/packages/installer/src/config/ide-configs.js +10 -10
- package/packages/installer/src/config/templates/core-config-template.js +6 -3
- package/packages/installer/src/wizard/ide-config-generator.js +373 -2
- package/packages/installer/src/wizard/ide-selector.js +1 -1
- package/pro/README.md +66 -0
- package/pro/license/degradation.js +220 -0
- package/pro/license/errors.js +450 -0
- package/pro/license/feature-gate.js +354 -0
- package/pro/license/index.js +181 -0
- package/pro/license/license-api.js +617 -0
- package/pro/license/license-cache.js +523 -0
- package/pro/license/license-crypto.js +303 -0
- package/scripts/code-intel-health-check.js +125 -125
- package/scripts/ensure-manifest.js +58 -0
- package/.aios-core/infrastructure/scripts/ide-sync/transformers/windsurf.js +0 -106
- package/.aios-core/product/templates/ide-rules/cline-rules.md +0 -84
- package/.aios-core/product/templates/ide-rules/roo-rules.md +0 -86
- package/.aios-core/product/templates/ide-rules/windsurf-rules.md +0 -80
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const FALLBACK_DESCRIPTION = 'Agente especializado AIOS';
|
|
7
|
+
const MAX_DESCRIPTION_CONTEXT = 120;
|
|
8
|
+
|
|
9
|
+
const MENU_ORDER = [
|
|
10
|
+
'aios-master',
|
|
11
|
+
'analyst',
|
|
12
|
+
'architect',
|
|
13
|
+
'data-engineer',
|
|
14
|
+
'dev',
|
|
15
|
+
'devops',
|
|
16
|
+
'pm',
|
|
17
|
+
'po',
|
|
18
|
+
'qa',
|
|
19
|
+
'sm',
|
|
20
|
+
'squad-creator',
|
|
21
|
+
'ux-design-expert',
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
function commandSlugForAgent(agentId) {
|
|
25
|
+
if (agentId.startsWith('aios-')) {
|
|
26
|
+
return agentId.replace(/^aios-/, '');
|
|
27
|
+
}
|
|
28
|
+
return agentId;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function menuCommandName(agentId) {
|
|
32
|
+
return `/aios-${commandSlugForAgent(agentId)}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function normalizeText(text) {
|
|
36
|
+
if (!text || typeof text !== 'string') return '';
|
|
37
|
+
return text.replace(/\s+/g, ' ').trim();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function truncateText(text, maxLen = MAX_DESCRIPTION_CONTEXT) {
|
|
41
|
+
if (!text || text.length <= maxLen) return text;
|
|
42
|
+
return `${text.slice(0, maxLen - 1).trimEnd()}…`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function summarizeWhenToUse(whenToUse) {
|
|
46
|
+
const normalized = normalizeText(whenToUse);
|
|
47
|
+
if (!normalized) return '';
|
|
48
|
+
|
|
49
|
+
// Drop redirect/negative guidance sections that are useful for routing, not for menu labels.
|
|
50
|
+
const withoutNegativeSection = normalized.split(/\b(?:NOT\s+for|NÃO\s+para)\b/i)[0].trim();
|
|
51
|
+
const primary = withoutNegativeSection || normalized;
|
|
52
|
+
|
|
53
|
+
// Keep only the first sentence/chunk for concise autocomplete labels.
|
|
54
|
+
const firstChunk = primary.split(/[.;!?](?:\s|$)/)[0].trim();
|
|
55
|
+
return truncateText(firstChunk || primary);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function escapeTomlString(text) {
|
|
59
|
+
return String(text || '').replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function buildAgentDescription(agent) {
|
|
63
|
+
const agentData = agent.agent || {};
|
|
64
|
+
const title = normalizeText(agentData.title);
|
|
65
|
+
const whenToUseSummary = summarizeWhenToUse(agentData.whenToUse);
|
|
66
|
+
|
|
67
|
+
if (title && whenToUseSummary) {
|
|
68
|
+
return `${title} (${whenToUseSummary})`;
|
|
69
|
+
}
|
|
70
|
+
if (title) {
|
|
71
|
+
return title;
|
|
72
|
+
}
|
|
73
|
+
if (whenToUseSummary) {
|
|
74
|
+
return whenToUseSummary;
|
|
75
|
+
}
|
|
76
|
+
return `Ativar agente AIOS ${agent.id}`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function buildAgentCommandPrompt(agentId) {
|
|
80
|
+
return [
|
|
81
|
+
`Ative o agente ${agentId}:`,
|
|
82
|
+
`1. Leia a definição completa em .gemini/rules/AIOS/agents/${agentId}.md`,
|
|
83
|
+
'2. Siga as activation-instructions do bloco YAML',
|
|
84
|
+
`3. Renderize o greeting via: node .aios-core/development/scripts/generate-greeting.js ${agentId}`,
|
|
85
|
+
' Se shell nao disponivel, exiba o greeting de persona_profile.communication.greeting_levels.named',
|
|
86
|
+
'4. Mostre Quick Commands e aguarde input do usuario',
|
|
87
|
+
'Mantenha a persona até *exit.',
|
|
88
|
+
].join('\n');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function buildAgentCommandFile(agentId, description = FALLBACK_DESCRIPTION) {
|
|
92
|
+
const slug = commandSlugForAgent(agentId);
|
|
93
|
+
|
|
94
|
+
const prompt = buildAgentCommandPrompt(agentId);
|
|
95
|
+
const content = [
|
|
96
|
+
`description = "${escapeTomlString(description)}"`,
|
|
97
|
+
'prompt = """',
|
|
98
|
+
prompt,
|
|
99
|
+
'"""',
|
|
100
|
+
'',
|
|
101
|
+
].join('\n');
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
filename: `aios-${slug}.toml`,
|
|
105
|
+
content,
|
|
106
|
+
agentId,
|
|
107
|
+
description,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function buildMenuPrompt(commandFiles) {
|
|
112
|
+
const lines = [
|
|
113
|
+
'Você está no launcher AIOS para Gemini.',
|
|
114
|
+
'',
|
|
115
|
+
'Mostre a lista de agentes abaixo em formato numerado, explicando em 1 linha quando usar cada um:',
|
|
116
|
+
];
|
|
117
|
+
|
|
118
|
+
let index = 1;
|
|
119
|
+
for (const commandFile of commandFiles) {
|
|
120
|
+
lines.push(`${index}. ${menuCommandName(commandFile.agentId)} - ${commandFile.description}`);
|
|
121
|
+
index += 1;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
lines.push('');
|
|
125
|
+
lines.push('No final, peça para o usuário escolher um número ou digitar o comando direto.');
|
|
126
|
+
return lines.join('\n');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function buildMenuCommandFile(commandFiles) {
|
|
130
|
+
const content = [
|
|
131
|
+
'description = "Menu rápido AIOS (lista agentes e orienta qual ativar)"',
|
|
132
|
+
'prompt = """',
|
|
133
|
+
buildMenuPrompt(commandFiles),
|
|
134
|
+
'"""',
|
|
135
|
+
'',
|
|
136
|
+
].join('\n');
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
filename: 'aios-menu.toml',
|
|
140
|
+
content,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function resolveAgentOrder(agentIds) {
|
|
145
|
+
const unique = [...new Set(agentIds)];
|
|
146
|
+
const known = MENU_ORDER.filter((id) => unique.includes(id));
|
|
147
|
+
const extra = unique.filter((id) => !MENU_ORDER.includes(id)).sort();
|
|
148
|
+
return [...known, ...extra];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function buildGeminiCommandFiles(agents) {
|
|
152
|
+
const validAgents = agents
|
|
153
|
+
.filter((agent) => !agent.error)
|
|
154
|
+
.map((agent) => ({
|
|
155
|
+
id: agent.id,
|
|
156
|
+
description: buildAgentDescription(agent),
|
|
157
|
+
}));
|
|
158
|
+
|
|
159
|
+
const ordered = resolveAgentOrder(validAgents.map((agent) => agent.id));
|
|
160
|
+
const byId = new Map(validAgents.map((agent) => [agent.id, agent]));
|
|
161
|
+
const files = ordered.map((id) => {
|
|
162
|
+
const meta = byId.get(id);
|
|
163
|
+
const description = meta?.description || FALLBACK_DESCRIPTION;
|
|
164
|
+
return buildAgentCommandFile(id, description);
|
|
165
|
+
});
|
|
166
|
+
files.unshift(buildMenuCommandFile(files));
|
|
167
|
+
return files;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function syncGeminiCommands(agents, projectRoot, options = {}) {
|
|
171
|
+
const commandsDir = path.join(projectRoot, '.gemini', 'commands');
|
|
172
|
+
const files = buildGeminiCommandFiles(agents);
|
|
173
|
+
const written = [];
|
|
174
|
+
|
|
175
|
+
if (!options.dryRun) {
|
|
176
|
+
fs.ensureDirSync(commandsDir);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
for (const file of files) {
|
|
180
|
+
const targetPath = path.join(commandsDir, file.filename);
|
|
181
|
+
if (!options.dryRun) {
|
|
182
|
+
fs.writeFileSync(targetPath, file.content, 'utf8');
|
|
183
|
+
}
|
|
184
|
+
written.push({
|
|
185
|
+
filename: path.join('commands', file.filename),
|
|
186
|
+
path: targetPath,
|
|
187
|
+
content: file.content,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return { commandsDir, files: written };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
module.exports = {
|
|
195
|
+
FALLBACK_DESCRIPTION,
|
|
196
|
+
MENU_ORDER,
|
|
197
|
+
commandSlugForAgent,
|
|
198
|
+
menuCommandName,
|
|
199
|
+
buildAgentDescription,
|
|
200
|
+
summarizeWhenToUse,
|
|
201
|
+
truncateText,
|
|
202
|
+
escapeTomlString,
|
|
203
|
+
buildGeminiCommandFiles,
|
|
204
|
+
syncGeminiCommands,
|
|
205
|
+
};
|
|
@@ -24,11 +24,11 @@ const yaml = require('js-yaml');
|
|
|
24
24
|
const { parseAllAgents } = require('./agent-parser');
|
|
25
25
|
const { generateAllRedirects, writeRedirects } = require('./redirect-generator');
|
|
26
26
|
const { validateAllIdes, formatValidationReport } = require('./validator');
|
|
27
|
+
const { syncGeminiCommands, buildGeminiCommandFiles } = require('./gemini-commands');
|
|
27
28
|
|
|
28
29
|
// Transformers
|
|
29
30
|
const claudeCodeTransformer = require('./transformers/claude-code');
|
|
30
31
|
const cursorTransformer = require('./transformers/cursor');
|
|
31
|
-
const windsurfTransformer = require('./transformers/windsurf');
|
|
32
32
|
const antigravityTransformer = require('./transformers/antigravity');
|
|
33
33
|
|
|
34
34
|
// ANSI colors for output
|
|
@@ -66,16 +66,21 @@ function loadConfig(projectRoot) {
|
|
|
66
66
|
path: '.codex/agents',
|
|
67
67
|
format: 'full-markdown-yaml',
|
|
68
68
|
},
|
|
69
|
+
gemini: {
|
|
70
|
+
enabled: true,
|
|
71
|
+
path: '.gemini/rules/AIOS/agents',
|
|
72
|
+
format: 'full-markdown-yaml',
|
|
73
|
+
},
|
|
74
|
+
'github-copilot': {
|
|
75
|
+
enabled: true,
|
|
76
|
+
path: '.github/agents',
|
|
77
|
+
format: 'full-markdown-yaml',
|
|
78
|
+
},
|
|
69
79
|
cursor: {
|
|
70
80
|
enabled: true,
|
|
71
81
|
path: '.cursor/rules/agents',
|
|
72
82
|
format: 'condensed-rules',
|
|
73
83
|
},
|
|
74
|
-
windsurf: {
|
|
75
|
-
enabled: false, // Disabled - consolidating to core IDEs (v3.10.0)
|
|
76
|
-
path: '.windsurf/rules/agents',
|
|
77
|
-
format: 'xml-tagged-markdown',
|
|
78
|
-
},
|
|
79
84
|
antigravity: {
|
|
80
85
|
enabled: true,
|
|
81
86
|
path: '.antigravity/rules/agents',
|
|
@@ -120,7 +125,6 @@ function getTransformer(format) {
|
|
|
120
125
|
const transformers = {
|
|
121
126
|
'full-markdown-yaml': claudeCodeTransformer,
|
|
122
127
|
'condensed-rules': cursorTransformer,
|
|
123
|
-
'xml-tagged-markdown': windsurfTransformer,
|
|
124
128
|
'cursor-style': antigravityTransformer,
|
|
125
129
|
};
|
|
126
130
|
|
|
@@ -258,6 +262,15 @@ async function commandSync(options) {
|
|
|
258
262
|
}
|
|
259
263
|
|
|
260
264
|
const result = syncIde(agents, ideConfig, ideName, projectRoot, options);
|
|
265
|
+
|
|
266
|
+
// Gemini CLI: also sync slash launcher command files (.gemini/commands/*.toml)
|
|
267
|
+
if (ideName === 'gemini') {
|
|
268
|
+
const geminiCommands = syncGeminiCommands(agents, projectRoot, options);
|
|
269
|
+
result.commandFiles = geminiCommands.files;
|
|
270
|
+
} else {
|
|
271
|
+
result.commandFiles = [];
|
|
272
|
+
}
|
|
273
|
+
|
|
261
274
|
results.push(result);
|
|
262
275
|
|
|
263
276
|
// Generate redirects for this IDE
|
|
@@ -269,6 +282,7 @@ async function commandSync(options) {
|
|
|
269
282
|
}
|
|
270
283
|
|
|
271
284
|
const agentCount = result.files.length;
|
|
285
|
+
const commandCount = (result.commandFiles || []).length;
|
|
272
286
|
const redirectCount = redirectResult.written.length;
|
|
273
287
|
const errorCount = result.errors.length;
|
|
274
288
|
|
|
@@ -279,7 +293,7 @@ async function commandSync(options) {
|
|
|
279
293
|
}
|
|
280
294
|
|
|
281
295
|
console.log(
|
|
282
|
-
` ${status} ${agentCount} agents, ${redirectCount} redirects${errorCount > 0 ? `, ${errorCount} errors` : ''}`
|
|
296
|
+
` ${status} ${agentCount} agents${commandCount > 0 ? `, ${commandCount} commands` : ''}, ${redirectCount} redirects${errorCount > 0 ? `, ${errorCount} errors` : ''}`
|
|
283
297
|
);
|
|
284
298
|
|
|
285
299
|
if (options.verbose && result.errors.length > 0) {
|
|
@@ -291,7 +305,7 @@ async function commandSync(options) {
|
|
|
291
305
|
}
|
|
292
306
|
|
|
293
307
|
// Summary
|
|
294
|
-
const totalFiles = results.reduce((sum, r) => sum + r.files.length, 0);
|
|
308
|
+
const totalFiles = results.reduce((sum, r) => sum + r.files.length + (r.commandFiles || []).length, 0);
|
|
295
309
|
const totalRedirects =
|
|
296
310
|
Object.keys(config.redirects).length * targetIdes.filter(([, c]) => c.enabled).length;
|
|
297
311
|
const totalErrors = results.reduce((sum, r) => sum + r.errors.length, 0);
|
|
@@ -337,9 +351,18 @@ async function commandValidate(options) {
|
|
|
337
351
|
|
|
338
352
|
// Build expected files for each IDE
|
|
339
353
|
const ideConfigs = {};
|
|
354
|
+
let targetIdes = Object.entries(config.targets).filter(([, ideConfig]) => ideConfig.enabled);
|
|
340
355
|
|
|
341
|
-
|
|
342
|
-
|
|
356
|
+
// Filter IDEs if --ide flag specified
|
|
357
|
+
if (options.ide) {
|
|
358
|
+
targetIdes = targetIdes.filter(([name]) => name === options.ide);
|
|
359
|
+
if (targetIdes.length === 0) {
|
|
360
|
+
console.error(`${colors.red}Error: IDE '${options.ide}' not found in config${colors.reset}`);
|
|
361
|
+
process.exit(1);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
for (const [ideName, ideConfig] of targetIdes) {
|
|
343
366
|
|
|
344
367
|
const transformer = getTransformer(ideConfig.format);
|
|
345
368
|
const expectedFiles = [];
|
|
@@ -374,6 +397,18 @@ async function commandValidate(options) {
|
|
|
374
397
|
expectedFiles,
|
|
375
398
|
targetDir: path.join(projectRoot, ideConfig.path),
|
|
376
399
|
};
|
|
400
|
+
|
|
401
|
+
// Gemini CLI command launcher files are synced under .gemini/commands/*.toml
|
|
402
|
+
if (ideName === 'gemini') {
|
|
403
|
+
const commandFiles = buildGeminiCommandFiles(agents).map((entry) => ({
|
|
404
|
+
filename: entry.filename,
|
|
405
|
+
content: entry.content,
|
|
406
|
+
}));
|
|
407
|
+
ideConfigs['gemini-commands'] = {
|
|
408
|
+
expectedFiles: commandFiles,
|
|
409
|
+
targetDir: path.join(projectRoot, '.gemini', 'commands'),
|
|
410
|
+
};
|
|
411
|
+
}
|
|
377
412
|
}
|
|
378
413
|
|
|
379
414
|
// Validate
|
|
@@ -450,7 +485,9 @@ ${colors.bright}Options:${colors.reset}
|
|
|
450
485
|
${colors.bright}Examples:${colors.reset}
|
|
451
486
|
node ide-sync/index.js sync
|
|
452
487
|
node ide-sync/index.js sync --ide codex
|
|
488
|
+
node ide-sync/index.js sync --ide gemini
|
|
453
489
|
node ide-sync/index.js sync --ide cursor
|
|
490
|
+
node ide-sync/index.js validate --ide gemini --strict
|
|
454
491
|
node ide-sync/index.js validate --strict
|
|
455
492
|
node ide-sync/index.js sync --dry-run --verbose
|
|
456
493
|
`);
|
|
@@ -48,7 +48,7 @@ class ToolResolver {
|
|
|
48
48
|
// 2. Build search paths (squad → core priority)
|
|
49
49
|
const searchPaths = [];
|
|
50
50
|
if (context.expansionPack) {
|
|
51
|
-
searchPaths.push(`
|
|
51
|
+
searchPaths.push(`squads/${context.expansionPack}/tools`);
|
|
52
52
|
}
|
|
53
53
|
searchPaths.push(...this.basePaths);
|
|
54
54
|
|
|
@@ -304,7 +304,7 @@ class ToolResolver {
|
|
|
304
304
|
async toolExists(toolName, context = {}) {
|
|
305
305
|
const searchPaths = [];
|
|
306
306
|
if (context.expansionPack) {
|
|
307
|
-
searchPaths.push(`
|
|
307
|
+
searchPaths.push(`squads/${context.expansionPack}/tools`);
|
|
308
308
|
}
|
|
309
309
|
searchPaths.push(...this.basePaths);
|
|
310
310
|
|
|
@@ -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
|
+
function parseArgs(argv = process.argv.slice(2)) {
|
|
8
|
+
const args = new Set(argv);
|
|
9
|
+
return {
|
|
10
|
+
quiet: args.has('--quiet') || args.has('-q'),
|
|
11
|
+
json: args.has('--json'),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function countMarkdownFiles(dirPath) {
|
|
16
|
+
if (!fs.existsSync(dirPath)) return 0;
|
|
17
|
+
return fs.readdirSync(dirPath).filter((f) => f.endsWith('.md')).length;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function validateClaudeIntegration(options = {}) {
|
|
21
|
+
const projectRoot = options.projectRoot || process.cwd();
|
|
22
|
+
const rulesFile = options.rulesFile || path.join(projectRoot, '.claude', 'CLAUDE.md');
|
|
23
|
+
const agentsDir = options.agentsDir || path.join(projectRoot, '.claude', 'commands', 'AIOS', 'agents');
|
|
24
|
+
const hooksDir = options.hooksDir || path.join(projectRoot, '.claude', 'hooks');
|
|
25
|
+
const sourceAgentsDir =
|
|
26
|
+
options.sourceAgentsDir || path.join(projectRoot, '.aios-core', 'development', 'agents');
|
|
27
|
+
|
|
28
|
+
const errors = [];
|
|
29
|
+
const warnings = [];
|
|
30
|
+
|
|
31
|
+
if (!fs.existsSync(agentsDir)) {
|
|
32
|
+
errors.push(`Missing Claude agents dir: ${path.relative(projectRoot, agentsDir)}`);
|
|
33
|
+
}
|
|
34
|
+
if (!fs.existsSync(rulesFile)) {
|
|
35
|
+
warnings.push(`Claude rules file not found yet: ${path.relative(projectRoot, rulesFile)}`);
|
|
36
|
+
}
|
|
37
|
+
if (!fs.existsSync(hooksDir)) {
|
|
38
|
+
warnings.push(`Claude hooks dir not found yet: ${path.relative(projectRoot, hooksDir)}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const sourceCount = countMarkdownFiles(sourceAgentsDir);
|
|
42
|
+
const claudeCount = countMarkdownFiles(agentsDir);
|
|
43
|
+
if (sourceCount > 0 && claudeCount !== sourceCount) {
|
|
44
|
+
warnings.push(`Claude agent count differs from source (${claudeCount}/${sourceCount})`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
ok: errors.length === 0,
|
|
49
|
+
errors,
|
|
50
|
+
warnings,
|
|
51
|
+
metrics: {
|
|
52
|
+
sourceAgents: sourceCount,
|
|
53
|
+
claudeAgents: claudeCount,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function formatHumanReport(result) {
|
|
59
|
+
if (result.ok) {
|
|
60
|
+
const lines = [`✅ Claude integration validation passed (agents: ${result.metrics.claudeAgents})`];
|
|
61
|
+
if (result.warnings.length > 0) {
|
|
62
|
+
lines.push(...result.warnings.map((w) => `⚠️ ${w}`));
|
|
63
|
+
}
|
|
64
|
+
return lines.join('\n');
|
|
65
|
+
}
|
|
66
|
+
const lines = [
|
|
67
|
+
`❌ Claude integration validation failed (${result.errors.length} issue(s))`,
|
|
68
|
+
...result.errors.map((e) => `- ${e}`),
|
|
69
|
+
];
|
|
70
|
+
if (result.warnings.length > 0) {
|
|
71
|
+
lines.push(...result.warnings.map((w) => `⚠️ ${w}`));
|
|
72
|
+
}
|
|
73
|
+
return lines.join('\n');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function main() {
|
|
77
|
+
const args = parseArgs();
|
|
78
|
+
const result = validateClaudeIntegration(args);
|
|
79
|
+
|
|
80
|
+
if (!args.quiet) {
|
|
81
|
+
if (args.json) {
|
|
82
|
+
console.log(JSON.stringify(result, null, 2));
|
|
83
|
+
} else {
|
|
84
|
+
console.log(formatHumanReport(result));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!result.ok) {
|
|
89
|
+
process.exitCode = 1;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (require.main === module) {
|
|
94
|
+
main();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = {
|
|
98
|
+
validateClaudeIntegration,
|
|
99
|
+
parseArgs,
|
|
100
|
+
countMarkdownFiles,
|
|
101
|
+
};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
function getDefaultOptions() {
|
|
8
|
+
const projectRoot = process.cwd();
|
|
9
|
+
return {
|
|
10
|
+
projectRoot,
|
|
11
|
+
instructionsFile: path.join(projectRoot, 'AGENTS.md'),
|
|
12
|
+
agentsDir: path.join(projectRoot, '.codex', 'agents'),
|
|
13
|
+
skillsDir: path.join(projectRoot, '.codex', 'skills'),
|
|
14
|
+
sourceAgentsDir: path.join(projectRoot, '.aios-core', 'development', 'agents'),
|
|
15
|
+
quiet: false,
|
|
16
|
+
json: false,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function parseArgs(argv = process.argv.slice(2)) {
|
|
21
|
+
const args = new Set(argv);
|
|
22
|
+
return {
|
|
23
|
+
quiet: args.has('--quiet') || args.has('-q'),
|
|
24
|
+
json: args.has('--json'),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function countMarkdownFiles(dirPath) {
|
|
29
|
+
if (!fs.existsSync(dirPath)) return 0;
|
|
30
|
+
return fs.readdirSync(dirPath).filter((f) => f.endsWith('.md')).length;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function countSkillFiles(skillsDir) {
|
|
34
|
+
if (!fs.existsSync(skillsDir)) return 0;
|
|
35
|
+
const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
36
|
+
return entries
|
|
37
|
+
.filter((entry) => entry.isDirectory() && entry.name.startsWith('aios-'))
|
|
38
|
+
.filter((entry) => fs.existsSync(path.join(skillsDir, entry.name, 'SKILL.md')))
|
|
39
|
+
.length;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function validateCodexIntegration(options = {}) {
|
|
43
|
+
const projectRoot = options.projectRoot || process.cwd();
|
|
44
|
+
const resolved = {
|
|
45
|
+
...getDefaultOptions(),
|
|
46
|
+
...options,
|
|
47
|
+
projectRoot,
|
|
48
|
+
instructionsFile: options.instructionsFile || path.join(projectRoot, 'AGENTS.md'),
|
|
49
|
+
agentsDir: options.agentsDir || path.join(projectRoot, '.codex', 'agents'),
|
|
50
|
+
skillsDir: options.skillsDir || path.join(projectRoot, '.codex', 'skills'),
|
|
51
|
+
sourceAgentsDir: options.sourceAgentsDir || path.join(projectRoot, '.aios-core', 'development', 'agents'),
|
|
52
|
+
};
|
|
53
|
+
const errors = [];
|
|
54
|
+
const warnings = [];
|
|
55
|
+
|
|
56
|
+
if (!fs.existsSync(resolved.instructionsFile)) {
|
|
57
|
+
warnings.push(
|
|
58
|
+
`Codex instructions file not found yet: ${path.relative(resolved.projectRoot, resolved.instructionsFile)}`,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!fs.existsSync(resolved.agentsDir)) {
|
|
63
|
+
errors.push(`Missing Codex agents dir: ${path.relative(resolved.projectRoot, resolved.agentsDir)}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!fs.existsSync(resolved.skillsDir)) {
|
|
67
|
+
errors.push(`Missing Codex skills dir: ${path.relative(resolved.projectRoot, resolved.skillsDir)}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const sourceCount = countMarkdownFiles(resolved.sourceAgentsDir);
|
|
71
|
+
const codexAgentsCount = countMarkdownFiles(resolved.agentsDir);
|
|
72
|
+
const codexSkillsCount = countSkillFiles(resolved.skillsDir);
|
|
73
|
+
|
|
74
|
+
if (sourceCount > 0 && codexAgentsCount !== sourceCount) {
|
|
75
|
+
warnings.push(`Codex agent count differs from source (${codexAgentsCount}/${sourceCount})`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (sourceCount > 0 && codexSkillsCount !== sourceCount) {
|
|
79
|
+
warnings.push(`Codex skill count differs from source (${codexSkillsCount}/${sourceCount})`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
ok: errors.length === 0,
|
|
84
|
+
errors,
|
|
85
|
+
warnings,
|
|
86
|
+
metrics: {
|
|
87
|
+
sourceAgents: sourceCount,
|
|
88
|
+
codexAgents: codexAgentsCount,
|
|
89
|
+
codexSkills: codexSkillsCount,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function formatHumanReport(result) {
|
|
95
|
+
if (result.ok) {
|
|
96
|
+
const lines = [
|
|
97
|
+
`✅ Codex integration validation passed (agents: ${result.metrics.codexAgents}, skills: ${result.metrics.codexSkills})`,
|
|
98
|
+
];
|
|
99
|
+
if (result.warnings.length > 0) {
|
|
100
|
+
lines.push(...result.warnings.map((w) => `⚠️ ${w}`));
|
|
101
|
+
}
|
|
102
|
+
return lines.join('\n');
|
|
103
|
+
}
|
|
104
|
+
const lines = [
|
|
105
|
+
`❌ Codex integration validation failed (${result.errors.length} issue(s))`,
|
|
106
|
+
...result.errors.map((e) => `- ${e}`),
|
|
107
|
+
];
|
|
108
|
+
if (result.warnings.length > 0) {
|
|
109
|
+
lines.push(...result.warnings.map((w) => `⚠️ ${w}`));
|
|
110
|
+
}
|
|
111
|
+
return lines.join('\n');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function main() {
|
|
115
|
+
const args = parseArgs();
|
|
116
|
+
const result = validateCodexIntegration(args);
|
|
117
|
+
|
|
118
|
+
if (!args.quiet) {
|
|
119
|
+
if (args.json) {
|
|
120
|
+
console.log(JSON.stringify(result, null, 2));
|
|
121
|
+
} else {
|
|
122
|
+
console.log(formatHumanReport(result));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (!result.ok) {
|
|
127
|
+
process.exitCode = 1;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (require.main === module) {
|
|
132
|
+
main();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
module.exports = {
|
|
136
|
+
validateCodexIntegration,
|
|
137
|
+
parseArgs,
|
|
138
|
+
getDefaultOptions,
|
|
139
|
+
countMarkdownFiles,
|
|
140
|
+
countSkillFiles,
|
|
141
|
+
};
|