@jaimevalasek/aioson 1.4.0 → 1.5.1
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 +3 -1
- package/docs/en/squad-dashboard.md +372 -0
- package/docs/openclaw-bridge.md +308 -0
- package/docs/pt/agentes.md +124 -10
- package/docs/pt/cenarios.md +46 -2
- package/docs/pt/comandos-cli.md +60 -1
- package/docs/pt/inicio-rapido.md +18 -2
- 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/backup-local.js +74 -0
- package/src/cli.js +98 -0
- package/src/commands/backup-local-cmd.js +25 -0
- package/src/commands/runtime.js +242 -0
- package/src/commands/setup-context.js +7 -2
- 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/web-map.js +70 -0
- package/src/commands/web-scrape.js +71 -0
- package/src/constants.js +8 -0
- package/src/context-writer.js +45 -1
- package/src/i18n/messages/en.js +127 -1
- package/src/i18n/messages/es.js +117 -0
- package/src/i18n/messages/fr.js +117 -0
- package/src/i18n/messages/pt-BR.js +126 -1
- package/src/lib/webhook-server.js +328 -0
- package/src/mcp-connectors/registry.js +602 -0
- package/src/runtime-store.js +259 -2
- 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/web.js +284 -0
- package/src/worker-runner.js +339 -0
- package/template/.aioson/agents/analyst.md +4 -0
- package/template/.aioson/agents/architect.md +4 -0
- package/template/.aioson/agents/dev.md +120 -11
- package/template/.aioson/agents/deyvin.md +8 -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/product.md +60 -12
- package/template/.aioson/agents/qa.md +1 -0
- package/template/.aioson/agents/setup.md +63 -19
- package/template/.aioson/agents/sheldon.md +603 -0
- package/template/.aioson/agents/squad.md +191 -0
- package/template/.aioson/agents/tester.md +254 -0
- package/template/.aioson/agents/ux-ui.md +12 -0
- package/template/.aioson/config.md +6 -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 +2 -1
- 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 +2 -1
- 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 +2 -1
- 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 +2 -1
- 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/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/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/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 +3 -0
- package/template/CLAUDE.md +5 -2
- package/template/OPENCODE.md +2 -0
|
@@ -59,6 +59,10 @@ module.exports = {
|
|
|
59
59
|
'aioson qa:scan [path] [--url=<app-url>] [--depth=3] [--max-pages=50] [--headed] [--html] [--json] [--locale=pt-BR]',
|
|
60
60
|
help_qa_report:
|
|
61
61
|
'aioson qa:report [path] [--html] [--json] [--locale=pt-BR]',
|
|
62
|
+
help_web_map:
|
|
63
|
+
'aioson web:map [path] --url=<url> [--depth=<N>] [--max-pages=<N>] [--include-external] [--json] [--locale=pt-BR]',
|
|
64
|
+
help_web_scrape:
|
|
65
|
+
'aioson web:scrape [path] --url=<url> [--format=markdown|text|html|links] [--json] [--locale=pt-BR]',
|
|
62
66
|
help_scan_project:
|
|
63
67
|
'aioson scan:project [path] --folder=<pasta[,pasta2]> [--summary-mode=titles|summaries|raw] [--context-mode=merge|rewrite] [--with-llm] [--provider=<name>] [--llm-model=<name>] [--dry-run] [--json] [--locale=pt-BR]',
|
|
64
68
|
help_config:
|
|
@@ -85,6 +89,18 @@ module.exports = {
|
|
|
85
89
|
'aioson squad:investigate [path] [--sub=list|show|score|link|register] [--investigation=<slug>] [--squad=<slug>] [--locale=pt-BR]',
|
|
86
90
|
help_squad_learning:
|
|
87
91
|
'aioson squad:learning [path] [--sub=list|stats|archive|promote|export] [--squad=<slug>] [--status=<status>] [--locale=pt-BR]',
|
|
92
|
+
help_squad_dashboard:
|
|
93
|
+
'aioson squad:dashboard [path] [--port=4180] [--squad=<slug>] [--locale=pt-BR]',
|
|
94
|
+
help_squad_worker:
|
|
95
|
+
'aioson squad:worker [path] [--sub=list|run|test|logs|scaffold] [--squad=<slug>] [--worker=<slug>] [--input=<json>] [--locale=pt-BR]',
|
|
96
|
+
help_squad_daemon:
|
|
97
|
+
'aioson squad:daemon [path] [--sub=start|status|stop|logs] [--squad=<slug>] [--port=<N>] [--locale=pt-BR]',
|
|
98
|
+
help_squad_mcp:
|
|
99
|
+
'aioson squad:mcp [path] [--sub=status|connectors|configure|test] [--squad=<slug>] [--mcp=<slug>] [--connector=<id>]',
|
|
100
|
+
help_squad_roi:
|
|
101
|
+
'aioson squad:roi [path] [--sub=config|metric|report|export] [--squad=<slug>] [--key=<metrica>] [--value=<N>]',
|
|
102
|
+
help_squad_score:
|
|
103
|
+
'aioson squad:score [path] --squad=<slug> [--locale=pt-BR]',
|
|
88
104
|
help_learning:
|
|
89
105
|
'aioson learning [path] [--sub=list|stats|promote] [--status=<status>] [--id=<learning-id>] [--locale=pt-BR]',
|
|
90
106
|
help_runtime_init:
|
|
@@ -758,6 +774,23 @@ module.exports = {
|
|
|
758
774
|
not_found: 'Nenhum relatorio QA encontrado. Execute: aioson qa:run ou aioson qa:scan',
|
|
759
775
|
html_report_written: 'Relatorio HTML escrito: {path}'
|
|
760
776
|
},
|
|
777
|
+
web_map: {
|
|
778
|
+
url_missing: 'Opcao obrigatoria ausente: --url=<url>.',
|
|
779
|
+
starting: 'Mapeando site: {url}',
|
|
780
|
+
pages_found: 'Paginas descobertas: {count}',
|
|
781
|
+
page_line: '- {url} | profundidade={depth} | status={status} | links={links}',
|
|
782
|
+
done: 'Mapa web concluido.',
|
|
783
|
+
failed: 'Falha no mapa web: {error}'
|
|
784
|
+
},
|
|
785
|
+
web_scrape: {
|
|
786
|
+
url_missing: 'Opcao obrigatoria ausente: --url=<url>.',
|
|
787
|
+
invalid_format: 'Valor invalido para --format: {format}. Use markdown, text, html ou links.',
|
|
788
|
+
fetching: 'Buscando pagina: {url}',
|
|
789
|
+
title_line: 'Titulo: {title}',
|
|
790
|
+
status_line: 'Status: {status} | Content-Type: {type}',
|
|
791
|
+
done: 'Web scrape concluido ({format}).',
|
|
792
|
+
failed: 'Falha no web scrape: {error}'
|
|
793
|
+
},
|
|
761
794
|
config: {
|
|
762
795
|
usage_error:
|
|
763
796
|
'Uso: aioson config <set KEY=value|show|get KEY> [--json] [--locale=pt-BR]',
|
|
@@ -841,7 +874,9 @@ module.exports = {
|
|
|
841
874
|
sessions: ' Sessoes : {count} ({path})',
|
|
842
875
|
latest_html: ' Latest HTML : {value}',
|
|
843
876
|
logs: ' Logs : {count} ({path})',
|
|
844
|
-
genomes: ' Genomes : {count} no squad / {agent_count} vinculos por agente'
|
|
877
|
+
genomes: ' Genomes : {count} no squad / {agent_count} vinculos por agente',
|
|
878
|
+
model_tiers: ' Model Tiers : {value}',
|
|
879
|
+
estimated_cost: ' Custo Est. : ~${value}/run'
|
|
845
880
|
},
|
|
846
881
|
squad_agent_create: {
|
|
847
882
|
no_name: 'Uso: aioson squad:agent-create [path] --name=<nome-agente> [--type=agent|assistant|clone|worker] [--scope=my-agents|squad] [--squad=<slug>]',
|
|
@@ -965,6 +1000,96 @@ module.exports = {
|
|
|
965
1000
|
registered: 'Investigacao registrada: {slug} ({path})',
|
|
966
1001
|
unknown_sub: 'Subcomando desconhecido: {sub}. Use: list, show, score, link, register.'
|
|
967
1002
|
},
|
|
1003
|
+
squad_daemon: {
|
|
1004
|
+
squad_required: 'Slug do squad e obrigatorio. Use --squad=<slug>.',
|
|
1005
|
+
started: 'Daemon iniciado para squad "{squad}" na porta {port} ({workers} workers, {cron} cron jobs)',
|
|
1006
|
+
webhook_hint: 'Endpoint webhook: POST http://127.0.0.1:{port}/webhook/<worker-slug>',
|
|
1007
|
+
stop_hint: 'Pressione Ctrl+C para parar.',
|
|
1008
|
+
stopping: 'Parando daemon...',
|
|
1009
|
+
start_failed: 'Falha ao iniciar daemon: {error}',
|
|
1010
|
+
no_runtime: 'Runtime store nao encontrado. Execute aioson runtime:init primeiro.',
|
|
1011
|
+
no_daemons: 'Nenhum registro de daemon encontrado.',
|
|
1012
|
+
not_found: 'Nenhum registro de daemon para o squad: {squad}',
|
|
1013
|
+
not_running: 'O daemon do squad "{squad}" nao esta rodando.',
|
|
1014
|
+
signal_sent: 'SIGTERM enviado ao daemon de "{squad}" (pid {pid}).',
|
|
1015
|
+
process_gone: 'O processo do daemon de "{squad}" nao esta mais rodando.',
|
|
1016
|
+
no_logs: 'Nenhum log de atividade do daemon encontrado.',
|
|
1017
|
+
unknown_sub: 'Subcomando desconhecido: {sub}. Use: start, status, stop, logs.'
|
|
1018
|
+
},
|
|
1019
|
+
|
|
1020
|
+
squad_mcp: {
|
|
1021
|
+
squad_required: 'Slug do squad e obrigatorio. Use --squad=<slug>.',
|
|
1022
|
+
connectors_title: 'Conectores MCP Integrados:',
|
|
1023
|
+
actions: 'Acoes',
|
|
1024
|
+
required_config: 'Obrigatorio',
|
|
1025
|
+
no_integrations: 'Nenhuma integracao configurada para o squad "{squad}".',
|
|
1026
|
+
missing_config: 'Config ausente',
|
|
1027
|
+
calls: 'Chamadas',
|
|
1028
|
+
mcp_required: 'Slug do MCP e obrigatorio. Use --mcp=<slug>.',
|
|
1029
|
+
connector_required: 'ID do conector e obrigatorio. Use --connector=<id>.',
|
|
1030
|
+
unknown_connector: 'Conector desconhecido: {connector}. Use --sub=connectors para listar.',
|
|
1031
|
+
configured: 'Integracao "{mcp}" configurada com conector "{connector}" (status: {status}).',
|
|
1032
|
+
still_missing: 'Ainda faltam env/config: {keys}',
|
|
1033
|
+
not_configured: 'Integracao "{mcp}" nao esta configurada.',
|
|
1034
|
+
test_missing: 'Integracao "{mcp}" tem config ausente: {keys}',
|
|
1035
|
+
test_ok: 'Integracao "{mcp}" ({connector}) — config OK.',
|
|
1036
|
+
health_url: 'URL de health check: {url}',
|
|
1037
|
+
testing_connection: 'Testando conexao...',
|
|
1038
|
+
health_ok: 'Conexao OK (HTTP {statusCode})',
|
|
1039
|
+
health_error: 'Erro na conexao: {error}',
|
|
1040
|
+
health_skipped: 'Verificacao de saude nao disponivel para este connector',
|
|
1041
|
+
action_required: 'Slug da acao e obrigatorio. Use --action=<slug>.',
|
|
1042
|
+
invalid_input: 'JSON invalido. Forneca JSON valido com --input.',
|
|
1043
|
+
unknown_sub: 'Subcomando desconhecido: {sub}. Use: status, connectors, configure, test, call.'
|
|
1044
|
+
},
|
|
1045
|
+
|
|
1046
|
+
squad_roi: {
|
|
1047
|
+
squad_required: 'Slug do squad e obrigatorio. Use --squad=<slug>.',
|
|
1048
|
+
config_saved: 'Config de ROI salva para o squad "{squad}".',
|
|
1049
|
+
pricing_model: 'Modelo de precificacao',
|
|
1050
|
+
setup_fee: 'Taxa de implantacao',
|
|
1051
|
+
monthly_fee: 'Mensalidade',
|
|
1052
|
+
percentage: 'Percentual',
|
|
1053
|
+
contract: 'Contrato',
|
|
1054
|
+
metric_required: 'Chave e valor da metrica sao obrigatorios. Use --key=<nome> --value=<N>.',
|
|
1055
|
+
metric_saved: 'Metrica "{key}" = {value} salva para o squad "{squad}".',
|
|
1056
|
+
no_metrics: 'Nenhuma metrica encontrada para o squad "{squad}".',
|
|
1057
|
+
report_title: 'Relatorio de ROI — {squad}',
|
|
1058
|
+
baseline: 'Baseline',
|
|
1059
|
+
actual: 'Atual',
|
|
1060
|
+
target: 'Meta',
|
|
1061
|
+
period: 'Periodo',
|
|
1062
|
+
cost_section: 'Resumo de Custos:',
|
|
1063
|
+
monthly_cost: 'Custo mensal efetivo',
|
|
1064
|
+
exported: 'Relatorio exportado para {file} ({format}).',
|
|
1065
|
+
unknown_sub: 'Subcomando desconhecido: {sub}. Use: config, metric, report, export.'
|
|
1066
|
+
},
|
|
1067
|
+
|
|
1068
|
+
squad_worker: {
|
|
1069
|
+
squad_required: 'Slug do squad e obrigatorio. Use --squad=<slug>.',
|
|
1070
|
+
no_workers: 'Nenhum worker encontrado para este squad.',
|
|
1071
|
+
run_usage: 'Uso: aioson squad:worker --sub=run --squad=<slug> --worker=<slug> [--input=<json>]',
|
|
1072
|
+
test_usage: 'Uso: aioson squad:worker --sub=test --squad=<slug> --worker=<slug>',
|
|
1073
|
+
scaffold_usage: 'Uso: aioson squad:worker --sub=scaffold --squad=<slug> --worker=<slug> [--trigger=manual|event|scheduled]',
|
|
1074
|
+
not_found: 'Worker nao encontrado: {worker}',
|
|
1075
|
+
invalid_input: 'JSON invalido. Forneca JSON valido com --input.',
|
|
1076
|
+
run_success: 'Worker "{worker}" concluido com sucesso.',
|
|
1077
|
+
run_failed: 'Worker "{worker}" falhou: {error}',
|
|
1078
|
+
test_passed: 'Worker "{worker}" teste aprovado.',
|
|
1079
|
+
test_failed: 'Worker "{worker}" teste falhou: {error}',
|
|
1080
|
+
scaffold_created: 'Worker "{worker}" criado em {path}',
|
|
1081
|
+
no_runtime: 'Runtime store nao encontrado. Execute aioson runtime:init primeiro.',
|
|
1082
|
+
no_logs: 'Nenhuma execucao de worker encontrada.',
|
|
1083
|
+
unknown_sub: 'Subcomando desconhecido: {sub}. Use: list, run, test, logs, scaffold.'
|
|
1084
|
+
},
|
|
1085
|
+
|
|
1086
|
+
squad_dashboard: {
|
|
1087
|
+
started: 'Squad Dashboard rodando em {url} (porta {port})',
|
|
1088
|
+
filtered: 'Filtrando para squad: {squad}',
|
|
1089
|
+
stop_hint: 'Pressione Ctrl+C para parar.',
|
|
1090
|
+
stopping: 'Parando Squad Dashboard...',
|
|
1091
|
+
port_in_use: 'Porta {port} ja esta em uso. Tente --port=<outra>'
|
|
1092
|
+
},
|
|
968
1093
|
implementation_plan: {
|
|
969
1094
|
not_found: 'Plano de implementacao nao encontrado: {file}',
|
|
970
1095
|
no_runtime: 'Runtime store nao encontrado. Execute aioson runtime:init primeiro.',
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const http = require('node:http');
|
|
4
|
+
const https = require('node:https');
|
|
5
|
+
const { randomBytes } = require('node:crypto');
|
|
6
|
+
|
|
7
|
+
function generateRunId() {
|
|
8
|
+
return randomBytes(8).toString('hex');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function sendJSON(res, statusCode, data) {
|
|
12
|
+
const body = JSON.stringify(data);
|
|
13
|
+
res.writeHead(statusCode, {
|
|
14
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
15
|
+
'Content-Length': Buffer.byteLength(body)
|
|
16
|
+
});
|
|
17
|
+
res.end(body);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function parseBody(req) {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
let data = '';
|
|
23
|
+
req.on('data', chunk => { data += chunk; });
|
|
24
|
+
req.on('end', () => {
|
|
25
|
+
try {
|
|
26
|
+
resolve(data ? JSON.parse(data) : {});
|
|
27
|
+
} catch {
|
|
28
|
+
reject(new Error('Invalid JSON body'));
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
req.on('error', reject);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function postCallback(url, payload, maxRetries = 3) {
|
|
36
|
+
const delays = [30000, 60000, 120000];
|
|
37
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
38
|
+
try {
|
|
39
|
+
await new Promise((resolve, reject) => {
|
|
40
|
+
const body = JSON.stringify(payload);
|
|
41
|
+
let parsed;
|
|
42
|
+
try { parsed = new URL(url); } catch { return reject(new Error('Invalid callback URL')); }
|
|
43
|
+
const isHttps = parsed.protocol === 'https:';
|
|
44
|
+
const mod = isHttps ? https : http;
|
|
45
|
+
const opts = {
|
|
46
|
+
hostname: parsed.hostname,
|
|
47
|
+
port: parsed.port ? parseInt(parsed.port, 10) : (isHttps ? 443 : 80),
|
|
48
|
+
path: parsed.pathname + parsed.search,
|
|
49
|
+
method: 'POST',
|
|
50
|
+
headers: {
|
|
51
|
+
'Content-Type': 'application/json',
|
|
52
|
+
'Content-Length': Buffer.byteLength(body)
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
const req = mod.request(opts, res => {
|
|
56
|
+
res.resume();
|
|
57
|
+
if (res.statusCode >= 200 && res.statusCode < 300) resolve();
|
|
58
|
+
else reject(new Error(`Callback returned HTTP ${res.statusCode}`));
|
|
59
|
+
});
|
|
60
|
+
req.on('error', reject);
|
|
61
|
+
req.setTimeout(10000, () => { req.destroy(new Error('Callback timeout')); });
|
|
62
|
+
req.write(body);
|
|
63
|
+
req.end();
|
|
64
|
+
});
|
|
65
|
+
return; // success — stop retrying
|
|
66
|
+
} catch {
|
|
67
|
+
if (attempt < maxRetries) {
|
|
68
|
+
await new Promise(r => setTimeout(r, delays[attempt] || 120000));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
class WebhookServer {
|
|
75
|
+
/**
|
|
76
|
+
* @param {object} options
|
|
77
|
+
* @param {number} [options.port=3210]
|
|
78
|
+
* @param {string} [options.token=''] Bearer token (empty = no auth)
|
|
79
|
+
* @param {number} [options.rateLimit=60] Max req/min per IP
|
|
80
|
+
* @param {Array} [options.squads=[]] [{name, timeout_ms}] — empty = all allowed
|
|
81
|
+
* @param {Function} [options.onTrigger] async ({squad,input,session_id,metadata,run_id}) -> {response}
|
|
82
|
+
* @param {Function} [options.onQuery] async ({squad,query,max_results}) -> {results}
|
|
83
|
+
* @param {string} [options.version='0.0.0']
|
|
84
|
+
*/
|
|
85
|
+
constructor(options = {}) {
|
|
86
|
+
this.port = options.port || 3210;
|
|
87
|
+
this.token = options.token || '';
|
|
88
|
+
this.rateLimit = options.rateLimit || 60;
|
|
89
|
+
this.allowedSquads = options.squads || [];
|
|
90
|
+
this.onTrigger = options.onTrigger || null;
|
|
91
|
+
this.onQuery = options.onQuery || null;
|
|
92
|
+
this.version = options.version || '0.0.0';
|
|
93
|
+
|
|
94
|
+
this._runs = new Map(); // run_id -> {status, response, error, session_id, metadata}
|
|
95
|
+
this._ipCounters = new Map(); // ip -> {count, windowStart}
|
|
96
|
+
this._server = null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
_checkRateLimit(ip) {
|
|
100
|
+
const now = Date.now();
|
|
101
|
+
const window = 60_000;
|
|
102
|
+
const entry = this._ipCounters.get(ip) || { count: 0, windowStart: now };
|
|
103
|
+
if (now - entry.windowStart > window) {
|
|
104
|
+
entry.count = 0;
|
|
105
|
+
entry.windowStart = now;
|
|
106
|
+
}
|
|
107
|
+
entry.count++;
|
|
108
|
+
this._ipCounters.set(ip, entry);
|
|
109
|
+
return entry.count <= this.rateLimit;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
_validateToken(req) {
|
|
113
|
+
if (!this.token) return true;
|
|
114
|
+
const auth = req.headers['authorization'] || '';
|
|
115
|
+
const spaceIdx = auth.indexOf(' ');
|
|
116
|
+
if (spaceIdx === -1) return false;
|
|
117
|
+
const scheme = auth.slice(0, spaceIdx);
|
|
118
|
+
const tok = auth.slice(spaceIdx + 1);
|
|
119
|
+
return scheme === 'Bearer' && tok === this.token;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
_getSquadNames() {
|
|
123
|
+
return this.allowedSquads.map(s => (typeof s === 'string' ? s : s.name));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
_isSquadAllowed(squadName) {
|
|
127
|
+
if (this.allowedSquads.length === 0) return true;
|
|
128
|
+
return this._getSquadNames().includes(squadName);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
_getSquadTimeout(squadName) {
|
|
132
|
+
const entry = this.allowedSquads.find(s => (typeof s === 'string' ? s : s.name) === squadName);
|
|
133
|
+
return (entry && entry.timeout_ms) || 120000;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async _handleTrigger(req, res) {
|
|
137
|
+
let body;
|
|
138
|
+
try {
|
|
139
|
+
body = await parseBody(req);
|
|
140
|
+
} catch {
|
|
141
|
+
return sendJSON(res, 400, { ok: false, error: 'Invalid JSON body' });
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const { squad, input, session_id, callback_url, metadata } = body;
|
|
145
|
+
|
|
146
|
+
if (!squad) return sendJSON(res, 400, { ok: false, error: 'squad is required' });
|
|
147
|
+
if (!input) return sendJSON(res, 400, { ok: false, error: 'input is required' });
|
|
148
|
+
|
|
149
|
+
if (!this._isSquadAllowed(squad)) {
|
|
150
|
+
return sendJSON(res, 404, {
|
|
151
|
+
ok: false,
|
|
152
|
+
error: `Squad "${squad}" not found`,
|
|
153
|
+
available_squads: this._getSquadNames()
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const run_id = generateRunId();
|
|
158
|
+
this._runs.set(run_id, { status: 'queued', response: null, error: null, session_id, metadata });
|
|
159
|
+
|
|
160
|
+
sendJSON(res, 202, { run_id, status: 'queued' });
|
|
161
|
+
|
|
162
|
+
setImmediate(async () => {
|
|
163
|
+
const run = this._runs.get(run_id);
|
|
164
|
+
run.status = 'running';
|
|
165
|
+
|
|
166
|
+
const timeoutMs = this._getSquadTimeout(squad);
|
|
167
|
+
|
|
168
|
+
let timeoutHandle;
|
|
169
|
+
try {
|
|
170
|
+
const execPromise = this.onTrigger
|
|
171
|
+
? this.onTrigger({ squad, input, session_id, metadata, run_id })
|
|
172
|
+
: Promise.resolve({ response: `Squad ${squad} queued: ${input}` });
|
|
173
|
+
|
|
174
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
175
|
+
timeoutHandle = setTimeout(() => reject(new Error('Squad execution timed out')), timeoutMs);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const result = await Promise.race([execPromise, timeoutPromise]);
|
|
179
|
+
clearTimeout(timeoutHandle);
|
|
180
|
+
run.status = 'completed';
|
|
181
|
+
run.response = result.response || '';
|
|
182
|
+
} catch (err) {
|
|
183
|
+
clearTimeout(timeoutHandle);
|
|
184
|
+
run.status = 'failed';
|
|
185
|
+
run.error = err.message;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (callback_url) {
|
|
189
|
+
const callbackPayload = {
|
|
190
|
+
run_id,
|
|
191
|
+
session_id,
|
|
192
|
+
response: run.response,
|
|
193
|
+
status: run.status,
|
|
194
|
+
metadata
|
|
195
|
+
};
|
|
196
|
+
postCallback(callback_url, callbackPayload).catch(() => {});
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
_handleStatus(runId, res) {
|
|
202
|
+
const run = this._runs.get(runId);
|
|
203
|
+
if (!run) return sendJSON(res, 404, { ok: false, error: 'Run not found' });
|
|
204
|
+
return sendJSON(res, 200, {
|
|
205
|
+
run_id: runId,
|
|
206
|
+
status: run.status,
|
|
207
|
+
response: run.response || null,
|
|
208
|
+
error: run.error || null
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async _handleQuery(req, res) {
|
|
213
|
+
let body;
|
|
214
|
+
try {
|
|
215
|
+
body = await parseBody(req);
|
|
216
|
+
} catch {
|
|
217
|
+
return sendJSON(res, 400, { ok: false, error: 'Invalid JSON body' });
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const { squad, query, max_results } = body;
|
|
221
|
+
|
|
222
|
+
if (!squad) return sendJSON(res, 400, { ok: false, error: 'squad is required' });
|
|
223
|
+
if (!query) return sendJSON(res, 400, { ok: false, error: 'query is required' });
|
|
224
|
+
|
|
225
|
+
if (!this._isSquadAllowed(squad)) {
|
|
226
|
+
return sendJSON(res, 404, {
|
|
227
|
+
ok: false,
|
|
228
|
+
error: `Squad "${squad}" not found`,
|
|
229
|
+
available_squads: this._getSquadNames()
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const t0 = Date.now();
|
|
234
|
+
const QUERY_TIMEOUT_MS = 10_000;
|
|
235
|
+
|
|
236
|
+
let timeoutHandle;
|
|
237
|
+
try {
|
|
238
|
+
const execPromise = this.onQuery
|
|
239
|
+
? this.onQuery({ squad, query, max_results: max_results || 10 })
|
|
240
|
+
: Promise.resolve({ results: [] });
|
|
241
|
+
|
|
242
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
243
|
+
timeoutHandle = setTimeout(() => reject(new Error('Query timed out')), QUERY_TIMEOUT_MS);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
const result = await Promise.race([execPromise, timeoutPromise]);
|
|
247
|
+
clearTimeout(timeoutHandle);
|
|
248
|
+
const latency_ms = Date.now() - t0;
|
|
249
|
+
|
|
250
|
+
return sendJSON(res, 200, {
|
|
251
|
+
results: result.results || [],
|
|
252
|
+
squad,
|
|
253
|
+
latency_ms
|
|
254
|
+
});
|
|
255
|
+
} catch (err) {
|
|
256
|
+
clearTimeout(timeoutHandle);
|
|
257
|
+
const latency_ms = Date.now() - t0;
|
|
258
|
+
return sendJSON(res, 504, { ok: false, error: err.message, squad, latency_ms });
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
_handleHealth(res) {
|
|
263
|
+
return sendJSON(res, 200, {
|
|
264
|
+
ok: true,
|
|
265
|
+
version: this.version,
|
|
266
|
+
squads: this._getSquadNames()
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async _handleRequest(req, res) {
|
|
271
|
+
const ip = req.socket.remoteAddress || '0.0.0.0';
|
|
272
|
+
const url = req.url || '/';
|
|
273
|
+
const method = req.method || 'GET';
|
|
274
|
+
|
|
275
|
+
if (!this._checkRateLimit(ip)) {
|
|
276
|
+
return sendJSON(res, 429, { ok: false, error: 'Too many requests' });
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Health check — no auth required
|
|
280
|
+
if (method === 'GET' && url === '/health') {
|
|
281
|
+
return this._handleHealth(res);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (!this._validateToken(req)) {
|
|
285
|
+
return sendJSON(res, 401, { ok: false, error: 'Unauthorized' });
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (method === 'POST' && url === '/trigger') {
|
|
289
|
+
return this._handleTrigger(req, res);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (method === 'POST' && url === '/query') {
|
|
293
|
+
return this._handleQuery(req, res);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const statusMatch = method === 'GET' && url.match(/^\/status\/([^/?]+)/);
|
|
297
|
+
if (statusMatch) {
|
|
298
|
+
return this._handleStatus(statusMatch[1], res);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return sendJSON(res, 404, { ok: false, error: 'Not found' });
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
start() {
|
|
305
|
+
return new Promise((resolve, reject) => {
|
|
306
|
+
this._server = http.createServer((req, res) => {
|
|
307
|
+
this._handleRequest(req, res).catch(() => {
|
|
308
|
+
sendJSON(res, 500, { ok: false, error: 'Internal server error' });
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
this._server.listen(this.port, () => resolve(this._server));
|
|
312
|
+
this._server.once('error', reject);
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
stop() {
|
|
317
|
+
return new Promise((resolve, reject) => {
|
|
318
|
+
if (!this._server) return resolve();
|
|
319
|
+
// Close idle keep-alive connections so server.close() callback fires promptly
|
|
320
|
+
if (typeof this._server.closeIdleConnections === 'function') {
|
|
321
|
+
this._server.closeIdleConnections();
|
|
322
|
+
}
|
|
323
|
+
this._server.close(err => (err ? reject(err) : resolve()));
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
module.exports = { WebhookServer, postCallback };
|