@jaimevalasek/aioson 1.5.1 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/docs/design-previews/aurora-command-ui-website.html +884 -0
- package/docs/design-previews/aurora-command-ui.html +682 -0
- package/docs/design-previews/bold-editorial-ui-website.html +658 -0
- package/docs/design-previews/bold-editorial-ui.html +717 -0
- package/docs/design-previews/clean-saas-ui-website.html +1202 -0
- package/docs/design-previews/clean-saas-ui.html +549 -0
- package/docs/design-previews/cognitive-core-ui-website.html +1009 -0
- package/docs/design-previews/cognitive-core-ui.html +463 -0
- package/docs/design-previews/glassmorphism-ui-website.html +572 -0
- package/docs/design-previews/glassmorphism-ui.html +886 -0
- package/docs/design-previews/index.html +699 -0
- package/docs/design-previews/interface-design-website.html +1187 -0
- package/docs/design-previews/interface-design.html +513 -0
- package/docs/design-previews/neo-brutalist-ui-website.html +621 -0
- package/docs/design-previews/neo-brutalist-ui.html +797 -0
- package/docs/design-previews/premium-command-center-ui-website.html +1217 -0
- package/docs/design-previews/premium-command-center-ui.html +552 -0
- package/docs/design-previews/warm-craft-ui-website.html +684 -0
- package/docs/design-previews/warm-craft-ui.html +739 -0
- package/docs/en/cli-reference.md +20 -9
- package/docs/pt/README.md +7 -0
- package/docs/pt/agent-sharding.md +132 -0
- package/docs/pt/agentes.md +8 -2
- package/docs/pt/busca-de-contexto.md +129 -0
- package/docs/pt/cache-de-contexto.md +156 -0
- package/docs/pt/comandos-cli.md +28 -0
- package/docs/pt/design-hybrid-forge.md +107 -0
- package/docs/pt/inicio-rapido.md +54 -3
- package/docs/pt/inteligencia-adaptativa.md +324 -0
- package/docs/pt/monitor-de-contexto.md +104 -0
- package/docs/pt/recuperacao-de-sessao.md +125 -0
- package/docs/pt/sandbox.md +125 -0
- package/docs/pt/skills.md +98 -6
- package/package.json +1 -1
- package/src/agent-loader.js +280 -0
- package/src/cli.js +94 -0
- package/src/commands/agent-loader.js +85 -0
- package/src/commands/context-cache.js +90 -0
- package/src/commands/context-monitor.js +92 -0
- package/src/commands/context-search.js +66 -0
- package/src/commands/design-hybrid-options.js +385 -0
- package/src/commands/health.js +214 -0
- package/src/commands/init.js +54 -13
- package/src/commands/install.js +52 -13
- package/src/commands/learning-evolve.js +355 -0
- package/src/commands/live.js +34 -0
- package/src/commands/recovery.js +43 -0
- package/src/commands/sandbox.js +37 -0
- package/src/commands/setup-context.js +22 -2
- package/src/commands/setup.js +178 -0
- package/src/commands/skill.js +79 -32
- package/src/commands/tool-registry-cmd.js +232 -0
- package/src/commands/update.js +7 -0
- package/src/constants.js +9 -0
- package/src/context-cache.js +159 -0
- package/src/context-search.js +326 -0
- package/src/design-variation-catalog.js +503 -0
- package/src/i18n/messages/en.js +32 -2
- package/src/i18n/messages/es.js +30 -2
- package/src/i18n/messages/fr.js +30 -2
- package/src/i18n/messages/pt-BR.js +32 -2
- package/src/install-animation.js +260 -0
- package/src/install-profile.js +143 -0
- package/src/install-wizard.js +474 -0
- package/src/installer.js +38 -10
- package/src/parser.js +7 -1
- package/src/recovery-context-session.js +154 -0
- package/src/runtime-store.js +97 -1
- package/src/sandbox.js +177 -0
- package/src/tool-executor.js +94 -0
- package/src/updater.js +11 -3
- package/template/.aioson/agents/analyst.md +58 -3
- package/template/.aioson/agents/architect.md +38 -0
- package/template/.aioson/agents/design-hybrid-forge.md +127 -0
- package/template/.aioson/agents/dev.md +103 -0
- package/template/.aioson/agents/deyvin.md +57 -0
- package/template/.aioson/agents/pm.md +58 -0
- package/template/.aioson/agents/product.md +28 -0
- package/template/.aioson/agents/qa.md +79 -0
- package/template/.aioson/agents/setup.md +65 -3
- package/template/.aioson/agents/sheldon.md +107 -6
- package/template/.aioson/agents/tester.md +156 -0
- package/template/.aioson/config.md +15 -0
- package/template/.aioson/context/forensics/.gitkeep +0 -0
- package/template/.aioson/context/seeds/seed-example.md +27 -0
- package/template/.aioson/context/user-profile.md +42 -0
- package/template/.aioson/locales/en/agents/setup.md +33 -1
- package/template/.aioson/locales/es/agents/setup.md +33 -1
- package/template/.aioson/locales/fr/agents/setup.md +33 -1
- package/template/.aioson/locales/pt-BR/agents/setup.md +33 -1
- package/template/.aioson/skills/design/aurora-command-ui/SKILL.md +243 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/art-direction.md +293 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/components.md +827 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/dashboards.md +250 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/design-tokens.md +585 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/motion.md +365 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/patterns.md +482 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/websites.md +387 -0
- package/template/.aioson/skills/design/glassmorphism-ui/SKILL.md +222 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/art-direction.md +159 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/components.md +498 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/dashboards.md +236 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/design-tokens.md +274 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/motion.md +355 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/patterns.md +198 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/websites.md +307 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/SKILL.md +213 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/art-direction.md +228 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/components.md +855 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/dashboards.md +334 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/design-tokens.md +342 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/motion.md +286 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/patterns.md +458 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/websites.md +723 -0
- package/template/.aioson/skills/process/aioson-spec-driven/SKILL.md +45 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/approval-gates.md +109 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/artifact-map.md +44 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/classification-map.md +37 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/hardening-lane.md +49 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/maintenance-and-state.md +66 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/ui-language.md +75 -0
- package/template/.aioson/skills/process/design-hybrid-forge/SKILL.md +144 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/crossover-protocol.md +221 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/naming-registry.md +88 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/output-contract.md +291 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/pair-compatibility.md +117 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/quality-gates.md +188 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/variation-library.md +125 -0
- package/template/AGENTS.md +23 -1
- package/template/CLAUDE.md +1 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const readline = require('node:readline/promises');
|
|
5
|
+
const { installTemplate, readInstallProfile } = require('../installer');
|
|
6
|
+
const { detectFramework } = require('../detector');
|
|
7
|
+
const { detectSystemLanguage } = require('./setup-context');
|
|
8
|
+
const { runSetupContext } = require('./setup-context');
|
|
9
|
+
const { resolvePromptTool } = require('../prompt-tool');
|
|
10
|
+
const { normalizeBoolean } = require('../context-writer');
|
|
11
|
+
const { runInstallWizard } = require('../install-wizard');
|
|
12
|
+
|
|
13
|
+
async function ask(rl, question, fallback = '') {
|
|
14
|
+
const suffix = fallback ? ` (${fallback})` : '';
|
|
15
|
+
const value = await rl.question(`${question}${suffix}: `);
|
|
16
|
+
const cleaned = String(value || '').trim();
|
|
17
|
+
if (!cleaned) return fallback;
|
|
18
|
+
return cleaned;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function runSetup({ args, options, logger, t }) {
|
|
22
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
23
|
+
const dryRun = Boolean(options['dry-run']);
|
|
24
|
+
const force = Boolean(options.force);
|
|
25
|
+
const defaultsMode = Boolean(options.defaults);
|
|
26
|
+
const promptTool = resolvePromptTool(options.tool);
|
|
27
|
+
|
|
28
|
+
// Step 1 — detect install profile (wizard if first time in TTY)
|
|
29
|
+
const isTTY = process.stdin.isTTY && process.stdout.isTTY;
|
|
30
|
+
let installProfile = null;
|
|
31
|
+
|
|
32
|
+
if (!dryRun && isTTY) {
|
|
33
|
+
const existingProfile = await readInstallProfile(targetDir);
|
|
34
|
+
if (!existingProfile) {
|
|
35
|
+
installProfile = await runInstallWizard({});
|
|
36
|
+
} else {
|
|
37
|
+
installProfile = existingProfile;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Step 2 — install template
|
|
42
|
+
logger.log(t('setup.installing'));
|
|
43
|
+
const installResult = await installTemplate(targetDir, {
|
|
44
|
+
overwrite: force,
|
|
45
|
+
dryRun,
|
|
46
|
+
mode: 'install',
|
|
47
|
+
installProfile
|
|
48
|
+
});
|
|
49
|
+
logger.log(t('setup.installed', { count: installResult.copied.length }));
|
|
50
|
+
|
|
51
|
+
// Step 3 — detect framework and system language
|
|
52
|
+
const detection = await detectFramework(targetDir);
|
|
53
|
+
const detectedFramework = detection.framework;
|
|
54
|
+
const detectedInstalled = detection.installed;
|
|
55
|
+
const systemLang = detectSystemLanguage();
|
|
56
|
+
|
|
57
|
+
// Build setup:context options by merging detected state with explicit flags
|
|
58
|
+
const contextOptions = { defaults: true };
|
|
59
|
+
|
|
60
|
+
// Propagate any explicit overrides the user passed to `setup`
|
|
61
|
+
const passthroughFlags = [
|
|
62
|
+
'project-name', 'project-type', 'framework', 'framework-installed',
|
|
63
|
+
'classification', 'lang', 'language', 'profile', 'backend', 'frontend',
|
|
64
|
+
'database', 'auth', 'uiux', 'design-skill', 'test-runner',
|
|
65
|
+
'web3-enabled', 'web3-networks', 'contract-framework',
|
|
66
|
+
'wallet-provider', 'indexer', 'rpc-provider',
|
|
67
|
+
'queues', 'storage', 'websockets', 'payments', 'email', 'cache', 'search'
|
|
68
|
+
];
|
|
69
|
+
for (const flag of passthroughFlags) {
|
|
70
|
+
if (Object.prototype.hasOwnProperty.call(options, flag)) {
|
|
71
|
+
contextOptions[flag] = options[flag];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Apply language: explicit flag > system detection
|
|
76
|
+
if (!contextOptions.lang && !contextOptions.language) {
|
|
77
|
+
contextOptions.lang = systemLang;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// For greenfield projects (nothing detected), ask minimal interactive questions
|
|
81
|
+
// unless --defaults is set or the user already passed --framework
|
|
82
|
+
const isGreenfield = !detectedFramework;
|
|
83
|
+
const frameworkProvided = Object.prototype.hasOwnProperty.call(options, 'framework');
|
|
84
|
+
|
|
85
|
+
if (!defaultsMode && isGreenfield && !frameworkProvided) {
|
|
86
|
+
const rl = readline.createInterface({
|
|
87
|
+
input: process.stdin,
|
|
88
|
+
output: process.stdout
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
logger.log(t('setup.no_framework_detected'));
|
|
93
|
+
|
|
94
|
+
const projectName = await ask(
|
|
95
|
+
rl,
|
|
96
|
+
t('setup.q_project_name'),
|
|
97
|
+
path.basename(targetDir) || 'my-project'
|
|
98
|
+
);
|
|
99
|
+
if (projectName !== path.basename(targetDir)) {
|
|
100
|
+
contextOptions['project-name'] = projectName;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const framework = await ask(rl, t('setup.q_framework'), '');
|
|
104
|
+
if (framework) {
|
|
105
|
+
contextOptions.framework = framework;
|
|
106
|
+
contextOptions['framework-installed'] = 'false';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const detectedLang = contextOptions.lang || systemLang;
|
|
110
|
+
const lang = await ask(rl, t('setup.q_lang'), detectedLang);
|
|
111
|
+
contextOptions.lang = lang;
|
|
112
|
+
} finally {
|
|
113
|
+
rl.close();
|
|
114
|
+
}
|
|
115
|
+
} else if (!defaultsMode && detectedFramework) {
|
|
116
|
+
// Existing project with detected framework — confirm before proceeding
|
|
117
|
+
const rl = readline.createInterface({
|
|
118
|
+
input: process.stdin,
|
|
119
|
+
output: process.stdout
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
logger.log(
|
|
124
|
+
t('setup.framework_detected', {
|
|
125
|
+
framework: detectedFramework,
|
|
126
|
+
installed: String(detectedInstalled)
|
|
127
|
+
})
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
const confirmed = normalizeBoolean(
|
|
131
|
+
await ask(rl, t('setup.q_confirm_framework'), 'true'),
|
|
132
|
+
true
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
if (!confirmed) {
|
|
136
|
+
const override = await ask(rl, t('setup.q_override_framework'), detectedFramework);
|
|
137
|
+
contextOptions.framework = override;
|
|
138
|
+
contextOptions['framework-installed'] = await ask(
|
|
139
|
+
rl,
|
|
140
|
+
t('setup.q_framework_installed'),
|
|
141
|
+
'false'
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const detectedLang = contextOptions.lang || systemLang;
|
|
146
|
+
const lang = await ask(rl, t('setup.q_lang'), detectedLang);
|
|
147
|
+
contextOptions.lang = lang;
|
|
148
|
+
} finally {
|
|
149
|
+
rl.close();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Step 4 — run setup:context with fully resolved options
|
|
154
|
+
logger.log(t('setup.writing_context'));
|
|
155
|
+
const contextResult = await runSetupContext({
|
|
156
|
+
args: [targetDir],
|
|
157
|
+
options: contextOptions,
|
|
158
|
+
logger,
|
|
159
|
+
t
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
if (!dryRun) {
|
|
163
|
+
logger.log('');
|
|
164
|
+
logger.log(t('setup.done'));
|
|
165
|
+
logger.log(t('setup.step_agents'));
|
|
166
|
+
logger.log(t('setup.step_agent_prompt', { tool: promptTool }));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
ok: true,
|
|
171
|
+
targetDir,
|
|
172
|
+
installResult,
|
|
173
|
+
contextResult,
|
|
174
|
+
detection
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
module.exports = { runSetup };
|
package/src/commands/skill.js
CHANGED
|
@@ -16,6 +16,47 @@ function resolveTargetDir(args) {
|
|
|
16
16
|
return path.resolve(process.cwd(), args[0] || '.');
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
async function copyRecursive(src, dest) {
|
|
20
|
+
const stat = await fs.stat(src);
|
|
21
|
+
if (stat.isDirectory()) {
|
|
22
|
+
await ensureDir(dest);
|
|
23
|
+
const entries = await fs.readdir(src);
|
|
24
|
+
for (const entry of entries) {
|
|
25
|
+
await copyRecursive(path.join(src, entry), path.join(dest, entry));
|
|
26
|
+
}
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
await ensureDir(path.dirname(dest));
|
|
31
|
+
await fs.copyFile(src, dest);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function replaceDirectory(srcDir, destDir) {
|
|
35
|
+
await fs.rm(destDir, { recursive: true, force: true });
|
|
36
|
+
await copyRecursive(srcDir, destDir);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function readJsonIfExists(filePath) {
|
|
40
|
+
if (!(await exists(filePath))) return null;
|
|
41
|
+
try {
|
|
42
|
+
return JSON.parse(await fs.readFile(filePath, 'utf8'));
|
|
43
|
+
} catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function writeSkillMeta(destDir, patch) {
|
|
49
|
+
const metaPath = path.join(destDir, '.skill-meta.json');
|
|
50
|
+
const existing = await readJsonIfExists(metaPath) || {};
|
|
51
|
+
const merged = {
|
|
52
|
+
...existing,
|
|
53
|
+
...patch
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
await fs.writeFile(metaPath, JSON.stringify(merged, null, 2), 'utf8');
|
|
57
|
+
return merged;
|
|
58
|
+
}
|
|
59
|
+
|
|
19
60
|
/**
|
|
20
61
|
* Parse YAML frontmatter from a SKILL.md file.
|
|
21
62
|
*/
|
|
@@ -44,17 +85,7 @@ async function distributeToTool(targetDir, slug, skillDir) {
|
|
|
44
85
|
for (const toolPath of TOOL_TARGETS) {
|
|
45
86
|
const toolSkillDir = path.join(targetDir, toolPath, slug);
|
|
46
87
|
try {
|
|
47
|
-
await
|
|
48
|
-
// Copy all files from the installed skill dir
|
|
49
|
-
const entries = await fs.readdir(skillDir);
|
|
50
|
-
for (const entry of entries) {
|
|
51
|
-
const src = path.join(skillDir, entry);
|
|
52
|
-
const dest = path.join(toolSkillDir, entry);
|
|
53
|
-
const stat = await fs.stat(src);
|
|
54
|
-
if (stat.isFile()) {
|
|
55
|
-
await fs.copyFile(src, dest);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
88
|
+
await replaceDirectory(skillDir, toolSkillDir);
|
|
58
89
|
results.push({ tool: toolPath, ok: true });
|
|
59
90
|
} catch (err) {
|
|
60
91
|
results.push({ tool: toolPath, ok: false, error: err.message });
|
|
@@ -187,12 +218,13 @@ async function installFromNpm(targetDir, slug, options, logger) {
|
|
|
187
218
|
|
|
188
219
|
// Copy to .aioson/installed-skills/{slug}/
|
|
189
220
|
const destDir = path.join(targetDir, INSTALLED_SKILLS_DIR, slug);
|
|
190
|
-
await
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
221
|
+
await replaceDirectory(sourceDir, destDir);
|
|
222
|
+
await writeSkillMeta(destDir, {
|
|
223
|
+
source: 'npm',
|
|
224
|
+
sourcePackage: '@tech-leads-club/agent-skills',
|
|
225
|
+
sourcePath: path.relative(targetDir, sourceDir),
|
|
226
|
+
installedAt: new Date().toISOString()
|
|
227
|
+
});
|
|
196
228
|
|
|
197
229
|
resolve({ ok: true, sourceDir, destDir });
|
|
198
230
|
});
|
|
@@ -248,15 +280,16 @@ async function installFromCloud(targetDir, slug, options, logger) {
|
|
|
248
280
|
].join('\n');
|
|
249
281
|
|
|
250
282
|
const destDir = path.join(targetDir, INSTALLED_SKILLS_DIR, slug);
|
|
283
|
+
await fs.rm(destDir, { recursive: true, force: true });
|
|
251
284
|
await ensureDir(destDir);
|
|
252
285
|
await fs.writeFile(path.join(destDir, 'SKILL.md'), fm, 'utf8');
|
|
253
286
|
|
|
254
287
|
// Write meta
|
|
255
|
-
await
|
|
288
|
+
await writeSkillMeta(destDir, {
|
|
256
289
|
source: 'cloud',
|
|
257
290
|
cloudSlug: snapshot.skill.slug,
|
|
258
291
|
installedAt: new Date().toISOString()
|
|
259
|
-
}
|
|
292
|
+
});
|
|
260
293
|
|
|
261
294
|
return { ok: true, destDir };
|
|
262
295
|
}
|
|
@@ -271,30 +304,32 @@ async function installFromLocal(targetDir, slug, filePath, logger) {
|
|
|
271
304
|
}
|
|
272
305
|
|
|
273
306
|
const destDir = path.join(targetDir, INSTALLED_SKILLS_DIR, slug);
|
|
274
|
-
await ensureDir(destDir);
|
|
275
|
-
|
|
276
307
|
const stat = await fs.stat(absPath);
|
|
308
|
+
const samePath = path.resolve(absPath) === path.resolve(destDir);
|
|
309
|
+
|
|
310
|
+
if (!samePath) {
|
|
311
|
+
await fs.rm(destDir, { recursive: true, force: true });
|
|
312
|
+
await ensureDir(destDir);
|
|
313
|
+
} else if (!stat.isDirectory()) {
|
|
314
|
+
return { ok: false, error: 'Local self-install only supports skill directories' };
|
|
315
|
+
}
|
|
316
|
+
|
|
277
317
|
if (stat.isDirectory()) {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
for (const entry of entries) {
|
|
281
|
-
const src = path.join(absPath, entry);
|
|
282
|
-
const srcStat = await fs.stat(src);
|
|
283
|
-
if (srcStat.isFile()) {
|
|
284
|
-
await fs.copyFile(src, path.join(destDir, entry));
|
|
285
|
-
}
|
|
318
|
+
if (!samePath) {
|
|
319
|
+
await replaceDirectory(absPath, destDir);
|
|
286
320
|
}
|
|
287
321
|
} else {
|
|
288
322
|
// Single file — copy as SKILL.md
|
|
323
|
+
await ensureDir(destDir);
|
|
289
324
|
await fs.copyFile(absPath, path.join(destDir, 'SKILL.md'));
|
|
290
325
|
}
|
|
291
326
|
|
|
292
327
|
// Write meta
|
|
293
|
-
await
|
|
328
|
+
await writeSkillMeta(destDir, {
|
|
294
329
|
source: 'local',
|
|
295
330
|
sourcePath: filePath,
|
|
296
331
|
installedAt: new Date().toISOString()
|
|
297
|
-
}
|
|
332
|
+
});
|
|
298
333
|
|
|
299
334
|
return { ok: true, destDir };
|
|
300
335
|
}
|
|
@@ -429,17 +464,27 @@ async function runSkillList({ args, options = {}, logger, t }) {
|
|
|
429
464
|
const fm = parseSkillFrontmatter(raw);
|
|
430
465
|
|
|
431
466
|
let source = 'unknown';
|
|
467
|
+
let meta = null;
|
|
432
468
|
try {
|
|
433
469
|
const metaRaw = await fs.readFile(path.join(skillsDir, slug, '.skill-meta.json'), 'utf8');
|
|
434
|
-
|
|
470
|
+
meta = JSON.parse(metaRaw);
|
|
435
471
|
source = meta.source || 'unknown';
|
|
436
472
|
} catch { /* no meta */ }
|
|
437
473
|
|
|
474
|
+
const author = meta?.author?.name || meta?.author_name || null;
|
|
475
|
+
const model =
|
|
476
|
+
meta?.generator?.model ||
|
|
477
|
+
meta?.generation?.model ||
|
|
478
|
+
meta?.generated_by_model ||
|
|
479
|
+
null;
|
|
480
|
+
|
|
438
481
|
installed.push({
|
|
439
482
|
slug,
|
|
440
483
|
name: fm.name || slug,
|
|
441
484
|
description: fm.description || '',
|
|
442
485
|
source,
|
|
486
|
+
author,
|
|
487
|
+
model,
|
|
443
488
|
path: path.relative(targetDir, path.join(skillsDir, slug))
|
|
444
489
|
});
|
|
445
490
|
}
|
|
@@ -472,6 +517,8 @@ async function runSkillList({ args, options = {}, logger, t }) {
|
|
|
472
517
|
if (s.description) {
|
|
473
518
|
logger.log(` ${s.description.slice(0, 100)}`);
|
|
474
519
|
}
|
|
520
|
+
if (s.author) logger.log(` author: ${s.author}`);
|
|
521
|
+
if (s.model) logger.log(` model: ${s.model}`);
|
|
475
522
|
logger.log(` ${s.path}/SKILL.md`);
|
|
476
523
|
logger.log('');
|
|
477
524
|
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const {
|
|
5
|
+
openRuntimeDb,
|
|
6
|
+
registerDynamicTool,
|
|
7
|
+
unregisterDynamicTool,
|
|
8
|
+
getDynamicTool,
|
|
9
|
+
listDynamicTools
|
|
10
|
+
} = require('../runtime-store');
|
|
11
|
+
const { executeTool } = require('../tool-executor');
|
|
12
|
+
|
|
13
|
+
const TOOL_NAME_RE = /^[a-z][a-z0-9_]*$/;
|
|
14
|
+
|
|
15
|
+
async function runToolRegistry({ args = [], options = {}, logger = console, t = (k) => k } = {}) {
|
|
16
|
+
const projectDir = path.resolve(process.cwd(), args[0] || '.');
|
|
17
|
+
const sub = options.sub || 'list';
|
|
18
|
+
|
|
19
|
+
if (sub === 'register') return handleRegister(projectDir, options, logger);
|
|
20
|
+
if (sub === 'list') return handleList(projectDir, options, logger);
|
|
21
|
+
if (sub === 'call') return handleCall(projectDir, options, logger);
|
|
22
|
+
if (sub === 'unregister') return handleUnregister(projectDir, options, logger);
|
|
23
|
+
if (sub === 'show') return handleShow(projectDir, options, logger);
|
|
24
|
+
|
|
25
|
+
logger.error(`Subcomando desconhecido: ${sub}. Disponíveis: register, list, call, unregister, show`);
|
|
26
|
+
return { ok: false, error: 'unknown_sub' };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function handleRegister(projectDir, options, logger) {
|
|
30
|
+
const name = String(options.name || '').trim();
|
|
31
|
+
const description = String(options.description || options.desc || '').trim();
|
|
32
|
+
const handlerType = String(options.type || 'shell').trim();
|
|
33
|
+
const handlerCode = options.cmd ? String(options.cmd) : null;
|
|
34
|
+
const handlerPath = options.path ? String(options.path) : null;
|
|
35
|
+
const squadSlug = options.squad ? String(options.squad) : null;
|
|
36
|
+
const registeredBy = options.by ? String(options.by) : null;
|
|
37
|
+
|
|
38
|
+
if (!name) {
|
|
39
|
+
logger.error('--name é obrigatório');
|
|
40
|
+
return { ok: false, error: 'name_required' };
|
|
41
|
+
}
|
|
42
|
+
if (!TOOL_NAME_RE.test(name) || name.length > 64) {
|
|
43
|
+
logger.error(`Nome inválido: "${name}". Use apenas letras minúsculas, números e _ (máx 64 chars, começando com letra)`);
|
|
44
|
+
return { ok: false, error: 'invalid_name' };
|
|
45
|
+
}
|
|
46
|
+
if (!description) {
|
|
47
|
+
logger.error('--description é obrigatório');
|
|
48
|
+
return { ok: false, error: 'description_required' };
|
|
49
|
+
}
|
|
50
|
+
if (!['shell', 'script'].includes(handlerType)) {
|
|
51
|
+
logger.error('--type deve ser "shell" ou "script"');
|
|
52
|
+
return { ok: false, error: 'invalid_type' };
|
|
53
|
+
}
|
|
54
|
+
if (handlerType === 'shell' && !handlerCode) {
|
|
55
|
+
logger.error('--cmd é obrigatório para tools do tipo shell');
|
|
56
|
+
return { ok: false, error: 'cmd_required' };
|
|
57
|
+
}
|
|
58
|
+
if (handlerType === 'script' && !handlerPath) {
|
|
59
|
+
logger.error('--path é obrigatório para tools do tipo script');
|
|
60
|
+
return { ok: false, error: 'path_required' };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const handle = await openRuntimeDb(projectDir);
|
|
64
|
+
if (!handle) {
|
|
65
|
+
logger.error('Runtime store não encontrado. Execute aioson runtime:init primeiro.');
|
|
66
|
+
return { ok: false, error: 'no_runtime' };
|
|
67
|
+
}
|
|
68
|
+
const { db } = handle;
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
registerDynamicTool(db, {
|
|
72
|
+
name,
|
|
73
|
+
description,
|
|
74
|
+
handlerType,
|
|
75
|
+
handlerCode,
|
|
76
|
+
handlerPath,
|
|
77
|
+
squadSlug,
|
|
78
|
+
registeredBy
|
|
79
|
+
});
|
|
80
|
+
logger.log(`Tool registrada: ${name} (${handlerType})`);
|
|
81
|
+
return { ok: true, name, handlerType };
|
|
82
|
+
} finally {
|
|
83
|
+
db.close();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function handleList(projectDir, options, logger) {
|
|
88
|
+
const handle = await openRuntimeDb(projectDir, { mustExist: true });
|
|
89
|
+
if (!handle) {
|
|
90
|
+
logger.log('Nenhum runtime store encontrado.');
|
|
91
|
+
return { ok: true, tools: [] };
|
|
92
|
+
}
|
|
93
|
+
const { db } = handle;
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
const tools = listDynamicTools(db, options.squad || null);
|
|
97
|
+
if (tools.length === 0) {
|
|
98
|
+
logger.log('Nenhuma tool registrada neste projeto.');
|
|
99
|
+
return { ok: true, tools: [] };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
logger.log(`Tools registradas (${tools.length}):`);
|
|
103
|
+
logger.log('');
|
|
104
|
+
for (const tool of tools) {
|
|
105
|
+
const scope = tool.squad_slug ? ` [squad:${tool.squad_slug}]` : '';
|
|
106
|
+
logger.log(` ${tool.name}${scope}`);
|
|
107
|
+
logger.log(` ${tool.description}`);
|
|
108
|
+
logger.log(` tipo: ${tool.handler_type} | registrada: ${tool.registered_at.slice(0, 10)}`);
|
|
109
|
+
logger.log('');
|
|
110
|
+
}
|
|
111
|
+
return { ok: true, tools };
|
|
112
|
+
} finally {
|
|
113
|
+
db.close();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function handleCall(projectDir, options, logger) {
|
|
118
|
+
const name = String(options.name || '').trim();
|
|
119
|
+
if (!name) {
|
|
120
|
+
logger.error('--name é obrigatório');
|
|
121
|
+
return { ok: false, error: 'name_required' };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
let input = {};
|
|
125
|
+
if (options.input) {
|
|
126
|
+
try {
|
|
127
|
+
input = JSON.parse(String(options.input));
|
|
128
|
+
} catch {
|
|
129
|
+
logger.error('--input deve ser JSON válido');
|
|
130
|
+
return { ok: false, error: 'invalid_input' };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const handle = await openRuntimeDb(projectDir, { mustExist: true });
|
|
135
|
+
if (!handle) {
|
|
136
|
+
logger.error('Runtime store não encontrado.');
|
|
137
|
+
return { ok: false, error: 'no_runtime' };
|
|
138
|
+
}
|
|
139
|
+
const { db } = handle;
|
|
140
|
+
|
|
141
|
+
let tool;
|
|
142
|
+
try {
|
|
143
|
+
tool = getDynamicTool(db, name);
|
|
144
|
+
} finally {
|
|
145
|
+
db.close();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (!tool) {
|
|
149
|
+
logger.error(`Tool não encontrada: ${name}`);
|
|
150
|
+
return { ok: false, error: 'tool_not_found' };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const timeoutMs = options.timeout ? Number(options.timeout) * 1000 : undefined;
|
|
154
|
+
const result = executeTool(tool, input, { projectDir, timeoutMs });
|
|
155
|
+
|
|
156
|
+
if (result.stdout) logger.log(result.stdout);
|
|
157
|
+
if (result.stderr) logger.error(result.stderr);
|
|
158
|
+
|
|
159
|
+
if (!result.ok) {
|
|
160
|
+
logger.error(`Tool falhou (exit ${result.exitCode})${result.error ? `: ${result.error}` : ''}`);
|
|
161
|
+
return { ok: false, exitCode: result.exitCode, error: result.error };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return { ok: true, exitCode: result.exitCode, stdout: result.stdout };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async function handleUnregister(projectDir, options, logger) {
|
|
168
|
+
const name = String(options.name || '').trim();
|
|
169
|
+
if (!name) {
|
|
170
|
+
logger.error('--name é obrigatório');
|
|
171
|
+
return { ok: false, error: 'name_required' };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const handle = await openRuntimeDb(projectDir, { mustExist: true });
|
|
175
|
+
if (!handle) {
|
|
176
|
+
logger.error('Runtime store não encontrado.');
|
|
177
|
+
return { ok: false, error: 'no_runtime' };
|
|
178
|
+
}
|
|
179
|
+
const { db } = handle;
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
const tool = getDynamicTool(db, name);
|
|
183
|
+
if (!tool) {
|
|
184
|
+
logger.error(`Tool não encontrada: ${name}`);
|
|
185
|
+
return { ok: false, error: 'tool_not_found' };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
unregisterDynamicTool(db, name);
|
|
189
|
+
logger.log(`Tool removida: ${name}`);
|
|
190
|
+
return { ok: true, name };
|
|
191
|
+
} finally {
|
|
192
|
+
db.close();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async function handleShow(projectDir, options, logger) {
|
|
197
|
+
const name = String(options.name || '').trim();
|
|
198
|
+
if (!name) {
|
|
199
|
+
logger.error('--name é obrigatório');
|
|
200
|
+
return { ok: false, error: 'name_required' };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const handle = await openRuntimeDb(projectDir, { mustExist: true });
|
|
204
|
+
if (!handle) {
|
|
205
|
+
logger.error('Runtime store não encontrado.');
|
|
206
|
+
return { ok: false, error: 'no_runtime' };
|
|
207
|
+
}
|
|
208
|
+
const { db } = handle;
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
const tool = getDynamicTool(db, name);
|
|
212
|
+
if (!tool) {
|
|
213
|
+
logger.error(`Tool não encontrada: ${name}`);
|
|
214
|
+
return { ok: false, error: 'tool_not_found' };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
logger.log(`Tool: ${tool.name}`);
|
|
218
|
+
logger.log(`Descrição: ${tool.description}`);
|
|
219
|
+
logger.log(`Tipo: ${tool.handler_type}`);
|
|
220
|
+
if (tool.handler_code) logger.log(`Comando: ${tool.handler_code}`);
|
|
221
|
+
if (tool.handler_path) logger.log(`Script: ${tool.handler_path}`);
|
|
222
|
+
if (tool.squad_slug) logger.log(`Squad: ${tool.squad_slug}`);
|
|
223
|
+
if (tool.registered_by) logger.log(`Registrada por: ${tool.registered_by}`);
|
|
224
|
+
logger.log(`Registrada em: ${tool.registered_at}`);
|
|
225
|
+
|
|
226
|
+
return { ok: true, tool };
|
|
227
|
+
} finally {
|
|
228
|
+
db.close();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
module.exports = { runToolRegistry };
|
package/src/commands/update.js
CHANGED
|
@@ -28,6 +28,9 @@ async function runUpdate({ args, options, logger, t }) {
|
|
|
28
28
|
requestedLanguage ||
|
|
29
29
|
(context.parsed && context.data && context.data.conversation_language
|
|
30
30
|
? context.data.conversation_language
|
|
31
|
+
: null) ||
|
|
32
|
+
(result.savedProfile && result.savedProfile.locale
|
|
33
|
+
? result.savedProfile.locale
|
|
31
34
|
: 'en');
|
|
32
35
|
localeSync = await applyAgentLocale(targetDir, language, { dryRun });
|
|
33
36
|
}
|
|
@@ -35,6 +38,10 @@ async function runUpdate({ args, options, logger, t }) {
|
|
|
35
38
|
logger.log(t('update.done_at', { targetDir }));
|
|
36
39
|
logger.log(t('update.files_updated', { count: result.copied.length }));
|
|
37
40
|
logger.log(t('update.backups_created', { count: result.backedUp.length }));
|
|
41
|
+
if (!dryRun) {
|
|
42
|
+
logger.log('');
|
|
43
|
+
logger.log(t('update.reconfigure_hint'));
|
|
44
|
+
}
|
|
38
45
|
if (localeSync) {
|
|
39
46
|
if (dryRun) {
|
|
40
47
|
logger.log(t('locale_apply.dry_run_applied', { locale: localeSync.locale }));
|
package/src/constants.js
CHANGED
|
@@ -33,6 +33,7 @@ const MANAGED_FILES = [
|
|
|
33
33
|
'.aioson/agents/squad.md',
|
|
34
34
|
'.aioson/agents/orache.md',
|
|
35
35
|
'.aioson/agents/genome.md',
|
|
36
|
+
'.aioson/agents/design-hybrid-forge.md',
|
|
36
37
|
'.aioson/agents/profiler-researcher.md',
|
|
37
38
|
'.aioson/agents/profiler-enricher.md',
|
|
38
39
|
'.aioson/agents/profiler-forge.md',
|
|
@@ -349,6 +350,14 @@ const AGENT_DEFINITIONS = [
|
|
|
349
350
|
dependsOn: [],
|
|
350
351
|
output: '.aioson/genomes/[slug].md + .aioson/genomes/[slug].meta.json + optional binding in .aioson/squads/{slug}/squad.md or .aioson/squads/{slug}/squad.manifest.json'
|
|
351
352
|
},
|
|
353
|
+
{
|
|
354
|
+
id: 'design-hybrid-forge',
|
|
355
|
+
displayName: 'Design Hybrid Forge',
|
|
356
|
+
command: '@design-hybrid-forge',
|
|
357
|
+
path: '.aioson/agents/design-hybrid-forge.md',
|
|
358
|
+
dependsOn: ['.aioson/context/project.context.md'],
|
|
359
|
+
output: '.aioson/installed-skills/{hybrid-slug}/SKILL.md + .aioson/installed-skills/{hybrid-slug}/references/ + .aioson/installed-skills/{hybrid-slug}/previews/ + .aioson/installed-skills/{hybrid-slug}/.skill-meta.json'
|
|
360
|
+
},
|
|
352
361
|
{
|
|
353
362
|
id: 'profiler-researcher',
|
|
354
363
|
displayName: 'Profiler Researcher',
|