@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
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const { withIndex } = require('../context-search');
|
|
5
|
+
|
|
6
|
+
async function runContextSearch({ args, options, logger }) {
|
|
7
|
+
const query = args[0] || options.query || '';
|
|
8
|
+
const cwd = path.resolve(process.cwd(), options.cwd || '.');
|
|
9
|
+
const limit = Number(options.limit) || 10;
|
|
10
|
+
|
|
11
|
+
if (!query) {
|
|
12
|
+
logger.log('Usage: aioson context:search <query> [--limit=10] [--cwd=.]');
|
|
13
|
+
return { ok: false, error: 'missing_query' };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const results = await withIndex(async (idx) => {
|
|
17
|
+
return idx.search(query, { limit, projectDir: cwd });
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
if (options.json) {
|
|
21
|
+
return { ok: true, results };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (results.length === 0) {
|
|
25
|
+
logger.log(`No results for: ${query}`);
|
|
26
|
+
return { ok: true, results: [] };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
logger.log(`\n Search results for: "${query}"\n`);
|
|
30
|
+
for (let i = 0; i < results.length; i++) {
|
|
31
|
+
const r = results[i];
|
|
32
|
+
logger.log(` ${i + 1}. ${r.title}`);
|
|
33
|
+
logger.log(` ${r.relPath}`);
|
|
34
|
+
if (r.snippet) {
|
|
35
|
+
logger.log(` ${r.snippet.replace(/\n/g, ' ')}`);
|
|
36
|
+
}
|
|
37
|
+
logger.log('');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return { ok: true, results };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function runContextSearchIndex({ args, options, logger }) {
|
|
44
|
+
const cwd = path.resolve(process.cwd(), args[0] || '.');
|
|
45
|
+
const force = Boolean(options.force);
|
|
46
|
+
|
|
47
|
+
logger.log(`Indexing: ${cwd} ...`);
|
|
48
|
+
|
|
49
|
+
const result = await withIndex(async (idx) => {
|
|
50
|
+
const r = await idx.indexDirectory(cwd, { force });
|
|
51
|
+
const stats = idx.stats();
|
|
52
|
+
return { ...r, stats };
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
if (options.json) {
|
|
56
|
+
return { ok: true, ...result };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
logger.log(` Indexed: ${result.indexed} files`);
|
|
60
|
+
logger.log(` Skipped: ${result.skipped} files (already indexed)`);
|
|
61
|
+
logger.log(` Total in index: ${result.stats.totalDocs} docs`);
|
|
62
|
+
|
|
63
|
+
return { ok: true, ...result };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = { runContextSearch, runContextSearchIndex };
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs/promises');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const readline = require('node:readline');
|
|
6
|
+
const { validateProjectContextFile } = require('../context');
|
|
7
|
+
const { resolveAgentLocale } = require('../locales');
|
|
8
|
+
const { ensureDir } = require('../utils');
|
|
9
|
+
const {
|
|
10
|
+
getDesignVariationCatalog,
|
|
11
|
+
getDesignVariationSources
|
|
12
|
+
} = require('../design-variation-catalog');
|
|
13
|
+
|
|
14
|
+
function resolveTargetDir(args) {
|
|
15
|
+
return path.resolve(process.cwd(), args[0] || '.');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function detectProjectLocale(targetDir) {
|
|
19
|
+
const context = await validateProjectContextFile(targetDir);
|
|
20
|
+
if (context.parsed && context.data && context.data.conversation_language) {
|
|
21
|
+
return {
|
|
22
|
+
locale: resolveAgentLocale(context.data.conversation_language),
|
|
23
|
+
source: 'project-context'
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
locale: 'en',
|
|
28
|
+
source: 'default'
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function resolveLocale(optionsLocale, projectLocale) {
|
|
33
|
+
return resolveAgentLocale(optionsLocale || projectLocale || 'en');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function formatTimestamp(date = new Date()) {
|
|
37
|
+
const pad = (value) => String(value).padStart(2, '0');
|
|
38
|
+
return [
|
|
39
|
+
date.getUTCFullYear(),
|
|
40
|
+
pad(date.getUTCMonth() + 1),
|
|
41
|
+
pad(date.getUTCDate())
|
|
42
|
+
].join('') + '-' + [
|
|
43
|
+
pad(date.getUTCHours()),
|
|
44
|
+
pad(date.getUTCMinutes()),
|
|
45
|
+
pad(date.getUTCSeconds())
|
|
46
|
+
].join('');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function getUiText(locale) {
|
|
50
|
+
if (locale === 'pt-BR') {
|
|
51
|
+
return {
|
|
52
|
+
title: 'AIOSON — Opções do Design Hybrid',
|
|
53
|
+
instructions: 'Use ↑/↓ para mover, espaço para marcar, enter para confirmar, q para cancelar.',
|
|
54
|
+
launching: 'Abrindo seletor de variações de design...',
|
|
55
|
+
saved: 'Preset de variação salvo.',
|
|
56
|
+
path: 'Arquivo ativo',
|
|
57
|
+
history: 'Histórico',
|
|
58
|
+
promptReady: 'Bloco pronto para usar com @design-hybrid-forge:',
|
|
59
|
+
presetHeading: '# Preset de Variação de Design',
|
|
60
|
+
presetIntro: 'Use este arquivo como overlay de variação para `@design-hybrid-forge` ou `/design-hybrid-forge`. O arquivo ativo deve ser arquivado após a skill híbrida ser gerada; a cópia em histórico permanece como trilha de criação.',
|
|
61
|
+
selectedVariations: '## Variações selecionadas',
|
|
62
|
+
presetPolicy: '## Política do preset',
|
|
63
|
+
presetPolicyLines: [
|
|
64
|
+
'- Este preset é temporário e serve apenas para a próxima geração da skill híbrida.',
|
|
65
|
+
'- Após a geração, mova ou apague `.aioson/context/design-variation-preset.md`.',
|
|
66
|
+
'- O histórico em `.aioson/context/history/design-variation-presets/` deve ser preservado.',
|
|
67
|
+
'- O layout padrão do projeto continua sendo definido pela `design_skill` ativa, não por este preset.'
|
|
68
|
+
],
|
|
69
|
+
promptBlock: '## Bloco para prompt',
|
|
70
|
+
sources: '## Fontes',
|
|
71
|
+
none: 'nenhum',
|
|
72
|
+
ttyError: 'Execute este comando em um terminal interativo, ou use --json para inspecionar o catálogo.'
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
title: 'AIOSON — Design Hybrid Options',
|
|
78
|
+
instructions: 'Use ↑/↓ to move, space to toggle, enter to confirm, q to cancel.',
|
|
79
|
+
launching: 'Launching design variation picker...',
|
|
80
|
+
saved: 'Design variation preset saved.',
|
|
81
|
+
path: 'Active file',
|
|
82
|
+
history: 'History',
|
|
83
|
+
promptReady: 'Prompt block ready for @design-hybrid-forge:',
|
|
84
|
+
presetHeading: '# Design Variation Preset',
|
|
85
|
+
presetIntro: 'Use this file as a variation overlay for `@design-hybrid-forge` or `/design-hybrid-forge`. The active file should be archived after the hybrid skill is generated; the history copy remains as the creation trail.',
|
|
86
|
+
selectedVariations: '## Selected variations',
|
|
87
|
+
presetPolicy: '## Preset policy',
|
|
88
|
+
presetPolicyLines: [
|
|
89
|
+
'- This preset is temporary and should drive only the next hybrid skill generation.',
|
|
90
|
+
'- After generation, move or delete `.aioson/context/design-variation-preset.md`.',
|
|
91
|
+
'- Keep the history copy in `.aioson/context/history/design-variation-presets/`.',
|
|
92
|
+
'- The project default layout still comes from the active `design_skill`, not from this preset.'
|
|
93
|
+
],
|
|
94
|
+
promptBlock: '## Prompt block',
|
|
95
|
+
sources: '## Sources',
|
|
96
|
+
none: 'none',
|
|
97
|
+
ttyError: 'Run this command in an interactive terminal, or use --json to inspect the catalog.'
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function clearScreen(stdout = process.stdout) {
|
|
102
|
+
stdout.write('\x1Bc');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function renderGroup(group, cursor, selected, ui, stdout = process.stdout) {
|
|
106
|
+
clearScreen(stdout);
|
|
107
|
+
stdout.write(`${ui.title}\n\n`);
|
|
108
|
+
stdout.write(`${group.title}\n`);
|
|
109
|
+
stdout.write(`${group.guidance}\n`);
|
|
110
|
+
stdout.write(`${ui.instructions}\n\n`);
|
|
111
|
+
|
|
112
|
+
for (let i = 0; i < group.options.length; i++) {
|
|
113
|
+
const option = group.options[i];
|
|
114
|
+
const isActive = i === cursor;
|
|
115
|
+
const isSelected = selected.has(option.id);
|
|
116
|
+
const marker = isSelected ? '[x]' : '[ ]';
|
|
117
|
+
const pointer = isActive ? '>' : ' ';
|
|
118
|
+
stdout.write(`${pointer} ${marker} ${option.label}\n`);
|
|
119
|
+
stdout.write(` ${option.description}\n`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function promptMultiSelectGroup(group, ui, io = {}) {
|
|
124
|
+
const stdin = io.stdin || process.stdin;
|
|
125
|
+
const stdout = io.stdout || process.stdout;
|
|
126
|
+
|
|
127
|
+
if (!stdin.isTTY || !stdout.isTTY) {
|
|
128
|
+
throw new Error('Interactive design-hybrid:options requires a TTY terminal.');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
readline.emitKeypressEvents(stdin);
|
|
132
|
+
const wasRaw = Boolean(stdin.isRaw);
|
|
133
|
+
const wasPaused = typeof stdin.isPaused === 'function' ? stdin.isPaused() : true;
|
|
134
|
+
if (typeof stdin.setRawMode === 'function') stdin.setRawMode(true);
|
|
135
|
+
if (typeof stdin.resume === 'function') stdin.resume();
|
|
136
|
+
|
|
137
|
+
let cursor = 0;
|
|
138
|
+
const selected = new Set();
|
|
139
|
+
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
let cleanedUp = false;
|
|
142
|
+
|
|
143
|
+
function cleanup() {
|
|
144
|
+
if (cleanedUp) return;
|
|
145
|
+
cleanedUp = true;
|
|
146
|
+
stdin.removeListener('keypress', onKeypress);
|
|
147
|
+
if (stdin.listenerCount('keypress') === 0 && stdin.listenerCount('data') > 0) {
|
|
148
|
+
stdin.emit('data', Buffer.alloc(0));
|
|
149
|
+
}
|
|
150
|
+
if (typeof stdin.setRawMode === 'function') stdin.setRawMode(wasRaw);
|
|
151
|
+
if (wasPaused && typeof stdin.pause === 'function') stdin.pause();
|
|
152
|
+
stdout.write('\n');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function onKeypress(_str, key) {
|
|
156
|
+
if (key && key.ctrl && key.name === 'c') {
|
|
157
|
+
cleanup();
|
|
158
|
+
reject(new Error('Interrupted'));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (key && key.name === 'q') {
|
|
163
|
+
cleanup();
|
|
164
|
+
reject(new Error('Cancelled'));
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (key && key.name === 'up') {
|
|
169
|
+
cursor = cursor === 0 ? group.options.length - 1 : cursor - 1;
|
|
170
|
+
renderGroup(group, cursor, selected, ui, stdout);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (key && key.name === 'down') {
|
|
175
|
+
cursor = cursor === group.options.length - 1 ? 0 : cursor + 1;
|
|
176
|
+
renderGroup(group, cursor, selected, ui, stdout);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (key && key.name === 'space') {
|
|
181
|
+
const id = group.options[cursor].id;
|
|
182
|
+
if (selected.has(id)) selected.delete(id);
|
|
183
|
+
else selected.add(id);
|
|
184
|
+
renderGroup(group, cursor, selected, ui, stdout);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (key && key.name === 'return') {
|
|
189
|
+
cleanup();
|
|
190
|
+
resolve(group.options.filter((option) => selected.has(option.id)));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
stdin.on('keypress', onKeypress);
|
|
195
|
+
renderGroup(group, cursor, selected, ui, stdout);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function buildPromptBlock(selections) {
|
|
200
|
+
const lines = ['variation_overlay:'];
|
|
201
|
+
for (const group of selections.__groups) {
|
|
202
|
+
const chosen = selections[group.id] || [];
|
|
203
|
+
lines.push(` ${group.id}:`);
|
|
204
|
+
if (chosen.length === 0) {
|
|
205
|
+
lines.push(' - none');
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
for (const option of chosen) {
|
|
209
|
+
lines.push(` - ${option.id}`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return lines.join('\n');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function buildPresetMarkdown(selections, locale, options = {}) {
|
|
216
|
+
const generatedAt = new Date().toISOString();
|
|
217
|
+
const oneShot = options.oneShot !== false;
|
|
218
|
+
const modifierPolicy = options.advanced ? 'up_to_3_modifiers' : 'up_to_2_modifiers';
|
|
219
|
+
const ui = getUiText(locale);
|
|
220
|
+
const lines = [
|
|
221
|
+
'---',
|
|
222
|
+
'preset_type: design-variation',
|
|
223
|
+
`locale: "${locale}"`,
|
|
224
|
+
`consumption_mode: "${oneShot ? 'archive_after_generation' : 'persistent'}"`,
|
|
225
|
+
`modifier_policy: "${modifierPolicy}"`,
|
|
226
|
+
`generated_at: "${generatedAt}"`,
|
|
227
|
+
'---',
|
|
228
|
+
'',
|
|
229
|
+
ui.presetHeading,
|
|
230
|
+
'',
|
|
231
|
+
ui.presetIntro,
|
|
232
|
+
'',
|
|
233
|
+
ui.selectedVariations
|
|
234
|
+
];
|
|
235
|
+
|
|
236
|
+
for (const group of selections.__groups) {
|
|
237
|
+
lines.push('');
|
|
238
|
+
lines.push(`### ${group.title}`);
|
|
239
|
+
const chosen = selections[group.id] || [];
|
|
240
|
+
if (chosen.length === 0) {
|
|
241
|
+
lines.push(`- ${ui.none}`);
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
for (const option of chosen) {
|
|
245
|
+
lines.push(`- ${option.label} — ${option.description}`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
lines.push('');
|
|
250
|
+
lines.push(ui.presetPolicy);
|
|
251
|
+
lines.push('');
|
|
252
|
+
for (const line of ui.presetPolicyLines) {
|
|
253
|
+
lines.push(line);
|
|
254
|
+
}
|
|
255
|
+
lines.push('');
|
|
256
|
+
lines.push(ui.promptBlock);
|
|
257
|
+
lines.push('');
|
|
258
|
+
lines.push('```yaml');
|
|
259
|
+
lines.push(buildPromptBlock(selections));
|
|
260
|
+
lines.push('```');
|
|
261
|
+
lines.push('');
|
|
262
|
+
lines.push(ui.sources);
|
|
263
|
+
for (const source of selections.__sources) {
|
|
264
|
+
lines.push(`- ${source.label}: ${source.url}`);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return `${lines.join('\n')}\n`;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function buildSummary(selections) {
|
|
271
|
+
const parts = [];
|
|
272
|
+
for (const group of selections.__groups) {
|
|
273
|
+
const chosen = selections[group.id] || [];
|
|
274
|
+
if (chosen.length === 0) continue;
|
|
275
|
+
parts.push(`${group.title}: ${chosen.map((item) => item.label).join(', ')}`);
|
|
276
|
+
}
|
|
277
|
+
return parts;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
async function runDesignHybridOptions({ args, options = {}, logger, io = {} }) {
|
|
281
|
+
const targetDir = resolveTargetDir(args);
|
|
282
|
+
const presetPath = path.join(targetDir, '.aioson/context/design-variation-preset.md');
|
|
283
|
+
const historyDir = path.join(targetDir, '.aioson/context/history/design-variation-presets');
|
|
284
|
+
const stdin = io.stdin || process.stdin;
|
|
285
|
+
const stdout = io.stdout || process.stdout;
|
|
286
|
+
const projectLocaleResult = await detectProjectLocale(targetDir);
|
|
287
|
+
const projectLocale = projectLocaleResult.locale;
|
|
288
|
+
const localeOption = options.locale || options.language || options.lang;
|
|
289
|
+
const locale = resolveLocale(localeOption, projectLocale);
|
|
290
|
+
const ui = getUiText(locale);
|
|
291
|
+
const groups = getDesignVariationCatalog(locale);
|
|
292
|
+
const sources = getDesignVariationSources(locale);
|
|
293
|
+
const advanced = Boolean(options.advanced);
|
|
294
|
+
const modifierPolicy = advanced ? 'up_to_3_modifiers' : 'up_to_2_modifiers';
|
|
295
|
+
const localeSource = localeOption ? 'option' : projectLocaleResult.source;
|
|
296
|
+
|
|
297
|
+
if (options.json) {
|
|
298
|
+
return {
|
|
299
|
+
ok: true,
|
|
300
|
+
targetDir,
|
|
301
|
+
locale,
|
|
302
|
+
localeSource,
|
|
303
|
+
projectLocale,
|
|
304
|
+
advanced,
|
|
305
|
+
modifierPolicy,
|
|
306
|
+
presetPath: path.relative(targetDir, presetPath),
|
|
307
|
+
historyDir: path.relative(targetDir, historyDir),
|
|
308
|
+
groups,
|
|
309
|
+
sources
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (!stdin.isTTY || !stdout.isTTY) {
|
|
314
|
+
logger.log(ui.ttyError);
|
|
315
|
+
return {
|
|
316
|
+
ok: false,
|
|
317
|
+
error: 'TTY required',
|
|
318
|
+
message: ui.ttyError
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
logger.log(ui.launching);
|
|
323
|
+
const selections = {
|
|
324
|
+
__groups: groups,
|
|
325
|
+
__sources: sources
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
for (const group of groups) {
|
|
329
|
+
const chosen = await promptMultiSelectGroup(group, ui, { stdin, stdout });
|
|
330
|
+
selections[group.id] = chosen;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const content = buildPresetMarkdown(selections, locale, {
|
|
334
|
+
oneShot: options['persistent'] !== true,
|
|
335
|
+
advanced
|
|
336
|
+
});
|
|
337
|
+
const historyPath = path.join(historyDir, `${formatTimestamp()}.md`);
|
|
338
|
+
await ensureDir(path.dirname(presetPath));
|
|
339
|
+
await ensureDir(historyDir);
|
|
340
|
+
await fs.writeFile(presetPath, content, 'utf8');
|
|
341
|
+
await fs.writeFile(historyPath, content, 'utf8');
|
|
342
|
+
|
|
343
|
+
const summary = buildSummary(selections);
|
|
344
|
+
logger.log(`${ui.saved}\n`);
|
|
345
|
+
logger.log(`${ui.path}: ${path.relative(targetDir, presetPath)}\n`);
|
|
346
|
+
logger.log(`${ui.history}: ${path.relative(targetDir, historyPath)}\n`);
|
|
347
|
+
if (summary.length > 0) {
|
|
348
|
+
for (const line of summary) logger.log(`- ${line}`);
|
|
349
|
+
logger.log('');
|
|
350
|
+
}
|
|
351
|
+
logger.log(ui.promptReady);
|
|
352
|
+
logger.log('');
|
|
353
|
+
logger.log(buildPromptBlock(selections));
|
|
354
|
+
|
|
355
|
+
return {
|
|
356
|
+
ok: true,
|
|
357
|
+
targetDir,
|
|
358
|
+
locale,
|
|
359
|
+
localeSource,
|
|
360
|
+
projectLocale,
|
|
361
|
+
advanced,
|
|
362
|
+
modifierPolicy,
|
|
363
|
+
presetPath: path.relative(targetDir, presetPath),
|
|
364
|
+
historyPath: path.relative(targetDir, historyPath),
|
|
365
|
+
selections: Object.fromEntries(
|
|
366
|
+
Object.entries(selections)
|
|
367
|
+
.filter(([key]) => !key.startsWith('__'))
|
|
368
|
+
.map(([key, value]) => [
|
|
369
|
+
key,
|
|
370
|
+
Array.isArray(value) ? value.map((item) => item.id) : value
|
|
371
|
+
])
|
|
372
|
+
)
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
module.exports = {
|
|
377
|
+
runDesignHybridOptions,
|
|
378
|
+
__test__: {
|
|
379
|
+
getUiText,
|
|
380
|
+
promptMultiSelectGroup,
|
|
381
|
+
buildPresetMarkdown,
|
|
382
|
+
buildPromptBlock,
|
|
383
|
+
buildSummary
|
|
384
|
+
}
|
|
385
|
+
};
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const fs = require('node:fs/promises');
|
|
5
|
+
const { openRuntimeDb, listSquadLearnings, listProjectLearnings, listDynamicTools } = require('../runtime-store');
|
|
6
|
+
|
|
7
|
+
const MIN_FREQUENCY = 2;
|
|
8
|
+
const INACTIVITY_DAYS = 14;
|
|
9
|
+
const EVOLUTION_DIR = path.join('.aioson', 'evolution');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Verifica se há tools com handlers inválidos.
|
|
13
|
+
*/
|
|
14
|
+
async function checkBrokenTools(tools, projectDir) {
|
|
15
|
+
const broken = [];
|
|
16
|
+
for (const tool of tools) {
|
|
17
|
+
if (tool.handler_type === 'script' && tool.handler_path) {
|
|
18
|
+
const absPath = path.isAbsolute(tool.handler_path)
|
|
19
|
+
? tool.handler_path
|
|
20
|
+
: path.resolve(projectDir, tool.handler_path);
|
|
21
|
+
try {
|
|
22
|
+
await fs.access(absPath);
|
|
23
|
+
} catch {
|
|
24
|
+
broken.push(tool.name);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return broken;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Conta learnings prontos para evoluir.
|
|
33
|
+
*/
|
|
34
|
+
function countEvolvablelearnings(db) {
|
|
35
|
+
const squadLearnings = listSquadLearnings(db, null, 'active').filter(
|
|
36
|
+
(l) => Number(l.frequency || 1) >= MIN_FREQUENCY
|
|
37
|
+
);
|
|
38
|
+
const projectLearnings = listProjectLearnings(db, 'active').filter(
|
|
39
|
+
(l) => Number(l.frequency || 1) >= MIN_FREQUENCY
|
|
40
|
+
);
|
|
41
|
+
return squadLearnings.length + projectLearnings.length;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Verifica squads inativos (sem sessão recente).
|
|
46
|
+
*/
|
|
47
|
+
function getInactiveSquads(db) {
|
|
48
|
+
const cutoff = new Date(Date.now() - INACTIVITY_DAYS * 24 * 60 * 60 * 1000).toISOString();
|
|
49
|
+
const rows = db.prepare(`
|
|
50
|
+
SELECT squad_slug, updated_at FROM squads
|
|
51
|
+
WHERE status = 'active' AND (updated_at IS NULL OR updated_at < ?)
|
|
52
|
+
ORDER BY updated_at ASC
|
|
53
|
+
LIMIT 5
|
|
54
|
+
`).all(cutoff);
|
|
55
|
+
return rows;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Conta arquivos pendentes de evolução.
|
|
60
|
+
*/
|
|
61
|
+
async function countPendingEvolutions(projectDir) {
|
|
62
|
+
const evolutionDir = path.resolve(projectDir, EVOLUTION_DIR);
|
|
63
|
+
try {
|
|
64
|
+
const files = await fs.readdir(evolutionDir);
|
|
65
|
+
return files.filter((f) => f.startsWith('pending-') && f.endsWith('.json')).length;
|
|
66
|
+
} catch {
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Comando principal: aioson health [project-dir]
|
|
73
|
+
*/
|
|
74
|
+
async function runHealth({ args = [], options = {}, logger = console } = {}) {
|
|
75
|
+
const projectDir = path.resolve(process.cwd(), args[0] || '.');
|
|
76
|
+
const quiet = Boolean(options.quiet);
|
|
77
|
+
const json = Boolean(options.json);
|
|
78
|
+
|
|
79
|
+
const handle = await openRuntimeDb(projectDir, { mustExist: true });
|
|
80
|
+
|
|
81
|
+
const report = {
|
|
82
|
+
ok: true,
|
|
83
|
+
projectDir,
|
|
84
|
+
items: [],
|
|
85
|
+
evolvableLearnings: 0,
|
|
86
|
+
brokenTools: [],
|
|
87
|
+
inactiveSquads: [],
|
|
88
|
+
pendingEvolutions: 0,
|
|
89
|
+
hasRuntimeStore: Boolean(handle)
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
if (!handle) {
|
|
93
|
+
if (!json && !quiet) {
|
|
94
|
+
logger.log('AIOSON Health — nenhum runtime store encontrado neste projeto.');
|
|
95
|
+
logger.log('Execute: aioson runtime:init .');
|
|
96
|
+
}
|
|
97
|
+
return report;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const { db } = handle;
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
// 1. Learnings evoluíveis
|
|
104
|
+
report.evolvableLearnings = countEvolvablelearnings(db);
|
|
105
|
+
if (report.evolvableLearnings > 0) {
|
|
106
|
+
report.items.push({
|
|
107
|
+
type: 'learnings',
|
|
108
|
+
level: 'info',
|
|
109
|
+
message: `${report.evolvableLearnings} learning(s) prontos para evoluir`,
|
|
110
|
+
action: 'aioson learning:evolve .'
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 2. Squads inativos
|
|
115
|
+
const inactiveSquads = getInactiveSquads(db);
|
|
116
|
+
report.inactiveSquads = inactiveSquads.map((s) => s.squad_slug);
|
|
117
|
+
if (inactiveSquads.length > 0) {
|
|
118
|
+
for (const squad of inactiveSquads) {
|
|
119
|
+
const days = squad.updated_at
|
|
120
|
+
? Math.floor((Date.now() - new Date(squad.updated_at).getTime()) / (1000 * 60 * 60 * 24))
|
|
121
|
+
: '?';
|
|
122
|
+
report.items.push({
|
|
123
|
+
type: 'squad_inactive',
|
|
124
|
+
level: 'warn',
|
|
125
|
+
message: `Squad "${squad.squad_slug}" inativo há ${days} dia(s)`,
|
|
126
|
+
action: null
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 3. Dynamic tools com handlers quebrados
|
|
132
|
+
const tools = listDynamicTools(db, null);
|
|
133
|
+
const broken = await checkBrokenTools(tools, projectDir);
|
|
134
|
+
report.brokenTools = broken;
|
|
135
|
+
if (broken.length > 0) {
|
|
136
|
+
report.items.push({
|
|
137
|
+
type: 'broken_tools',
|
|
138
|
+
level: 'error',
|
|
139
|
+
message: `${broken.length} tool(s) com handler inválido: ${broken.join(', ')}`,
|
|
140
|
+
action: 'aioson tool:unregister . --name=<nome>'
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// 4. Evoluções pendentes
|
|
145
|
+
report.pendingEvolutions = await countPendingEvolutions(projectDir);
|
|
146
|
+
if (report.pendingEvolutions > 0) {
|
|
147
|
+
report.items.push({
|
|
148
|
+
type: 'pending_evolutions',
|
|
149
|
+
level: 'info',
|
|
150
|
+
message: `${report.pendingEvolutions} proposta(s) de evolução aguardando revisão`,
|
|
151
|
+
action: `aioson learning:apply . --file=.aioson/evolution/pending-XXX.json`
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
} finally {
|
|
155
|
+
db.close();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (json) return report;
|
|
159
|
+
|
|
160
|
+
// Output formatado
|
|
161
|
+
if (report.items.length === 0) {
|
|
162
|
+
if (!quiet) logger.log('AIOSON Health — tudo em ordem. Nenhum item pendente.');
|
|
163
|
+
return report;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
logger.log('');
|
|
167
|
+
logger.log('AIOSON Health — itens que precisam de atenção:');
|
|
168
|
+
logger.log('');
|
|
169
|
+
|
|
170
|
+
const icons = { info: '●', warn: '○', error: '✗' };
|
|
171
|
+
for (const item of report.items) {
|
|
172
|
+
const icon = icons[item.level] || '●';
|
|
173
|
+
logger.log(` ${icon} ${item.message}`);
|
|
174
|
+
if (item.action) logger.log(` → ${item.action}`);
|
|
175
|
+
}
|
|
176
|
+
logger.log('');
|
|
177
|
+
|
|
178
|
+
return report;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Versão compacta para injeção silenciosa no live:start e live:close.
|
|
183
|
+
* Retorna string de aviso ou null se tudo ok.
|
|
184
|
+
*/
|
|
185
|
+
async function getHealthDigest(projectDir) {
|
|
186
|
+
try {
|
|
187
|
+
const handle = await openRuntimeDb(projectDir, { mustExist: true });
|
|
188
|
+
if (!handle) return null;
|
|
189
|
+
|
|
190
|
+
const { db } = handle;
|
|
191
|
+
const items = [];
|
|
192
|
+
|
|
193
|
+
try {
|
|
194
|
+
const count = countEvolvablelearnings(db);
|
|
195
|
+
if (count > 0) items.push(`${count} learning(s) prontos para evoluir`);
|
|
196
|
+
|
|
197
|
+
const tools = listDynamicTools(db, null);
|
|
198
|
+
const broken = await checkBrokenTools(tools, projectDir);
|
|
199
|
+
if (broken.length > 0) items.push(`${broken.length} tool(s) com handler quebrado`);
|
|
200
|
+
|
|
201
|
+
const pending = await countPendingEvolutions(projectDir);
|
|
202
|
+
if (pending > 0) items.push(`${pending} evolução(ões) pendente(s)`);
|
|
203
|
+
} finally {
|
|
204
|
+
db.close();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (items.length === 0) return null;
|
|
208
|
+
return items;
|
|
209
|
+
} catch {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
module.exports = { runHealth, getHealthDigest };
|