@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,250 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs/promises');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
|
|
6
|
+
async function readJsonIfExists(filePath) {
|
|
7
|
+
try {
|
|
8
|
+
const raw = await fs.readFile(filePath, 'utf8');
|
|
9
|
+
return JSON.parse(raw);
|
|
10
|
+
} catch { return null; }
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function scoreCompletude(manifest) {
|
|
14
|
+
let score = 0;
|
|
15
|
+
const details = {};
|
|
16
|
+
const executors = Array.isArray(manifest.executors) ? manifest.executors : [];
|
|
17
|
+
const workflows = Array.isArray(manifest.workflows) ? manifest.workflows : [];
|
|
18
|
+
const checklists = Array.isArray(manifest.checklists) ? manifest.checklists : [];
|
|
19
|
+
|
|
20
|
+
// Executors typed (5pts)
|
|
21
|
+
const allTyped = executors.length > 0 && executors.every(e => e.type);
|
|
22
|
+
if (allTyped) { score += 5; details.executorsTyped = true; }
|
|
23
|
+
|
|
24
|
+
// Workflow defined (5pts)
|
|
25
|
+
const hasWorkflow = workflows.some(w => Array.isArray(w.phases) && w.phases.length >= 2);
|
|
26
|
+
if (hasWorkflow) { score += 5; details.workflowDefined = true; }
|
|
27
|
+
|
|
28
|
+
// Checklists present (3pts)
|
|
29
|
+
if (checklists.length > 0) { score += 3; details.checklistsPresent = true; }
|
|
30
|
+
|
|
31
|
+
// Tasks decomposed (5pts)
|
|
32
|
+
const hasTask = executors.some(e => Array.isArray(e.tasks) && e.tasks.length > 0);
|
|
33
|
+
if (hasTask) { score += 5; details.tasksDecomposed = true; }
|
|
34
|
+
|
|
35
|
+
// Workers present (2pts)
|
|
36
|
+
const hasWorker = executors.some(e => e.type === 'worker' || e.usesLLM === false);
|
|
37
|
+
if (hasWorker) { score += 2; details.workersPresent = true; }
|
|
38
|
+
|
|
39
|
+
// Investigation report (3pts)
|
|
40
|
+
if (manifest._investigationPath) { score += 3; details.investigationReport = true; }
|
|
41
|
+
|
|
42
|
+
// Model tiering (2pts)
|
|
43
|
+
const allTiered = executors.length > 0 && executors.every(e => e.modelTier);
|
|
44
|
+
if (allTiered) { score += 2; details.modelTiering = true; }
|
|
45
|
+
|
|
46
|
+
return { score, max: 25, details };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function scoreProfundidade(manifest) {
|
|
50
|
+
let score = 0;
|
|
51
|
+
const details = {};
|
|
52
|
+
const executors = Array.isArray(manifest.executors) ? manifest.executors : [];
|
|
53
|
+
|
|
54
|
+
// Executor focus areas avg >= 3 (5pts)
|
|
55
|
+
const focusCounts = executors.map(e => (Array.isArray(e.focus) ? e.focus : []).length);
|
|
56
|
+
const avgFocus = focusCounts.length > 0 ? focusCounts.reduce((a, b) => a + b, 0) / focusCounts.length : 0;
|
|
57
|
+
if (avgFocus >= 3) { score += 5; details.focusAreas = true; }
|
|
58
|
+
|
|
59
|
+
// Task quality criteria avg >= 3 (5pts)
|
|
60
|
+
const allTasks = executors.flatMap(e => Array.isArray(e.tasks) ? e.tasks : []);
|
|
61
|
+
if (allTasks.length > 0) { score += 5; details.taskCriteria = true; }
|
|
62
|
+
|
|
63
|
+
// Veto conditions (5pts)
|
|
64
|
+
const workflows = Array.isArray(manifest.workflows) ? manifest.workflows : [];
|
|
65
|
+
const hasVeto = workflows.some(w =>
|
|
66
|
+
(Array.isArray(w.phases) ? w.phases : []).some(p =>
|
|
67
|
+
Array.isArray(p.vetoConditions) && p.vetoConditions.length > 0
|
|
68
|
+
)
|
|
69
|
+
);
|
|
70
|
+
if (hasVeto) { score += 5; details.vetoConditions = true; }
|
|
71
|
+
|
|
72
|
+
// Content blueprints with 3+ sections (5pts)
|
|
73
|
+
const blueprints = Array.isArray(manifest.contentBlueprints) ? manifest.contentBlueprints : [];
|
|
74
|
+
const hasBp = blueprints.some(bp => Array.isArray(bp.sections) && bp.sections.length >= 3);
|
|
75
|
+
if (hasBp) { score += 5; details.contentBlueprints = true; }
|
|
76
|
+
|
|
77
|
+
// Skills declared >= 2 (5pts)
|
|
78
|
+
const skills = Array.isArray(manifest.skills) ? manifest.skills : [];
|
|
79
|
+
if (skills.length >= 2) { score += 5; details.skillsDeclared = true; }
|
|
80
|
+
|
|
81
|
+
return { score, max: 25, details };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function scoreQualidadeEstrutural(manifest) {
|
|
85
|
+
let score = 0;
|
|
86
|
+
const details = {};
|
|
87
|
+
const executors = Array.isArray(manifest.executors) ? manifest.executors : [];
|
|
88
|
+
const workflows = Array.isArray(manifest.workflows) ? manifest.workflows : [];
|
|
89
|
+
|
|
90
|
+
// Review loops (5pts)
|
|
91
|
+
const hasReview = workflows.some(w =>
|
|
92
|
+
(Array.isArray(w.phases) ? w.phases : []).some(p => p.review)
|
|
93
|
+
);
|
|
94
|
+
if (hasReview) { score += 5; details.reviewLoops = true; }
|
|
95
|
+
|
|
96
|
+
// Human gates (5pts)
|
|
97
|
+
const hasGate = workflows.some(w =>
|
|
98
|
+
(Array.isArray(w.phases) ? w.phases : []).some(p => p.humanGate)
|
|
99
|
+
);
|
|
100
|
+
if (hasGate) { score += 5; details.humanGates = true; }
|
|
101
|
+
|
|
102
|
+
// Cross-squad awareness (3pts) — orchestrator mentions cross-squad
|
|
103
|
+
// Simplified: check if ports are defined
|
|
104
|
+
if (manifest.ports && (Array.isArray(manifest.ports.inputs) || Array.isArray(manifest.ports.outputs))) {
|
|
105
|
+
score += 3; details.crossSquad = true;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Output strategy configured (4pts)
|
|
109
|
+
const os = manifest.outputStrategy;
|
|
110
|
+
if (os && os.mode && os.mode !== 'hybrid') { score += 4; details.outputStrategy = true; }
|
|
111
|
+
else if (os && os.mode === 'hybrid') { score += 4; details.outputStrategy = true; }
|
|
112
|
+
|
|
113
|
+
// Genome bindings (3pts)
|
|
114
|
+
const genomes = manifest.genomes;
|
|
115
|
+
const hasGenome = genomes && (
|
|
116
|
+
(Array.isArray(genomes) && genomes.length > 0) ||
|
|
117
|
+
(typeof genomes === 'object' && !Array.isArray(genomes))
|
|
118
|
+
);
|
|
119
|
+
if (hasGenome) { score += 3; details.genomeBindings = true; }
|
|
120
|
+
|
|
121
|
+
// Format references (5pts)
|
|
122
|
+
const hasFormat = executors.some(e => Array.isArray(e.formats) && e.formats.length > 0);
|
|
123
|
+
if (hasFormat) { score += 5; details.formatReferences = true; }
|
|
124
|
+
|
|
125
|
+
return { score, max: 25, details };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function scorePotencial(manifest) {
|
|
129
|
+
let score = 0;
|
|
130
|
+
const details = {};
|
|
131
|
+
const workflows = Array.isArray(manifest.workflows) ? manifest.workflows : [];
|
|
132
|
+
|
|
133
|
+
// Anti-pattern guards via veto conditions (5pts)
|
|
134
|
+
const hasVeto = workflows.some(w =>
|
|
135
|
+
(Array.isArray(w.phases) ? w.phases : []).some(p =>
|
|
136
|
+
Array.isArray(p.vetoConditions) && p.vetoConditions.length > 0
|
|
137
|
+
)
|
|
138
|
+
);
|
|
139
|
+
if (hasVeto) { score += 5; details.antiPatternGuards = true; }
|
|
140
|
+
|
|
141
|
+
// Domain vocabulary — investigation (5pts)
|
|
142
|
+
if (manifest._investigationPath) { score += 5; details.domainVocabulary = true; }
|
|
143
|
+
|
|
144
|
+
// Structural patterns — content blueprints (5pts)
|
|
145
|
+
const blueprints = Array.isArray(manifest.contentBlueprints) ? manifest.contentBlueprints : [];
|
|
146
|
+
if (blueprints.length > 0) { score += 5; details.structuralPatterns = true; }
|
|
147
|
+
|
|
148
|
+
// Executor coherence + Output realism (10pts) → LLM-only, mark as partial
|
|
149
|
+
details.llmAssessmentPending = true;
|
|
150
|
+
|
|
151
|
+
return { score, max: 25, details };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function gradeFromScore(total) {
|
|
155
|
+
if (total >= 90) return 'S (Exceptional)';
|
|
156
|
+
if (total >= 80) return 'A (Excellent)';
|
|
157
|
+
if (total >= 70) return 'B (Good)';
|
|
158
|
+
if (total >= 50) return 'C (Adequate)';
|
|
159
|
+
return 'D (Needs work)';
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function suggestQuickWins(d1, d2, d3, d4) {
|
|
163
|
+
const wins = [];
|
|
164
|
+
if (!d3.details.reviewLoops) wins.push({ action: 'Add review loop to a workflow phase', pts: 5 });
|
|
165
|
+
if (!d1.details.tasksDecomposed) wins.push({ action: 'Decompose at least 1 executor into tasks', pts: 5 });
|
|
166
|
+
if (!d3.details.formatReferences) wins.push({ action: 'Add a format reference to an executor', pts: 5 });
|
|
167
|
+
if (!d2.details.vetoConditions) wins.push({ action: 'Add veto conditions to a workflow phase', pts: 5 });
|
|
168
|
+
if (!d1.details.modelTiering) wins.push({ action: 'Assign modelTier to all executors', pts: 2 });
|
|
169
|
+
if (!d1.details.workersPresent) wins.push({ action: 'Add a worker executor (no LLM)', pts: 2 });
|
|
170
|
+
return wins.slice(0, 3);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async function runSquadScore({ args = [], options = {}, logger = console, translator } = {}) {
|
|
174
|
+
const projectDir = path.resolve(process.cwd(), args[0] || '.');
|
|
175
|
+
const slug = options.squad || args[1];
|
|
176
|
+
|
|
177
|
+
if (!slug) {
|
|
178
|
+
logger.error('Usage: aioson squad:score [path] --squad=<slug>');
|
|
179
|
+
return { valid: false, error: 'No slug provided' };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const manifestPath = path.join(projectDir, '.aioson', 'squads', slug, 'squad.manifest.json');
|
|
183
|
+
const manifest = await readJsonIfExists(manifestPath);
|
|
184
|
+
|
|
185
|
+
if (!manifest) {
|
|
186
|
+
logger.error(`Squad "${slug}" not found or invalid manifest`);
|
|
187
|
+
return { valid: false, error: 'Manifest not found' };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Check for investigation
|
|
191
|
+
const squadSearchDir = path.join(projectDir, 'squad-searches', slug);
|
|
192
|
+
try {
|
|
193
|
+
await fs.access(squadSearchDir);
|
|
194
|
+
manifest._investigationPath = squadSearchDir;
|
|
195
|
+
} catch { /* no investigation */ }
|
|
196
|
+
|
|
197
|
+
const d1 = scoreCompletude(manifest);
|
|
198
|
+
const d2 = scoreProfundidade(manifest);
|
|
199
|
+
const d3 = scoreQualidadeEstrutural(manifest);
|
|
200
|
+
const d4 = scorePotencial(manifest);
|
|
201
|
+
|
|
202
|
+
const total = d1.score + d2.score + d3.score + d4.score;
|
|
203
|
+
const maxTotal = d1.max + d2.max + d3.max + d4.max;
|
|
204
|
+
const grade = gradeFromScore(total);
|
|
205
|
+
const wins = suggestQuickWins(d1, d2, d3, d4);
|
|
206
|
+
|
|
207
|
+
logger.log('');
|
|
208
|
+
logger.log(` Squad: ${slug}`);
|
|
209
|
+
logger.log('');
|
|
210
|
+
logger.log(` Completude: ${String(d1.score).padStart(2)}/${d1.max}`);
|
|
211
|
+
logger.log(` Profundidade: ${String(d2.score).padStart(2)}/${d2.max}`);
|
|
212
|
+
logger.log(` Qualidade Estrutural: ${String(d3.score).padStart(2)}/${d3.max}`);
|
|
213
|
+
logger.log(` Potencial de Resultado: ${String(d4.score).padStart(2)}/${d4.max}*`);
|
|
214
|
+
logger.log(` ${'─'.repeat(40)}`);
|
|
215
|
+
logger.log(` TOTAL: ${String(total).padStart(2)}/${maxTotal}`);
|
|
216
|
+
logger.log(` Grade: ${grade}`);
|
|
217
|
+
logger.log('');
|
|
218
|
+
logger.log(' * Dimensão 4 parcial (sem LLM assessment)');
|
|
219
|
+
|
|
220
|
+
if (wins.length > 0) {
|
|
221
|
+
logger.log('');
|
|
222
|
+
logger.log(' Quick wins:');
|
|
223
|
+
wins.forEach((w, i) => logger.log(` ${i + 1}. ${w.action} → +${w.pts} pts`));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
logger.log('');
|
|
227
|
+
|
|
228
|
+
// Store in runtime if available
|
|
229
|
+
try {
|
|
230
|
+
const { openRuntimeDb } = require('../runtime-store');
|
|
231
|
+
const { db } = openRuntimeDb(projectDir);
|
|
232
|
+
const now = new Date().toISOString();
|
|
233
|
+
const stmt = db.prepare('INSERT OR REPLACE INTO squad_scores (squad_slug, dimension, score, max_score, details_json, scored_at) VALUES (?, ?, ?, ?, ?, ?)');
|
|
234
|
+
stmt.run(slug, 'completude', d1.score, d1.max, JSON.stringify(d1.details), now);
|
|
235
|
+
stmt.run(slug, 'profundidade', d2.score, d2.max, JSON.stringify(d2.details), now);
|
|
236
|
+
stmt.run(slug, 'qualidade', d3.score, d3.max, JSON.stringify(d3.details), now);
|
|
237
|
+
stmt.run(slug, 'potencial', d4.score, d4.max, JSON.stringify(d4.details), now);
|
|
238
|
+
} catch { /* runtime not available */ }
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
slug,
|
|
242
|
+
total,
|
|
243
|
+
max: maxTotal,
|
|
244
|
+
grade,
|
|
245
|
+
dimensions: { completude: d1, profundidade: d2, qualidade: d3, potencial: d4 },
|
|
246
|
+
quickWins: wins
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
module.exports = { runSquadScore, scoreCompletude, scoreProfundidade, scoreQualidadeEstrutural, scorePotencial, gradeFromScore };
|
|
@@ -4,6 +4,34 @@ const fs = require('node:fs/promises');
|
|
|
4
4
|
const path = require('node:path');
|
|
5
5
|
const { flattenGenomeBindings, mergeGenomeBindings } = require('../genomes/bindings');
|
|
6
6
|
|
|
7
|
+
const TIER_COSTS = {
|
|
8
|
+
powerful: { inputPer1k: 0.015, outputPer1k: 0.075 },
|
|
9
|
+
balanced: { inputPer1k: 0.003, outputPer1k: 0.015 },
|
|
10
|
+
fast: { inputPer1k: 0.0008, outputPer1k: 0.004 },
|
|
11
|
+
none: { inputPer1k: 0, outputPer1k: 0 }
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function estimateRunCost(executors) {
|
|
15
|
+
if (!Array.isArray(executors) || executors.length === 0) return null;
|
|
16
|
+
let total = 0;
|
|
17
|
+
for (const ex of executors) {
|
|
18
|
+
const tier = ex.modelTier || (ex.usesLLM === false ? 'none' : 'balanced');
|
|
19
|
+
const cost = TIER_COSTS[tier] || TIER_COSTS.balanced;
|
|
20
|
+
total += (cost.inputPer1k * 2) + (cost.outputPer1k * 1);
|
|
21
|
+
}
|
|
22
|
+
return Math.round(total * 1000) / 1000;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function buildTierSummary(executors) {
|
|
26
|
+
if (!Array.isArray(executors) || executors.length === 0) return null;
|
|
27
|
+
const counts = {};
|
|
28
|
+
for (const ex of executors) {
|
|
29
|
+
const tier = ex.modelTier || (ex.usesLLM === false ? 'none' : 'balanced');
|
|
30
|
+
counts[tier] = (counts[tier] || 0) + 1;
|
|
31
|
+
}
|
|
32
|
+
return Object.entries(counts).map(([t, n]) => `${t}×${n}`).join(' / ');
|
|
33
|
+
}
|
|
34
|
+
|
|
7
35
|
const SQUADS_DIR = '.aioson/squads';
|
|
8
36
|
const AGENTS_ROOT = 'agents';
|
|
9
37
|
const OUTPUT_ROOT = 'output';
|
|
@@ -278,7 +306,9 @@ async function buildSquadRecordFromPackageDir(targetDir, slug) {
|
|
|
278
306
|
: outputExists && (await pathExists(path.join(targetDir, outputDir, 'session.html')))
|
|
279
307
|
? normalizeRel(path.join(outputDir, 'session.html'))
|
|
280
308
|
: '—',
|
|
281
|
-
mtime: latestHtml?.mtime || manifestStat?.mtime || null
|
|
309
|
+
mtime: latestHtml?.mtime || manifestStat?.mtime || null,
|
|
310
|
+
tierSummary: buildTierSummary(manifest.executors),
|
|
311
|
+
estimatedCost: estimateRunCost(manifest.executors)
|
|
282
312
|
};
|
|
283
313
|
}
|
|
284
314
|
|
|
@@ -410,6 +440,12 @@ async function runSquadStatus({ args, logger, t }) {
|
|
|
410
440
|
agent_count: squad.agentGenomes.length
|
|
411
441
|
})
|
|
412
442
|
);
|
|
443
|
+
if (squad.tierSummary) {
|
|
444
|
+
logger.log(t('squad_status.model_tiers', { value: squad.tierSummary }));
|
|
445
|
+
}
|
|
446
|
+
if (squad.estimatedCost != null) {
|
|
447
|
+
logger.log(t('squad_status.estimated_cost', { value: squad.estimatedCost.toFixed(3) }));
|
|
448
|
+
}
|
|
413
449
|
if (i < squads.length - 1) logger.log('');
|
|
414
450
|
}
|
|
415
451
|
|
|
@@ -64,6 +64,18 @@ async function validateStructure(projectDir, slug, manifest) {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
// Check api_endpoints workers
|
|
68
|
+
const apiEndpoints = Array.isArray(manifest.api_endpoints) ? manifest.api_endpoints : [];
|
|
69
|
+
for (const ep of apiEndpoints) {
|
|
70
|
+
if (ep.worker) {
|
|
71
|
+
const workerDir = path.join(squadDir, 'workers', ep.worker);
|
|
72
|
+
if (!(await pathExists(workerDir))) {
|
|
73
|
+
const rel = path.relative(projectDir, workerDir).replace(/\\/g, '/');
|
|
74
|
+
errors.push(`api_endpoints: worker "${ep.worker}" not found at ${rel}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
67
79
|
// Check output dir (warning only)
|
|
68
80
|
const outputDir = path.join(projectDir, 'output', slug);
|
|
69
81
|
if (!(await pathExists(outputDir))) {
|
|
@@ -197,7 +209,56 @@ async function validateSemanticDeep(projectDir, slug, manifest) {
|
|
|
197
209
|
}
|
|
198
210
|
}
|
|
199
211
|
|
|
200
|
-
// 6.
|
|
212
|
+
// 6. Task decomposition validation
|
|
213
|
+
for (const exec of executors) {
|
|
214
|
+
const tasks = Array.isArray(exec.tasks) ? exec.tasks : [];
|
|
215
|
+
if (tasks.length > 0) {
|
|
216
|
+
const orders = tasks.map(t => t.order).sort((a, b) => a - b);
|
|
217
|
+
for (let i = 0; i < orders.length; i++) {
|
|
218
|
+
if (orders[i] !== i + 1) {
|
|
219
|
+
warnings.push(`Executor "${exec.slug}": task order is not sequential (expected ${i + 1}, got ${orders[i]})`);
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// 6b. Model tiering validation
|
|
227
|
+
for (const exec of executors) {
|
|
228
|
+
if (exec.usesLLM === false && exec.modelTier && exec.modelTier !== 'none') {
|
|
229
|
+
warnings.push(`Executor "${exec.slug}": usesLLM is false but modelTier is "${exec.modelTier}" (expected "none")`);
|
|
230
|
+
}
|
|
231
|
+
if (exec.type === 'worker' && exec.modelTier && exec.modelTier !== 'none') {
|
|
232
|
+
warnings.push(`Executor "${exec.slug}": type is "worker" but modelTier is "${exec.modelTier}" (expected "none")`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 7. Review loop validation
|
|
237
|
+
const workflows = Array.isArray(manifest.workflows) ? manifest.workflows : [];
|
|
238
|
+
const executorSlugs = executors.map(e => e.slug);
|
|
239
|
+
for (const wf of workflows) {
|
|
240
|
+
const phases = Array.isArray(wf.phases) ? wf.phases : [];
|
|
241
|
+
const phaseIds = phases.map(p => p.id);
|
|
242
|
+
for (const phase of phases) {
|
|
243
|
+
if (phase.review) {
|
|
244
|
+
const rv = phase.review;
|
|
245
|
+
if (rv.reviewer && !executorSlugs.includes(rv.reviewer)) {
|
|
246
|
+
errors.push(`Workflow "${wf.slug}" phase "${phase.id}": reviewer "${rv.reviewer}" is not a declared executor`);
|
|
247
|
+
}
|
|
248
|
+
if (rv.onReject && !phaseIds.includes(rv.onReject)) {
|
|
249
|
+
errors.push(`Workflow "${wf.slug}" phase "${phase.id}": onReject target "${rv.onReject}" is not a valid phase ID`);
|
|
250
|
+
}
|
|
251
|
+
if (rv.reviewer && rv.reviewer === phase.executor) {
|
|
252
|
+
warnings.push(`Workflow "${wf.slug}" phase "${phase.id}": reviewer should not be the same as the creator executor`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (phase.review && (!phase.vetoConditions || phase.vetoConditions.length === 0)) {
|
|
256
|
+
warnings.push(`Workflow "${wf.slug}" phase "${phase.id}": has review but no vetoConditions — consider adding veto guards`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// 7. Readiness não contradiz blockers
|
|
201
262
|
if (manifest.readiness) {
|
|
202
263
|
for (const [dim, val] of Object.entries(manifest.readiness)) {
|
|
203
264
|
if (val && val.status === 'ready' && val.blocker) {
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const fs = require('node:fs/promises');
|
|
5
|
+
const { WebhookServer } = require('../lib/webhook-server');
|
|
6
|
+
const { getCliVersionSync } = require('../version');
|
|
7
|
+
const { listWorkers, runWorker } = require('../worker-runner');
|
|
8
|
+
const {
|
|
9
|
+
loadSession,
|
|
10
|
+
appendTurn,
|
|
11
|
+
buildContextualInput,
|
|
12
|
+
cleanExpiredSessions
|
|
13
|
+
} = require('../squad/external-session');
|
|
14
|
+
|
|
15
|
+
const SQUADS_DIR = path.join('.aioson', 'squads');
|
|
16
|
+
|
|
17
|
+
async function discoverSquads(projectDir) {
|
|
18
|
+
const squadsDir = path.join(projectDir, SQUADS_DIR);
|
|
19
|
+
let entries;
|
|
20
|
+
try {
|
|
21
|
+
entries = await fs.readdir(squadsDir, { withFileTypes: true });
|
|
22
|
+
} catch {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
return entries.filter(e => e.isDirectory()).map(e => e.name);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function executeSquad(projectDir, squadSlug, contextualInput) {
|
|
29
|
+
const workers = await listWorkers(projectDir, squadSlug);
|
|
30
|
+
if (workers.length === 0) {
|
|
31
|
+
throw new Error(`No workers found in squad "${squadSlug}"`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Run the first eligible worker as the squad entry point
|
|
35
|
+
for (const worker of workers) {
|
|
36
|
+
const result = await runWorker(
|
|
37
|
+
projectDir,
|
|
38
|
+
squadSlug,
|
|
39
|
+
worker.slug,
|
|
40
|
+
{ input: contextualInput },
|
|
41
|
+
{ triggerType: 'webhook' }
|
|
42
|
+
);
|
|
43
|
+
if (result.ok) {
|
|
44
|
+
const out = result.output;
|
|
45
|
+
return typeof out === 'string' ? out : JSON.stringify(out);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
throw new Error(`All workers in squad "${squadSlug}" failed`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function handleStart(projectDir, options, { logger }) {
|
|
53
|
+
const port = parseInt(options.port || process.env.AIOSON_WEBHOOK_PORT || '3210', 10);
|
|
54
|
+
const token = options.token || process.env.AIOSON_WEBHOOK_TOKEN || '';
|
|
55
|
+
const ttlHours = parseInt(options.sessionTtl || process.env.AIOSON_SESSION_TTL_HOURS || '24', 10);
|
|
56
|
+
const version = getCliVersionSync();
|
|
57
|
+
|
|
58
|
+
if (!token) {
|
|
59
|
+
logger.error('Warning: AIOSON_WEBHOOK_TOKEN not set — server running without authentication.');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Clean up expired sessions on startup
|
|
63
|
+
const cleaned = await cleanExpiredSessions(projectDir, ttlHours);
|
|
64
|
+
if (cleaned > 0) logger.log(`Cleaned ${cleaned} expired session(s).`);
|
|
65
|
+
|
|
66
|
+
const slugs = await discoverSquads(projectDir);
|
|
67
|
+
const squads = slugs.map(name => ({ name, timeout_ms: 120000 }));
|
|
68
|
+
|
|
69
|
+
const server = new WebhookServer({
|
|
70
|
+
port,
|
|
71
|
+
token,
|
|
72
|
+
squads,
|
|
73
|
+
version,
|
|
74
|
+
onTrigger: async ({ squad, input, session_id, metadata }) => {
|
|
75
|
+
// Load prior session context (if any)
|
|
76
|
+
const session = session_id
|
|
77
|
+
? await loadSession(projectDir, session_id, ttlHours)
|
|
78
|
+
: null;
|
|
79
|
+
|
|
80
|
+
const contextualInput = buildContextualInput(session, input);
|
|
81
|
+
|
|
82
|
+
// Save user turn before execution
|
|
83
|
+
if (session_id) {
|
|
84
|
+
await appendTurn(projectDir, session_id, 'user', input, metadata || {}, ttlHours);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const response = await executeSquad(projectDir, squad, contextualInput);
|
|
88
|
+
|
|
89
|
+
// Save assistant turn after execution
|
|
90
|
+
if (session_id) {
|
|
91
|
+
await appendTurn(projectDir, session_id, 'assistant', response, {}, ttlHours);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return { response };
|
|
95
|
+
},
|
|
96
|
+
onQuery: async ({ squad, query, max_results }) => {
|
|
97
|
+
const raw = await executeSquad(projectDir, squad, query);
|
|
98
|
+
// Best-effort: if the output is JSON, parse and slice; otherwise wrap as single result
|
|
99
|
+
let results;
|
|
100
|
+
try {
|
|
101
|
+
const parsed = JSON.parse(raw);
|
|
102
|
+
results = Array.isArray(parsed) ? parsed.slice(0, max_results) : [parsed];
|
|
103
|
+
} catch {
|
|
104
|
+
results = [{ text: raw }];
|
|
105
|
+
}
|
|
106
|
+
return { results };
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
await server.start();
|
|
111
|
+
|
|
112
|
+
logger.log(`AIOSON squad webhook server started on port ${port}`);
|
|
113
|
+
if (squads.length > 0) {
|
|
114
|
+
logger.log(`Available squads: ${squads.map(s => s.name).join(', ')}`);
|
|
115
|
+
} else {
|
|
116
|
+
logger.log('No squads discovered in .aioson/squads/');
|
|
117
|
+
}
|
|
118
|
+
logger.log('Endpoints: POST /trigger GET /status/:run_id GET /health');
|
|
119
|
+
logger.log('Press Ctrl+C to stop.');
|
|
120
|
+
|
|
121
|
+
process.on('SIGINT', async () => {
|
|
122
|
+
await server.stop();
|
|
123
|
+
process.exit(0);
|
|
124
|
+
});
|
|
125
|
+
process.on('SIGTERM', async () => {
|
|
126
|
+
await server.stop();
|
|
127
|
+
process.exit(0);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Keep the process alive until signal
|
|
131
|
+
await new Promise(() => {});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function handleConfig(options, { logger }) {
|
|
135
|
+
const channel = options.channel || 'whatsapp';
|
|
136
|
+
const squad = options.squad || 'atendimento';
|
|
137
|
+
const port = options.port || '3210';
|
|
138
|
+
|
|
139
|
+
logger.log(`OpenClaw configuration for squad "${squad}" via ${channel}:\n`);
|
|
140
|
+
logger.log(`hooks:\n ${channel}:\n auto_reply:\n - pattern: ".*"\n action: webhook\n url: "http://SEU_SERVIDOR:${port}/trigger"\n headers:\n Authorization: "Bearer \${AIOSON_WEBHOOK_TOKEN}"\n body_template: |\n {\n "squad": "${squad}",\n "input": "{{message.text}}",\n "session_id": "${channel}:{{message.from}}",\n "callback_url": "{{openclaw.callback_url}}",\n "metadata": {\n "channel": "${channel}",\n "phone": "{{message.from}}",\n "user_name": "{{message.contact_name}}"\n }\n }`);
|
|
141
|
+
|
|
142
|
+
return { ok: true };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function runSquadWebhook({ args, options, logger }) {
|
|
146
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
147
|
+
const sub = options.sub || 'start';
|
|
148
|
+
|
|
149
|
+
switch (sub) {
|
|
150
|
+
case 'start':
|
|
151
|
+
return handleStart(targetDir, options, { logger });
|
|
152
|
+
case 'config':
|
|
153
|
+
return handleConfig(options, { logger });
|
|
154
|
+
default:
|
|
155
|
+
logger.error(`Unknown subcommand: "${sub}". Use: start, config`);
|
|
156
|
+
return { ok: false };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
module.exports = { runSquadWebhook };
|