@jaimevalasek/aioson 1.4.0 → 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/CHANGELOG.md +31 -1
- package/LICENSE +661 -21
- package/README.md +9 -1
- 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/en/squad-dashboard.md +372 -0
- package/docs/openclaw-bridge.md +308 -0
- package/docs/pt/README.md +7 -0
- package/docs/pt/agent-sharding.md +132 -0
- package/docs/pt/agentes.md +131 -11
- package/docs/pt/busca-de-contexto.md +129 -0
- package/docs/pt/cache-de-contexto.md +156 -0
- package/docs/pt/cenarios.md +46 -2
- package/docs/pt/comandos-cli.md +88 -1
- package/docs/pt/design-hybrid-forge.md +107 -0
- package/docs/pt/inicio-rapido.md +72 -5
- 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/docs/pt/squad-dashboard.md +373 -0
- package/docs/testing/genome-2.0-matrix.md +5 -5
- package/docs/testing/genome-2.0-rollout.md +9 -9
- package/package.json +2 -2
- package/src/agent-loader.js +280 -0
- package/src/backup-local.js +74 -0
- package/src/cli.js +192 -0
- package/src/commands/agent-loader.js +85 -0
- package/src/commands/backup-local-cmd.js +25 -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/runtime.js +242 -0
- package/src/commands/sandbox.js +37 -0
- package/src/commands/setup-context.js +29 -4
- package/src/commands/setup.js +178 -0
- package/src/commands/skill.js +79 -32
- package/src/commands/squad-daemon.js +209 -0
- package/src/commands/squad-dashboard.js +39 -0
- package/src/commands/squad-deploy.js +64 -0
- package/src/commands/squad-doctor.js +52 -0
- package/src/commands/squad-mcp.js +270 -0
- package/src/commands/squad-processes.js +56 -0
- package/src/commands/squad-recovery.js +42 -0
- package/src/commands/squad-roi.js +291 -0
- package/src/commands/squad-score.js +250 -0
- package/src/commands/squad-status.js +37 -1
- package/src/commands/squad-validate.js +62 -1
- package/src/commands/squad-webhook.js +160 -0
- package/src/commands/squad-worker.js +191 -0
- package/src/commands/squad-worktrees.js +75 -0
- package/src/commands/tool-registry-cmd.js +232 -0
- package/src/commands/update.js +7 -0
- package/src/commands/web-map.js +70 -0
- package/src/commands/web-scrape.js +71 -0
- package/src/constants.js +17 -0
- package/src/context-cache.js +159 -0
- package/src/context-search.js +326 -0
- package/src/context-writer.js +45 -1
- package/src/design-variation-catalog.js +503 -0
- package/src/i18n/messages/en.js +159 -3
- package/src/i18n/messages/es.js +147 -2
- package/src/i18n/messages/fr.js +147 -2
- package/src/i18n/messages/pt-BR.js +158 -3
- 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/lib/webhook-server.js +328 -0
- package/src/mcp-connectors/registry.js +602 -0
- package/src/parser.js +7 -1
- package/src/recovery-context-session.js +154 -0
- package/src/runtime-store.js +355 -2
- package/src/sandbox.js +177 -0
- package/src/squad/external-session.js +180 -0
- package/src/squad/inter-squad.js +74 -0
- package/src/squad/recovery-context.js +201 -0
- package/src/squad/worktree-manager.js +114 -0
- package/src/squad-daemon.js +490 -0
- package/src/squad-dashboard/api.js +223 -0
- package/src/squad-dashboard/attachment-handler.js +93 -0
- package/src/squad-dashboard/context-monitor.js +157 -0
- package/src/squad-dashboard/execution-logs.js +115 -0
- package/src/squad-dashboard/hunk-review.js +209 -0
- package/src/squad-dashboard/metrics.js +133 -0
- package/src/squad-dashboard/process-monitor.js +125 -0
- package/src/squad-dashboard/renderer.js +858 -0
- package/src/squad-dashboard/server.js +232 -0
- package/src/squad-dashboard/styles.js +525 -0
- package/src/squad-dashboard/token-tracker.js +99 -0
- package/src/tool-executor.js +94 -0
- package/src/updater.js +11 -3
- package/src/web.js +284 -0
- package/src/worker-runner.js +339 -0
- package/template/.aioson/agents/analyst.md +62 -3
- package/template/.aioson/agents/architect.md +42 -0
- package/template/.aioson/agents/design-hybrid-forge.md +127 -0
- package/template/.aioson/agents/dev.md +223 -11
- package/template/.aioson/agents/deyvin.md +65 -0
- package/template/.aioson/agents/neo.md +152 -0
- package/template/.aioson/agents/orache.md +17 -0
- package/template/.aioson/agents/orchestrator.md +26 -0
- package/template/.aioson/agents/pm.md +58 -0
- package/template/.aioson/agents/product.md +88 -12
- package/template/.aioson/agents/qa.md +80 -0
- package/template/.aioson/agents/setup.md +128 -22
- package/template/.aioson/agents/sheldon.md +704 -0
- package/template/.aioson/agents/squad.md +191 -0
- package/template/.aioson/agents/tester.md +410 -0
- package/template/.aioson/agents/ux-ui.md +12 -0
- package/template/.aioson/config.md +21 -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/analyst.md +8 -0
- package/template/.aioson/locales/en/agents/architect.md +8 -0
- package/template/.aioson/locales/en/agents/dev.md +66 -7
- package/template/.aioson/locales/en/agents/deyvin.md +8 -0
- package/template/.aioson/locales/en/agents/neo.md +8 -0
- package/template/.aioson/locales/en/agents/orchestrator.md +26 -0
- package/template/.aioson/locales/en/agents/qa.md +49 -0
- package/template/.aioson/locales/en/agents/setup.md +35 -2
- package/template/.aioson/locales/en/agents/sheldon.md +340 -0
- package/template/.aioson/locales/en/agents/ux-ui.md +8 -0
- package/template/.aioson/locales/es/agents/analyst.md +8 -0
- package/template/.aioson/locales/es/agents/architect.md +8 -0
- package/template/.aioson/locales/es/agents/dev.md +66 -7
- package/template/.aioson/locales/es/agents/deyvin.md +8 -0
- package/template/.aioson/locales/es/agents/neo.md +48 -0
- package/template/.aioson/locales/es/agents/orchestrator.md +26 -0
- package/template/.aioson/locales/es/agents/qa.md +26 -0
- package/template/.aioson/locales/es/agents/setup.md +35 -2
- package/template/.aioson/locales/es/agents/sheldon.md +192 -0
- package/template/.aioson/locales/es/agents/squad.md +63 -0
- package/template/.aioson/locales/es/agents/ux-ui.md +8 -0
- package/template/.aioson/locales/fr/agents/analyst.md +8 -0
- package/template/.aioson/locales/fr/agents/architect.md +8 -0
- package/template/.aioson/locales/fr/agents/dev.md +66 -7
- package/template/.aioson/locales/fr/agents/deyvin.md +8 -0
- package/template/.aioson/locales/fr/agents/neo.md +48 -0
- package/template/.aioson/locales/fr/agents/orchestrator.md +26 -0
- package/template/.aioson/locales/fr/agents/qa.md +26 -0
- package/template/.aioson/locales/fr/agents/setup.md +35 -2
- package/template/.aioson/locales/fr/agents/sheldon.md +192 -0
- package/template/.aioson/locales/fr/agents/squad.md +63 -0
- package/template/.aioson/locales/fr/agents/ux-ui.md +8 -0
- package/template/.aioson/locales/pt-BR/agents/analyst.md +19 -0
- package/template/.aioson/locales/pt-BR/agents/architect.md +19 -0
- package/template/.aioson/locales/pt-BR/agents/dev.md +75 -12
- package/template/.aioson/locales/pt-BR/agents/deyvin.md +8 -0
- package/template/.aioson/locales/pt-BR/agents/neo.md +147 -0
- package/template/.aioson/locales/pt-BR/agents/orchestrator.md +26 -0
- package/template/.aioson/locales/pt-BR/agents/product.md +8 -3
- package/template/.aioson/locales/pt-BR/agents/qa.md +60 -0
- package/template/.aioson/locales/pt-BR/agents/setup.md +35 -2
- package/template/.aioson/locales/pt-BR/agents/sheldon.md +192 -0
- package/template/.aioson/locales/pt-BR/agents/squad.md +105 -0
- package/template/.aioson/locales/pt-BR/agents/ux-ui.md +8 -0
- package/template/.aioson/schemas/squad-blueprint.schema.json +21 -0
- package/template/.aioson/schemas/squad-manifest.schema.json +178 -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/bold-editorial-ui/SKILL.md +205 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/art-direction.md +338 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/components.md +977 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/dashboards.md +218 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/design-tokens.md +326 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/motion.md +461 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/patterns.md +293 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/websites.md +352 -0
- package/template/.aioson/skills/design/clean-saas-ui/SKILL.md +210 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/art-direction.md +319 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/components.md +365 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/dashboards.md +196 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/design-tokens.md +244 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/motion.md +235 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/patterns.md +215 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/websites.md +295 -0
- package/template/.aioson/skills/design/cognitive-core-ui/SKILL.md +55 -9
- package/template/.aioson/skills/design/cognitive-core-ui/references/art-direction.md +339 -0
- package/template/.aioson/skills/design/cognitive-core-ui/references/components.md +1 -1
- package/template/.aioson/skills/design/cognitive-core-ui/references/dashboards.md +100 -0
- package/template/.aioson/skills/design/cognitive-core-ui/references/design-tokens.md +43 -9
- package/template/.aioson/skills/design/cognitive-core-ui/references/motion.md +40 -0
- package/template/.aioson/skills/design/cognitive-core-ui/references/patterns.md +1 -1
- package/template/.aioson/skills/design/cognitive-core-ui/references/websites.md +99 -12
- 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/design/warm-craft-ui/SKILL.md +209 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/art-direction.md +324 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/components.md +508 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/dashboards.md +223 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/design-tokens.md +374 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/motion.md +356 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/patterns.md +288 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/websites.md +289 -0
- package/template/.aioson/skills/premium-visual-design/SKILL.md +83 -0
- package/template/.aioson/skills/premium-visual-design/components/agent-badge.md +92 -0
- package/template/.aioson/skills/premium-visual-design/components/dependency-node.md +102 -0
- package/template/.aioson/skills/premium-visual-design/components/mention-autocomplete.md +136 -0
- package/template/.aioson/skills/premium-visual-design/components/notification-center.md +136 -0
- package/template/.aioson/skills/premium-visual-design/components/review-action-bar.md +188 -0
- package/template/.aioson/skills/premium-visual-design/components/team-switcher.md +131 -0
- package/template/.aioson/skills/premium-visual-design/patterns/agent-message-thread.md +198 -0
- package/template/.aioson/skills/premium-visual-design/patterns/notification-panel.md +275 -0
- package/template/.aioson/skills/premium-visual-design/patterns/review-workflow-ui.md +234 -0
- package/template/.aioson/skills/premium-visual-design/patterns/task-dependency-graph.md +147 -0
- package/template/.aioson/skills/premium-visual-design/tokens/status-extended.md +142 -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/.aioson/skills/squad/formats/catalog.json +15 -0
- package/template/.aioson/skills/squad/formats/content/blog-post.md +47 -0
- package/template/.aioson/skills/squad/formats/content/newsletter.md +47 -0
- package/template/.aioson/skills/squad/formats/creative/podcast-script.md +43 -0
- package/template/.aioson/skills/squad/formats/creative/video-script.md +41 -0
- package/template/.aioson/skills/squad/formats/social/instagram-feed.md +42 -0
- package/template/.aioson/skills/squad/formats/social/linkedin-post.md +42 -0
- package/template/.aioson/skills/squad/formats/social/tiktok.md +39 -0
- package/template/.aioson/skills/squad/formats/social/twitter-thread.md +39 -0
- package/template/.aioson/skills/squad/formats/social/youtube-long.md +47 -0
- package/template/.aioson/skills/squad/formats/social/youtube-shorts.md +39 -0
- package/template/.aioson/skills/squad/patterns/multi-platform-pattern.md +108 -0
- package/template/.aioson/skills/squad/patterns/persona-based-pattern.md +98 -0
- package/template/.aioson/skills/squad/patterns/pipeline-pattern.md +106 -0
- package/template/.aioson/skills/squad/patterns/review-loop-pattern.md +81 -0
- package/template/.aioson/skills/squad/references/checklist-templates.md +122 -0
- package/template/.aioson/skills/squad/references/executor-archetypes.md +123 -0
- package/template/.aioson/skills/squad/references/workflow-templates.md +169 -0
- package/template/.aioson/skills/static/debugging-protocol.md +42 -0
- package/template/.aioson/skills/static/git-worktrees.md +36 -0
- package/template/.aioson/tasks/implementation-plan.md +19 -0
- package/template/.aioson/tasks/squad-design.md +28 -0
- package/template/.aioson/tasks/squad-profile.md +48 -0
- package/template/.aioson/tasks/squad-review.md +61 -0
- package/template/.aioson/tasks/squad-task-decompose.md +66 -0
- package/template/.claude/commands/aioson/agent/neo.md +5 -0
- package/template/.claude/commands/aioson/agent/tester.md +5 -0
- package/template/.gemini/GEMINI.md +1 -0
- package/template/.gemini/commands/aios-neo.toml +4 -0
- package/template/.gemini/commands/aios-tester.toml +6 -0
- package/template/AGENTS.md +26 -1
- package/template/CLAUDE.md +6 -2
- package/template/OPENCODE.md +2 -0
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,209 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs/promises');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const { SquadDaemon } = require('../squad-daemon');
|
|
6
|
+
const { openRuntimeDb } = require('../runtime-store');
|
|
7
|
+
|
|
8
|
+
async function handleStart(projectDir, squadSlug, options, { logger, t }) {
|
|
9
|
+
if (!squadSlug) {
|
|
10
|
+
logger.error(t('squad_daemon.squad_required'));
|
|
11
|
+
return { ok: false };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let squadConfig = {};
|
|
15
|
+
try {
|
|
16
|
+
const squadJsonPath = path.join(projectDir, '.aioson', 'squads', squadSlug, 'squad.json');
|
|
17
|
+
squadConfig = JSON.parse(await fs.readFile(squadJsonPath, 'utf8'));
|
|
18
|
+
} catch { /* squad.json is optional */ }
|
|
19
|
+
|
|
20
|
+
const daemon = new SquadDaemon(projectDir, squadSlug, {
|
|
21
|
+
port: options.port ? Number(options.port) : 0,
|
|
22
|
+
poll: options.poll ? Number(options.poll) : 10000,
|
|
23
|
+
config: squadConfig
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const info = await daemon.start();
|
|
28
|
+
logger.log(t('squad_daemon.started', {
|
|
29
|
+
squad: squadSlug,
|
|
30
|
+
port: info.port,
|
|
31
|
+
workers: info.workers,
|
|
32
|
+
cron: info.cronJobs
|
|
33
|
+
}));
|
|
34
|
+
logger.log(t('squad_daemon.webhook_hint', { port: info.port }));
|
|
35
|
+
logger.log(t('squad_daemon.stop_hint'));
|
|
36
|
+
|
|
37
|
+
// Keep alive until signal
|
|
38
|
+
await new Promise((resolve) => {
|
|
39
|
+
process.on('SIGINT', resolve);
|
|
40
|
+
process.on('SIGTERM', resolve);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
logger.log(t('squad_daemon.stopping'));
|
|
44
|
+
await daemon.stop();
|
|
45
|
+
return { ok: true, ...info };
|
|
46
|
+
} catch (err) {
|
|
47
|
+
logger.error(t('squad_daemon.start_failed', { error: err.message }));
|
|
48
|
+
return { ok: false, error: err.message };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function handleStatus(projectDir, squadSlug, { logger, t }) {
|
|
53
|
+
if (!squadSlug) {
|
|
54
|
+
// List all daemons
|
|
55
|
+
const handle = await openRuntimeDb(projectDir, { mustExist: true });
|
|
56
|
+
if (!handle) {
|
|
57
|
+
logger.error(t('squad_daemon.no_runtime'));
|
|
58
|
+
return { ok: false };
|
|
59
|
+
}
|
|
60
|
+
const { db } = handle;
|
|
61
|
+
try {
|
|
62
|
+
const daemons = db.prepare('SELECT * FROM squad_daemons ORDER BY squad_slug').all();
|
|
63
|
+
if (daemons.length === 0) {
|
|
64
|
+
logger.log(t('squad_daemon.no_daemons'));
|
|
65
|
+
return { ok: true, daemons: [] };
|
|
66
|
+
}
|
|
67
|
+
logger.log(`Daemons (${daemons.length}):`);
|
|
68
|
+
for (const d of daemons) {
|
|
69
|
+
const icon = d.status === 'running' ? '[*]' : '[ ]';
|
|
70
|
+
logger.log(` ${icon} ${d.squad_slug} (${d.status}) port:${d.port || '-'} pid:${d.pid || '-'} heartbeat:${d.last_heartbeat || '-'}`);
|
|
71
|
+
}
|
|
72
|
+
return { ok: true, daemons };
|
|
73
|
+
} finally {
|
|
74
|
+
db.close();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Specific squad daemon status
|
|
79
|
+
const handle = await openRuntimeDb(projectDir, { mustExist: true });
|
|
80
|
+
if (!handle) {
|
|
81
|
+
logger.error(t('squad_daemon.no_runtime'));
|
|
82
|
+
return { ok: false };
|
|
83
|
+
}
|
|
84
|
+
const { db } = handle;
|
|
85
|
+
try {
|
|
86
|
+
const record = db.prepare('SELECT * FROM squad_daemons WHERE squad_slug = ?').get(squadSlug);
|
|
87
|
+
if (!record) {
|
|
88
|
+
logger.log(t('squad_daemon.not_found', { squad: squadSlug }));
|
|
89
|
+
return { ok: true, daemon: null };
|
|
90
|
+
}
|
|
91
|
+
logger.log(`Daemon: ${record.squad_slug}`);
|
|
92
|
+
logger.log(` Status: ${record.status}`);
|
|
93
|
+
logger.log(` PID: ${record.pid || '-'}`);
|
|
94
|
+
logger.log(` Port: ${record.port || '-'}`);
|
|
95
|
+
logger.log(` Started: ${record.started_at || '-'}`);
|
|
96
|
+
logger.log(` Heartbeat: ${record.last_heartbeat || '-'}`);
|
|
97
|
+
if (record.error_message) logger.log(` Error: ${record.error_message}`);
|
|
98
|
+
if (record.config_json) {
|
|
99
|
+
try {
|
|
100
|
+
const config = JSON.parse(record.config_json);
|
|
101
|
+
if (config.cronJobs && config.cronJobs.length > 0) {
|
|
102
|
+
logger.log(` Cron Jobs:`);
|
|
103
|
+
for (const job of config.cronJobs) {
|
|
104
|
+
logger.log(` - ${job.worker} (${job.cron})`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
} catch { /* ignore */ }
|
|
108
|
+
}
|
|
109
|
+
return { ok: true, daemon: record };
|
|
110
|
+
} finally {
|
|
111
|
+
db.close();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function handleStop(projectDir, squadSlug, { logger, t }) {
|
|
116
|
+
if (!squadSlug) {
|
|
117
|
+
logger.error(t('squad_daemon.squad_required'));
|
|
118
|
+
return { ok: false };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const handle = await openRuntimeDb(projectDir, { mustExist: true });
|
|
122
|
+
if (!handle) {
|
|
123
|
+
logger.error(t('squad_daemon.no_runtime'));
|
|
124
|
+
return { ok: false };
|
|
125
|
+
}
|
|
126
|
+
const { db } = handle;
|
|
127
|
+
try {
|
|
128
|
+
const record = db.prepare('SELECT * FROM squad_daemons WHERE squad_slug = ?').get(squadSlug);
|
|
129
|
+
if (!record || record.status !== 'running') {
|
|
130
|
+
logger.log(t('squad_daemon.not_running', { squad: squadSlug }));
|
|
131
|
+
return { ok: true };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Try to kill the process
|
|
135
|
+
if (record.pid) {
|
|
136
|
+
try {
|
|
137
|
+
process.kill(record.pid, 'SIGTERM');
|
|
138
|
+
logger.log(t('squad_daemon.signal_sent', { squad: squadSlug, pid: record.pid }));
|
|
139
|
+
} catch {
|
|
140
|
+
logger.log(t('squad_daemon.process_gone', { squad: squadSlug }));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Update record
|
|
145
|
+
db.prepare(
|
|
146
|
+
"UPDATE squad_daemons SET status = 'stopped' WHERE squad_slug = ?"
|
|
147
|
+
).run(squadSlug);
|
|
148
|
+
|
|
149
|
+
return { ok: true };
|
|
150
|
+
} finally {
|
|
151
|
+
db.close();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function handleLogs(projectDir, squadSlug, { logger, t }) {
|
|
156
|
+
if (!squadSlug) {
|
|
157
|
+
logger.error(t('squad_daemon.squad_required'));
|
|
158
|
+
return { ok: false };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Show recent worker runs as daemon logs
|
|
162
|
+
const handle = await openRuntimeDb(projectDir, { mustExist: true });
|
|
163
|
+
if (!handle) {
|
|
164
|
+
logger.error(t('squad_daemon.no_runtime'));
|
|
165
|
+
return { ok: false };
|
|
166
|
+
}
|
|
167
|
+
const { db } = handle;
|
|
168
|
+
try {
|
|
169
|
+
const runs = db.prepare(
|
|
170
|
+
'SELECT * FROM worker_runs WHERE squad_slug = ? ORDER BY created_at DESC LIMIT 30'
|
|
171
|
+
).all(squadSlug);
|
|
172
|
+
if (runs.length === 0) {
|
|
173
|
+
logger.log(t('squad_daemon.no_logs'));
|
|
174
|
+
return { ok: true, runs: [] };
|
|
175
|
+
}
|
|
176
|
+
logger.log(`Recent daemon activity for "${squadSlug}" (${runs.length}):`);
|
|
177
|
+
for (const r of runs) {
|
|
178
|
+
const icon = r.status === 'completed' ? '[ok]' : r.status === 'failed' ? '[!!]' : '[..]';
|
|
179
|
+
const ms = r.duration_ms ? `${r.duration_ms}ms` : '-';
|
|
180
|
+
logger.log(` ${icon} ${r.created_at} ${r.worker_slug} (${r.trigger_type}) ${ms}`);
|
|
181
|
+
if (r.error_message) logger.log(` ${r.error_message}`);
|
|
182
|
+
}
|
|
183
|
+
return { ok: true, runs };
|
|
184
|
+
} finally {
|
|
185
|
+
db.close();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async function runSquadDaemon({ args, options, logger, t }) {
|
|
190
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
191
|
+
const sub = options.sub || 'status';
|
|
192
|
+
const squadSlug = options.squad;
|
|
193
|
+
|
|
194
|
+
switch (sub) {
|
|
195
|
+
case 'start':
|
|
196
|
+
return handleStart(targetDir, squadSlug, options, { logger, t });
|
|
197
|
+
case 'status':
|
|
198
|
+
return handleStatus(targetDir, squadSlug, { logger, t });
|
|
199
|
+
case 'stop':
|
|
200
|
+
return handleStop(targetDir, squadSlug, { logger, t });
|
|
201
|
+
case 'logs':
|
|
202
|
+
return handleLogs(targetDir, squadSlug, { logger, t });
|
|
203
|
+
default:
|
|
204
|
+
logger.error(t('squad_daemon.unknown_sub', { sub }));
|
|
205
|
+
return { ok: false };
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
module.exports = { runSquadDaemon };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const { createDashboardServer } = require('../squad-dashboard/server');
|
|
5
|
+
|
|
6
|
+
async function runSquadDashboard({ args, options, logger, t }) {
|
|
7
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
8
|
+
const port = Number(options.port) || 4180;
|
|
9
|
+
const filterSquad = options.squad || null;
|
|
10
|
+
|
|
11
|
+
const dashboard = createDashboardServer(targetDir, { port, squad: filterSquad });
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
const info = await dashboard.start();
|
|
15
|
+
logger.log(t('squad_dashboard.started', { url: info.url, port: info.port }));
|
|
16
|
+
if (filterSquad) {
|
|
17
|
+
logger.log(t('squad_dashboard.filtered', { squad: filterSquad }));
|
|
18
|
+
}
|
|
19
|
+
logger.log(t('squad_dashboard.stop_hint'));
|
|
20
|
+
|
|
21
|
+
// Keep the process alive until SIGINT/SIGTERM
|
|
22
|
+
await new Promise((resolve) => {
|
|
23
|
+
process.on('SIGINT', resolve);
|
|
24
|
+
process.on('SIGTERM', resolve);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
logger.log(t('squad_dashboard.stopping'));
|
|
28
|
+
await dashboard.stop();
|
|
29
|
+
return { ok: true, port: info.port, url: info.url };
|
|
30
|
+
} catch (err) {
|
|
31
|
+
if (err.code === 'EADDRINUSE') {
|
|
32
|
+
logger.error(t('squad_dashboard.port_in_use', { port }));
|
|
33
|
+
return { ok: false, error: `Port ${port} already in use` };
|
|
34
|
+
}
|
|
35
|
+
throw err;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = { runSquadDashboard };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs/promises');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
|
|
6
|
+
async function runSquadDeploy({ args, options, logger }) {
|
|
7
|
+
const squadSlug = args[0] || options.squad;
|
|
8
|
+
const projectDir = path.resolve(args[1] || options.path || '.');
|
|
9
|
+
const provider = options.provider || 'cloudpanel';
|
|
10
|
+
|
|
11
|
+
if (!squadSlug) {
|
|
12
|
+
logger.log('Uso: aioson squad:deploy <squad> [dir] --provider=cloudpanel');
|
|
13
|
+
return { ok: false };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const squadJsonPath = path.join(projectDir, '.aioson', 'squads', squadSlug, 'squad.json');
|
|
17
|
+
let squadConfig;
|
|
18
|
+
try {
|
|
19
|
+
squadConfig = JSON.parse(await fs.readFile(squadJsonPath, 'utf8'));
|
|
20
|
+
} catch {
|
|
21
|
+
logger.log(`Squad "${squadSlug}" não encontrado em ${squadJsonPath}`);
|
|
22
|
+
return { ok: false, error: 'squad_not_found' };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const port = squadConfig.port || 3001;
|
|
26
|
+
const deployDir = path.join(projectDir, '.aioson', 'squads', squadSlug, 'deploy');
|
|
27
|
+
await fs.mkdir(deployDir, { recursive: true });
|
|
28
|
+
|
|
29
|
+
const nginxConf = generateNginxConf(squadSlug, port, provider);
|
|
30
|
+
const outPath = path.join(deployDir, 'nginx.conf');
|
|
31
|
+
await fs.writeFile(outPath, nginxConf);
|
|
32
|
+
|
|
33
|
+
logger.log(`✓ Configuração nginx gerada: ${outPath}`);
|
|
34
|
+
logger.log('');
|
|
35
|
+
logger.log('Instruções CloudPanel:');
|
|
36
|
+
logger.log(' 1. Acesse CloudPanel → Websites → [seu site] → Nginx');
|
|
37
|
+
logger.log(' 2. Cole o conteúdo do arquivo nginx.conf em "Custom Nginx Directives"');
|
|
38
|
+
logger.log(' 3. Salve e aguarde o reload automático do nginx');
|
|
39
|
+
logger.log(` 4. Certifique-se que o daemon está rodando: aioson squad:daemon ${squadSlug} start`);
|
|
40
|
+
|
|
41
|
+
return { ok: true, path: outPath };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function generateNginxConf(slug, port, provider) {
|
|
45
|
+
return [
|
|
46
|
+
`# Squad: ${slug} — gerado por aioson squad:deploy`,
|
|
47
|
+
`# Provider: ${provider}`,
|
|
48
|
+
`# Cole em: CloudPanel → Website → Nginx → Custom Nginx Directives`,
|
|
49
|
+
`#`,
|
|
50
|
+
`# Pré-requisito: aioson squad:daemon ${slug} start`,
|
|
51
|
+
``,
|
|
52
|
+
`location /${slug}/webhook/ {`,
|
|
53
|
+
` proxy_pass http://127.0.0.1:${port}/webhook/;`,
|
|
54
|
+
` proxy_http_version 1.1;`,
|
|
55
|
+
` proxy_set_header Host $host;`,
|
|
56
|
+
` proxy_set_header X-Real-IP $remote_addr;`,
|
|
57
|
+
` proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;`,
|
|
58
|
+
` proxy_read_timeout 30s;`,
|
|
59
|
+
` proxy_connect_timeout 5s;`,
|
|
60
|
+
`}`,
|
|
61
|
+
].join('\n');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = { runSquadDeploy, generateNginxConf };
|
|
@@ -5,6 +5,7 @@ const path = require('node:path');
|
|
|
5
5
|
const { openRuntimeDb } = require('../runtime-store');
|
|
6
6
|
const { exists } = require('../utils');
|
|
7
7
|
const { runSquadValidate } = require('./squad-validate');
|
|
8
|
+
const { scoreCompletude, scoreProfundidade, scoreQualidadeEstrutural, scorePotencial, gradeFromScore } = require('./squad-score');
|
|
8
9
|
|
|
9
10
|
function normalizeRel(value) {
|
|
10
11
|
return String(value || '')
|
|
@@ -259,6 +260,36 @@ async function runSquadDoctor({ args, options = {}, logger, t }) {
|
|
|
259
260
|
));
|
|
260
261
|
}
|
|
261
262
|
|
|
263
|
+
// Webhook production checks (from squad.json, optional file)
|
|
264
|
+
const squadJsonPath = path.join(paths.packageDir, 'squad.json');
|
|
265
|
+
let squadConfig = null;
|
|
266
|
+
try {
|
|
267
|
+
const raw = await fs.readFile(squadJsonPath, 'utf8');
|
|
268
|
+
squadConfig = JSON.parse(raw);
|
|
269
|
+
} catch { /* squad.json is optional */ }
|
|
270
|
+
|
|
271
|
+
if (squadConfig && squadConfig.webhook?.validate_signature) {
|
|
272
|
+
const envKey = squadConfig.webhook.signature_env || 'WEBHOOK_SECRET';
|
|
273
|
+
const defined = Boolean(process.env[envKey]);
|
|
274
|
+
checks.push(makeCheck(
|
|
275
|
+
`webhook_env_${envKey}`,
|
|
276
|
+
defined,
|
|
277
|
+
defined ? 'info' : 'error',
|
|
278
|
+
defined
|
|
279
|
+
? `Env ${envKey} definida (HMAC validation enabled)`
|
|
280
|
+
: `Env ${envKey} não definida — webhook HMAC validation está ativo mas a variável está ausente`
|
|
281
|
+
));
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (squadConfig && squadConfig.webhook?.public) {
|
|
285
|
+
checks.push(makeCheck(
|
|
286
|
+
'webhook_public_deploy',
|
|
287
|
+
null,
|
|
288
|
+
'warn',
|
|
289
|
+
'Config nginx: execute aioson squad:deploy para gerar nginx.conf'
|
|
290
|
+
));
|
|
291
|
+
}
|
|
292
|
+
|
|
262
293
|
const runtimeHandle = await openRuntimeDb(targetDir, { mustExist: true });
|
|
263
294
|
if (!runtimeHandle) {
|
|
264
295
|
checks.push(makeCheck('runtime_store', false, 'warn', t('squad_doctor.check_runtime_missing')));
|
|
@@ -347,6 +378,27 @@ async function runSquadDoctor({ args, options = {}, logger, t }) {
|
|
|
347
378
|
checks.push(makeCheck('formal_validation', true, 'info', 'Manifest formally valid'));
|
|
348
379
|
}
|
|
349
380
|
|
|
381
|
+
// Quality score
|
|
382
|
+
try {
|
|
383
|
+
const d1 = scoreCompletude(manifest);
|
|
384
|
+
const d2 = scoreProfundidade(manifest);
|
|
385
|
+
const d3 = scoreQualidadeEstrutural(manifest);
|
|
386
|
+
const d4 = scorePotencial(manifest);
|
|
387
|
+
const total = d1.score + d2.score + d3.score + d4.score;
|
|
388
|
+
const maxTotal = d1.max + d2.max + d3.max + d4.max;
|
|
389
|
+
const grade = gradeFromScore(total);
|
|
390
|
+
const isLow = total < 50;
|
|
391
|
+
checks.push(
|
|
392
|
+
makeCheck(
|
|
393
|
+
'quality_score',
|
|
394
|
+
!isLow,
|
|
395
|
+
'info',
|
|
396
|
+
`Quality score: ${total}/${maxTotal} — ${grade}`,
|
|
397
|
+
{ qualityScore: { total, max: maxTotal, grade } }
|
|
398
|
+
)
|
|
399
|
+
);
|
|
400
|
+
} catch { /* scoring not critical */ }
|
|
401
|
+
|
|
350
402
|
const summary = {
|
|
351
403
|
failed: checks.filter((check) => check.severity === 'error' && !check.ok).length,
|
|
352
404
|
warned: checks.filter((check) => check.severity === 'warn' && !check.ok).length,
|