@jaimevalasek/aioson 1.6.0 → 1.7.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 +49 -0
- package/README.md +729 -232
- package/docs/design-previews/pt.squarespace.com-homepage.html +889 -0
- package/docs/integrations/sdlc-genius-boundary.md +76 -0
- package/docs/integrations/sdlc-genius-eval-matrix.md +75 -0
- package/docs/integrations/sdlc-genius-install-checklist.md +93 -0
- package/docs/integrations/sdlc-genius-review-samples.md +86 -0
- package/docs/pt/README.md +3 -0
- package/docs/pt/agentes.md +1 -0
- package/docs/pt/comandos-cli.md +888 -2
- package/docs/pt/design-hybrid-forge.md +255 -6
- package/docs/pt/devlog-pipeline.md +270 -0
- package/docs/pt/fluxo-artefatos.md +178 -0
- package/docs/pt/hooks-session-guard.md +454 -0
- package/docs/pt/monitor-de-contexto.md +59 -5
- package/docs/pt/sdd-automation-scripts.md +557 -0
- package/docs/pt/site-forge.md +309 -0
- package/docs/pt/spec-learnings-pipeline.md +265 -0
- package/package.json +1 -1
- package/src/a2a/client.js +165 -0
- package/src/a2a/server.js +223 -0
- package/src/cli.js +235 -1
- package/src/commands/agent-audit.js +397 -0
- package/src/commands/agent-export-skill.js +229 -0
- package/src/commands/artifact-validate.js +189 -0
- package/src/commands/brief-gen.js +405 -0
- package/src/commands/brief-validate.js +65 -0
- package/src/commands/classify.js +256 -0
- package/src/commands/context-compact.js +49 -0
- package/src/commands/context-health.js +175 -0
- package/src/commands/context-monitor.js +71 -0
- package/src/commands/context-trim.js +177 -0
- package/src/commands/detect-test-runner.js +55 -0
- package/src/commands/devlog-export-brains.js +27 -0
- package/src/commands/devlog-process.js +292 -0
- package/src/commands/devlog-watch.js +131 -0
- package/src/commands/feature-close.js +165 -0
- package/src/commands/gate-check.js +228 -0
- package/src/commands/hooks-emit.js +253 -0
- package/src/commands/hooks-install.js +347 -0
- package/src/commands/learning-auto-promote.js +195 -0
- package/src/commands/learning-evolve.js +18 -9
- package/src/commands/learning-export.js +103 -0
- package/src/commands/learning-rollback.js +164 -0
- package/src/commands/live.js +25 -1
- package/src/commands/pattern-detect.js +33 -0
- package/src/commands/preflight-context.js +30 -0
- package/src/commands/preflight.js +208 -0
- package/src/commands/pulse-update.js +130 -0
- package/src/commands/runner-daemon.js +274 -0
- package/src/commands/runner-plan.js +70 -0
- package/src/commands/runner-queue-from-plan.js +166 -0
- package/src/commands/runner-queue.js +189 -0
- package/src/commands/runner-run.js +129 -0
- package/src/commands/runtime.js +47 -1
- package/src/commands/self-implement-loop.js +256 -0
- package/src/commands/session-guard.js +218 -0
- package/src/commands/sizing.js +165 -0
- package/src/commands/skill.js +65 -0
- package/src/commands/spec-checkpoint.js +177 -0
- package/src/commands/spec-status.js +79 -0
- package/src/commands/spec-sync.js +190 -0
- package/src/commands/spec-tasks.js +288 -0
- package/src/commands/squad-autorun.js +1220 -0
- package/src/commands/squad-bus.js +217 -0
- package/src/commands/squad-card.js +149 -0
- package/src/commands/squad-daemon.js +134 -0
- package/src/commands/squad-dependency-graph.js +164 -0
- package/src/commands/squad-review.js +106 -0
- package/src/commands/squad-scaffold.js +55 -0
- package/src/commands/squad-tool-register.js +157 -0
- package/src/commands/state-save.js +122 -0
- package/src/commands/update.js +2 -0
- package/src/commands/verify-gate.js +572 -0
- package/src/commands/workflow-execute.js +241 -0
- package/src/constants.js +9 -0
- package/src/install-profile.js +2 -2
- package/src/install-wizard.js +3 -2
- package/src/installer.js +6 -0
- package/src/lib/health-check.js +158 -0
- package/src/lib/hook-protocol.js +76 -0
- package/src/mcp/apps/squad-dashboard/app.js +163 -0
- package/src/mcp/apps/squad-dashboard/index.html +261 -0
- package/src/mcp/apps/squad-dashboard/mcp-manifest.json +23 -0
- package/src/mcp/resources/squad-state.js +130 -0
- package/src/preflight-engine.js +443 -0
- package/src/runner/cascade.js +97 -0
- package/src/runner/cli-launcher.js +109 -0
- package/src/runner/plan-importer.js +63 -0
- package/src/runner/queue-store.js +159 -0
- package/src/runtime-store.js +61 -3
- package/src/squad/agent-teams-adapter.js +264 -0
- package/src/squad/brief-validator.js +350 -0
- package/src/squad/bus-bridge.js +140 -0
- package/src/squad/context-compactor.js +265 -0
- package/src/squad/cross-ai-synthesizer.js +250 -0
- package/src/squad/hooks-generator.js +196 -0
- package/src/squad/inter-squad-events.js +175 -0
- package/src/squad/intra-bus.js +345 -0
- package/src/squad/learning-extractor.js +213 -0
- package/src/squad/pattern-detector.js +365 -0
- package/src/squad/preflight-context.js +296 -0
- package/src/squad/recovery-context.js +242 -71
- package/src/squad/reflection.js +365 -0
- package/src/squad/squad-scaffold.js +177 -0
- package/src/squad/state-manager.js +310 -0
- package/src/squad/task-decomposer.js +652 -0
- package/src/squad/verify-gate.js +303 -0
- package/src/updater.js +4 -5
- package/src/worker-runner.js +186 -1
- package/template/.aioson/agents/analyst.md +62 -1
- package/template/.aioson/agents/architect.md +61 -1
- package/template/.aioson/agents/design-hybrid-forge.md +14 -0
- package/template/.aioson/agents/dev.md +242 -24
- package/template/.aioson/agents/deyvin.md +66 -8
- package/template/.aioson/agents/discovery-design-doc.md +44 -0
- package/template/.aioson/agents/genome.md +14 -0
- package/template/.aioson/agents/neo.md +78 -1
- package/template/.aioson/agents/orache.md +50 -4
- package/template/.aioson/agents/orchestrator.md +197 -1
- package/template/.aioson/agents/pm.md +35 -0
- package/template/.aioson/agents/product.md +50 -5
- package/template/.aioson/agents/profiler-enricher.md +14 -0
- package/template/.aioson/agents/profiler-forge.md +14 -0
- package/template/.aioson/agents/profiler-researcher.md +14 -0
- package/template/.aioson/agents/qa.md +172 -21
- package/template/.aioson/agents/setup.md +79 -9
- package/template/.aioson/agents/sheldon.md +131 -6
- package/template/.aioson/agents/site-forge.md +1753 -0
- package/template/.aioson/agents/squad.md +162 -0
- package/template/.aioson/agents/tester.md +53 -0
- package/template/.aioson/agents/ux-ui.md +34 -1
- package/template/.aioson/brains/README.md +128 -0
- package/template/.aioson/brains/_index.json +16 -0
- package/template/.aioson/brains/scripts/query.js +103 -0
- package/template/.aioson/brains/site-forge/visual-patterns.brain.json +205 -0
- package/template/.aioson/config.md +143 -13
- package/template/.aioson/constitution.md +33 -0
- package/template/.aioson/context/project-pulse.md +34 -0
- package/template/.aioson/docs/LAYERS.md +79 -0
- package/template/.aioson/docs/README.md +76 -0
- package/template/.aioson/docs/example-external-api-context.md +72 -0
- package/template/.aioson/locales/en/agents/architect.md +17 -0
- package/template/.aioson/locales/en/agents/dev.md +79 -13
- package/template/.aioson/locales/en/agents/orache.md +6 -0
- package/template/.aioson/locales/en/agents/orchestrator.md +24 -0
- package/template/.aioson/locales/en/agents/product.md +50 -0
- package/template/.aioson/locales/en/agents/sheldon.md +115 -0
- package/template/.aioson/locales/en/agents/squad.md +14 -0
- package/template/.aioson/locales/en/agents/tester.md +6 -0
- package/template/.aioson/locales/es/agents/analyst.md +2 -0
- package/template/.aioson/locales/es/agents/architect.md +19 -0
- package/template/.aioson/locales/es/agents/dev.md +64 -4
- package/template/.aioson/locales/es/agents/deyvin.md +2 -0
- package/template/.aioson/locales/es/agents/discovery-design-doc.md +2 -0
- package/template/.aioson/locales/es/agents/genome.md +2 -0
- package/template/.aioson/locales/es/agents/neo.md +2 -0
- package/template/.aioson/locales/es/agents/orache.md +2 -0
- package/template/.aioson/locales/es/agents/orchestrator.md +26 -0
- package/template/.aioson/locales/es/agents/pair.md +2 -0
- package/template/.aioson/locales/es/agents/pm.md +2 -0
- package/template/.aioson/locales/es/agents/product.md +52 -0
- package/template/.aioson/locales/es/agents/profiler-enricher.md +2 -0
- package/template/.aioson/locales/es/agents/profiler-forge.md +2 -0
- package/template/.aioson/locales/es/agents/profiler-researcher.md +2 -0
- package/template/.aioson/locales/es/agents/qa.md +2 -0
- package/template/.aioson/locales/es/agents/setup.md +2 -0
- package/template/.aioson/locales/es/agents/sheldon.md +117 -0
- package/template/.aioson/locales/es/agents/squad.md +16 -0
- package/template/.aioson/locales/es/agents/tester.md +9 -0
- package/template/.aioson/locales/es/agents/ux-ui.md +2 -0
- package/template/.aioson/locales/fr/agents/analyst.md +2 -0
- package/template/.aioson/locales/fr/agents/architect.md +19 -0
- package/template/.aioson/locales/fr/agents/dev.md +64 -4
- package/template/.aioson/locales/fr/agents/deyvin.md +2 -0
- package/template/.aioson/locales/fr/agents/discovery-design-doc.md +2 -0
- package/template/.aioson/locales/fr/agents/genome.md +2 -0
- package/template/.aioson/locales/fr/agents/neo.md +2 -0
- package/template/.aioson/locales/fr/agents/orache.md +2 -0
- package/template/.aioson/locales/fr/agents/orchestrator.md +26 -0
- package/template/.aioson/locales/fr/agents/pair.md +2 -0
- package/template/.aioson/locales/fr/agents/pm.md +2 -0
- package/template/.aioson/locales/fr/agents/product.md +52 -0
- package/template/.aioson/locales/fr/agents/profiler-enricher.md +2 -0
- package/template/.aioson/locales/fr/agents/profiler-forge.md +2 -0
- package/template/.aioson/locales/fr/agents/profiler-researcher.md +2 -0
- package/template/.aioson/locales/fr/agents/qa.md +2 -0
- package/template/.aioson/locales/fr/agents/setup.md +2 -0
- package/template/.aioson/locales/fr/agents/sheldon.md +117 -0
- package/template/.aioson/locales/fr/agents/squad.md +16 -0
- package/template/.aioson/locales/fr/agents/tester.md +9 -0
- package/template/.aioson/locales/fr/agents/ux-ui.md +2 -0
- package/template/.aioson/locales/pt-BR/agents/analyst.md +64 -3
- package/template/.aioson/locales/pt-BR/agents/architect.md +42 -0
- package/template/.aioson/locales/pt-BR/agents/dev.md +147 -14
- package/template/.aioson/locales/pt-BR/agents/deyvin.md +47 -0
- package/template/.aioson/locales/pt-BR/agents/neo.md +62 -1
- package/template/.aioson/locales/pt-BR/agents/orchestrator.md +158 -2
- package/template/.aioson/locales/pt-BR/agents/pm.md +95 -1
- package/template/.aioson/locales/pt-BR/agents/product.md +145 -18
- package/template/.aioson/locales/pt-BR/agents/qa.md +16 -0
- package/template/.aioson/locales/pt-BR/agents/setup.md +101 -18
- package/template/.aioson/locales/pt-BR/agents/sheldon.md +132 -1
- package/template/.aioson/locales/pt-BR/agents/squad.md +14 -0
- package/template/.aioson/locales/pt-BR/agents/tester.md +449 -0
- package/template/.aioson/rules/README.md +69 -0
- package/template/.aioson/rules/data-format-convention.md +136 -0
- package/template/.aioson/rules/example-monetary-values.md +30 -0
- package/template/.aioson/schemas/squad-manifest.schema.json +124 -3
- package/template/.aioson/skills/design/pt.squarespace.com/.skill-meta.json +31 -0
- package/template/.aioson/skills/design/pt.squarespace.com/SKILL.md +66 -0
- package/template/.aioson/skills/design/pt.squarespace.com/references/components.md +368 -0
- package/template/.aioson/skills/design/pt.squarespace.com/references/design-tokens.md +150 -0
- package/template/.aioson/skills/design/pt.squarespace.com/references/motion.md +270 -0
- package/template/.aioson/skills/design/pt.squarespace.com/references/patterns.md +189 -0
- package/template/.aioson/skills/design/pt.squarespace.com/references/websites.md +165 -0
- package/template/.aioson/skills/process/aioson-spec-driven/SKILL.md +1 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/analyst.md +30 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/architect.md +23 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/dev.md +47 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/deyvin.md +27 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/maintenance-and-state.md +35 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/product.md +25 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/qa.md +30 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/sheldon.md +25 -0
- package/template/.aioson/skills/process/design-hybrid-forge/SKILL.md +4 -1
- package/template/.aioson/skills/process/design-hybrid-forge/references/output-contract.md +15 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/pair-compatibility.md +32 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/quality-gates.md +20 -0
- package/template/.aioson/skills/process/simplify/SKILL.md +173 -0
- package/template/.aioson/skills/static/context-budget-guide.md +46 -0
- package/template/.aioson/skills/static/harness-sensors.md +74 -0
- package/template/.aioson/skills/static/multi-agent-patterns.md +43 -0
- package/template/.aioson/skills/static/react-motion-patterns.md +22 -0
- package/template/.aioson/skills/static/static-html-patterns/checklists.md +43 -0
- package/template/.aioson/skills/static/static-html-patterns/css-tokens.md +609 -0
- package/template/.aioson/skills/static/static-html-patterns/motion.md +193 -0
- package/template/.aioson/skills/static/static-html-patterns/premium.md +711 -0
- package/template/.aioson/skills/static/static-html-patterns/structure.md +209 -0
- package/template/.aioson/skills/static/static-html-patterns/utilities.md +190 -0
- package/template/.aioson/skills/static/static-html-patterns.md +58 -1913
- package/template/.aioson/skills/static/threejs-patterns.md +929 -0
- package/template/.aioson/skills/static/web-research-cache.md +112 -0
- package/template/.aioson/tasks/implementation-plan.md +21 -1
- package/template/.claude/commands/aioson/agent/design-hybrid-forge.md +5 -0
- package/template/.claude/commands/aioson/agent/orache.md +5 -0
- package/template/.claude/commands/aioson/agent/sheldon.md +5 -0
- package/template/.claude/commands/aioson/agent/site-forge.md +5 -0
- package/template/AGENTS.md +55 -3
- package/template/CLAUDE.md +30 -0
- package/template/OPENCODE.md +4 -0
- package/template/researchs/.gitkeep +0 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aioson workflow:execute — orchestrate the full agent workflow for a feature.
|
|
5
|
+
*
|
|
6
|
+
* Uses agent:prompt, gate:check, pulse:update, feature:close as building blocks.
|
|
7
|
+
* Always supports --dry-run to preview the plan without executing.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* aioson workflow:execute . --feature=checkout --tool=claude --dry-run
|
|
11
|
+
* aioson workflow:execute . --feature=checkout --tool=claude
|
|
12
|
+
* aioson workflow:execute . --feature=checkout --tool=claude --start-from=dev
|
|
13
|
+
* aioson workflow:execute . --feature=checkout --json --dry-run
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const path = require('node:path');
|
|
17
|
+
const { execSync } = require('node:child_process');
|
|
18
|
+
const {
|
|
19
|
+
detectClassification,
|
|
20
|
+
scanArtifacts,
|
|
21
|
+
readPhaseGates
|
|
22
|
+
} = require('../preflight-engine');
|
|
23
|
+
|
|
24
|
+
const BAR = '━'.repeat(45);
|
|
25
|
+
|
|
26
|
+
const WORKFLOW_BY_CLASSIFICATION = {
|
|
27
|
+
MICRO: [
|
|
28
|
+
{ agent: 'dev', gate_before: null, gate_after: null, description: 'Direct implementation' }
|
|
29
|
+
],
|
|
30
|
+
SMALL: [
|
|
31
|
+
{ agent: 'product', gate_before: null, gate_after: null, description: 'Generate PRD' },
|
|
32
|
+
{ agent: 'sheldon', gate_before: null, gate_after: null, description: 'Enrich PRD (recommended)', optional: true },
|
|
33
|
+
{ agent: 'analyst', gate_before: null, gate_after: 'A', description: 'Map requirements + spec' },
|
|
34
|
+
{ agent: 'dev', gate_before: 'A', gate_after: 'C', description: 'Implementation' },
|
|
35
|
+
{ agent: 'qa', gate_before: 'C', gate_after: 'D', description: 'QA + feature closure' }
|
|
36
|
+
],
|
|
37
|
+
MEDIUM: [
|
|
38
|
+
{ agent: 'product', gate_before: null, gate_after: null, description: 'Generate PRD' },
|
|
39
|
+
{ agent: 'sheldon', gate_before: null, gate_after: null, description: 'Enrich PRD (required)', optional: false },
|
|
40
|
+
{ agent: 'analyst', gate_before: null, gate_after: 'A', description: 'Map requirements + spec' },
|
|
41
|
+
{ agent: 'architect', gate_before: 'A', gate_after: 'B', description: 'Architecture design' },
|
|
42
|
+
{ agent: 'ux-ui', gate_before: 'A', gate_after: 'B', description: 'UI/UX design', optional: true },
|
|
43
|
+
{ agent: 'pm', gate_before: 'B', gate_after: null, description: 'Backlog + PM plan' },
|
|
44
|
+
{ agent: 'dev', gate_before: 'C', gate_after: 'C', description: 'Implementation' },
|
|
45
|
+
{ agent: 'qa', gate_before: 'C', gate_after: 'D', description: 'QA + feature closure' }
|
|
46
|
+
]
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const GATE_NAMES = { A: 'requirements', B: 'design', C: 'plan', D: 'execution' };
|
|
50
|
+
|
|
51
|
+
async function buildExecutionPlan(targetDir, slug, classification, startFrom) {
|
|
52
|
+
const steps = WORKFLOW_BY_CLASSIFICATION[classification] || WORKFLOW_BY_CLASSIFICATION.SMALL;
|
|
53
|
+
const artifacts = await scanArtifacts(targetDir, slug);
|
|
54
|
+
const gates = await readPhaseGates(targetDir, slug);
|
|
55
|
+
|
|
56
|
+
const plan = [];
|
|
57
|
+
let stepNum = 1;
|
|
58
|
+
let startFromReached = !startFrom;
|
|
59
|
+
|
|
60
|
+
for (const step of steps) {
|
|
61
|
+
if (startFrom && !startFromReached) {
|
|
62
|
+
if (step.agent === startFrom) startFromReached = true;
|
|
63
|
+
else continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Determine if step can be skipped (artifact already exists)
|
|
67
|
+
let skip = false;
|
|
68
|
+
let skipReason = null;
|
|
69
|
+
|
|
70
|
+
if (step.agent === 'product' && artifacts.prd.exists) {
|
|
71
|
+
skip = true; skipReason = 'prd already exists';
|
|
72
|
+
} else if (step.agent === 'sheldon' && artifacts.sheldon_enrichment.exists) {
|
|
73
|
+
skip = true; skipReason = 'sheldon enrichment already exists';
|
|
74
|
+
} else if (step.agent === 'analyst' && artifacts.requirements.exists && gates.requirements === 'approved') {
|
|
75
|
+
skip = true; skipReason = 'requirements + Gate A already approved';
|
|
76
|
+
} else if (step.agent === 'architect' && artifacts.architecture.exists && gates.design === 'approved') {
|
|
77
|
+
skip = true; skipReason = 'architecture + Gate B already approved';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
plan.push({
|
|
81
|
+
step: stepNum++,
|
|
82
|
+
agent: step.agent,
|
|
83
|
+
description: step.description,
|
|
84
|
+
gate_before: step.gate_before,
|
|
85
|
+
gate_after: step.gate_after,
|
|
86
|
+
optional: step.optional || false,
|
|
87
|
+
skip,
|
|
88
|
+
skip_reason: skipReason
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return plan;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function runCommand(cmd) {
|
|
96
|
+
try {
|
|
97
|
+
execSync(cmd, { stdio: 'inherit' });
|
|
98
|
+
return { ok: true };
|
|
99
|
+
} catch (err) {
|
|
100
|
+
return { ok: false, error: err.message };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function runWorkflowExecute({ args, options = {}, logger }) {
|
|
105
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
106
|
+
const slug = options.feature ? String(options.feature) : null;
|
|
107
|
+
const tool = options.tool ? String(options.tool) : 'claude';
|
|
108
|
+
const dryRun = Boolean(options['dry-run'] || options.dry);
|
|
109
|
+
const startFrom = options['start-from'] ? String(options['start-from']) : null;
|
|
110
|
+
const skipOptional = Boolean(options['skip-optional']);
|
|
111
|
+
|
|
112
|
+
if (!slug) {
|
|
113
|
+
if (options.json) return { ok: false, reason: 'missing_feature' };
|
|
114
|
+
logger.log('--feature=<slug> is required.');
|
|
115
|
+
return { ok: false };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let classification = await detectClassification(targetDir, slug);
|
|
119
|
+
if (!classification) classification = options.classification ? String(options.classification).toUpperCase() : 'SMALL';
|
|
120
|
+
|
|
121
|
+
const plan = await buildExecutionPlan(targetDir, slug, classification, startFrom);
|
|
122
|
+
const activePlan = plan.filter((s) => !s.skip && !(skipOptional && s.optional));
|
|
123
|
+
const skippedPlan = plan.filter((s) => s.skip);
|
|
124
|
+
|
|
125
|
+
if (dryRun || options.json) {
|
|
126
|
+
const result = {
|
|
127
|
+
ok: true,
|
|
128
|
+
feature: slug,
|
|
129
|
+
classification,
|
|
130
|
+
tool,
|
|
131
|
+
dry_run: true,
|
|
132
|
+
steps: plan,
|
|
133
|
+
active_steps: activePlan.length,
|
|
134
|
+
skipped_steps: skippedPlan.length
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
if (options.json) return result;
|
|
138
|
+
|
|
139
|
+
logger.log('');
|
|
140
|
+
logger.log(`Workflow Execution Plan — ${slug} (${classification})`);
|
|
141
|
+
logger.log(BAR);
|
|
142
|
+
|
|
143
|
+
for (const step of plan) {
|
|
144
|
+
const icon = step.skip ? '○ (skip)' : `Step ${step.step}:`;
|
|
145
|
+
const optional = step.optional ? ' (optional)' : '';
|
|
146
|
+
const gateInfo = step.gate_after ? ` → Gate ${step.gate_after} check` : '';
|
|
147
|
+
const skipInfo = step.skip ? ` — ${step.skip_reason}` : '';
|
|
148
|
+
logger.log(`${icon} @${step.agent}${optional} — ${step.description}${gateInfo}${skipInfo}`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
logger.log('');
|
|
152
|
+
logger.log(`Gates enforced: ${plan.filter((s) => s.gate_after && !s.skip).map((s) => s.gate_after).join(', ') || 'none'}`);
|
|
153
|
+
logger.log(`Active sessions: ${activePlan.length} | Skipped: ${skippedPlan.length}`);
|
|
154
|
+
logger.log('');
|
|
155
|
+
logger.log('Run without --dry-run to execute.');
|
|
156
|
+
logger.log('');
|
|
157
|
+
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Execute
|
|
162
|
+
logger.log('');
|
|
163
|
+
logger.log(`Workflow Execution — ${slug} (${classification})`);
|
|
164
|
+
logger.log(BAR);
|
|
165
|
+
|
|
166
|
+
let completed = 0;
|
|
167
|
+
let failed = 0;
|
|
168
|
+
const executionLog = [];
|
|
169
|
+
|
|
170
|
+
for (const step of plan) {
|
|
171
|
+
if (step.skip) {
|
|
172
|
+
logger.log(`[skip] @${step.agent} — ${step.skip_reason}`);
|
|
173
|
+
executionLog.push({ step: step.step, agent: step.agent, status: 'skipped', reason: step.skip_reason });
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (skipOptional && step.optional) {
|
|
178
|
+
logger.log(`[skip] @${step.agent} — optional, skipped`);
|
|
179
|
+
executionLog.push({ step: step.step, agent: step.agent, status: 'skipped', reason: 'optional' });
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Gate check before
|
|
184
|
+
if (step.gate_before) {
|
|
185
|
+
logger.log(`[Gate ${step.gate_before} check] pre-step ${step.step}...`);
|
|
186
|
+
const gateCmd = `aioson gate:check ${targetDir} --feature=${slug} --gate=${step.gate_before}`;
|
|
187
|
+
const gateResult = runCommand(gateCmd);
|
|
188
|
+
if (!gateResult.ok) {
|
|
189
|
+
logger.log(`[Gate ${step.gate_before}] BLOCKED — cannot proceed with @${step.agent}`);
|
|
190
|
+
executionLog.push({ step: step.step, agent: step.agent, status: 'blocked', gate: step.gate_before });
|
|
191
|
+
failed++;
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
logger.log(`[Step ${step.step}/${activePlan.length}] @${step.agent} — ${step.description}...`);
|
|
197
|
+
const agentCmd = `aioson agent:prompt ${targetDir} --agent=${step.agent} --feature=${slug} --tool=${tool}`;
|
|
198
|
+
const agentResult = runCommand(agentCmd);
|
|
199
|
+
|
|
200
|
+
if (!agentResult.ok) {
|
|
201
|
+
logger.log(`[Step ${step.step}] @${step.agent} FAILED`);
|
|
202
|
+
executionLog.push({ step: step.step, agent: step.agent, status: 'failed' });
|
|
203
|
+
failed++;
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Gate check after
|
|
208
|
+
if (step.gate_after) {
|
|
209
|
+
logger.log(`[Gate ${step.gate_after} check] post-step ${step.step}...`);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Pulse update
|
|
213
|
+
const pulseCmd = `aioson pulse:update ${targetDir} --agent=${step.agent} --feature=${slug} --action="${step.description}" 2>/dev/null || true`;
|
|
214
|
+
runCommand(pulseCmd);
|
|
215
|
+
|
|
216
|
+
executionLog.push({ step: step.step, agent: step.agent, status: 'completed' });
|
|
217
|
+
completed++;
|
|
218
|
+
logger.log(`[Step ${step.step}] @${step.agent} ✓`);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const allDone = completed === activePlan.length;
|
|
222
|
+
if (allDone) {
|
|
223
|
+
logger.log('');
|
|
224
|
+
logger.log(`Workflow complete: ${slug} → done`);
|
|
225
|
+
logger.log(`Total sessions: ${completed}`);
|
|
226
|
+
} else {
|
|
227
|
+
logger.log('');
|
|
228
|
+
logger.log(`Workflow stopped: ${completed} completed, ${failed} failed.`);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return {
|
|
232
|
+
ok: allDone,
|
|
233
|
+
feature: slug,
|
|
234
|
+
classification,
|
|
235
|
+
completed,
|
|
236
|
+
failed,
|
|
237
|
+
execution_log: executionLog
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
module.exports = { runWorkflowExecute };
|
package/src/constants.js
CHANGED
|
@@ -34,6 +34,7 @@ const MANAGED_FILES = [
|
|
|
34
34
|
'.aioson/agents/orache.md',
|
|
35
35
|
'.aioson/agents/genome.md',
|
|
36
36
|
'.aioson/agents/design-hybrid-forge.md',
|
|
37
|
+
'.aioson/agents/site-forge.md',
|
|
37
38
|
'.aioson/agents/profiler-researcher.md',
|
|
38
39
|
'.aioson/agents/profiler-enricher.md',
|
|
39
40
|
'.aioson/agents/profiler-forge.md',
|
|
@@ -358,6 +359,14 @@ const AGENT_DEFINITIONS = [
|
|
|
358
359
|
dependsOn: ['.aioson/context/project.context.md'],
|
|
359
360
|
output: '.aioson/installed-skills/{hybrid-slug}/SKILL.md + .aioson/installed-skills/{hybrid-slug}/references/ + .aioson/installed-skills/{hybrid-slug}/previews/ + .aioson/installed-skills/{hybrid-slug}/.skill-meta.json'
|
|
360
361
|
},
|
|
362
|
+
{
|
|
363
|
+
id: 'site-forge',
|
|
364
|
+
displayName: 'Site Forge',
|
|
365
|
+
command: '@site-forge',
|
|
366
|
+
path: '.aioson/agents/site-forge.md',
|
|
367
|
+
dependsOn: ['.aioson/context/project.context.md'],
|
|
368
|
+
output: 'src/components/*.tsx + src/app/page.tsx + docs/research/{hostname}/ + public/images/{hostname}/'
|
|
369
|
+
},
|
|
361
370
|
{
|
|
362
371
|
id: 'profiler-researcher',
|
|
363
372
|
displayName: 'Profiler Researcher',
|
package/src/install-profile.js
CHANGED
|
@@ -20,7 +20,7 @@ const TOOL_FILES = {
|
|
|
20
20
|
|
|
21
21
|
// Squad agent/task/skill paths (non-locale)
|
|
22
22
|
const SQUAD_PATHS = [
|
|
23
|
-
/^\.aioson\/agents\/(squad|orache|genome|profiler-researcher|profiler-enricher|profiler-forge
|
|
23
|
+
/^\.aioson\/agents\/(squad|orache|genome|profiler-researcher|profiler-enricher|profiler-forge)\.md$/,
|
|
24
24
|
/^\.aioson\/tasks\/squad-/,
|
|
25
25
|
/^\.aioson\/skills\/squad\//,
|
|
26
26
|
/^\.aioson\/templates\/squads\//,
|
|
@@ -28,7 +28,7 @@ const SQUAD_PATHS = [
|
|
|
28
28
|
];
|
|
29
29
|
|
|
30
30
|
// Squad agents inside locale dirs — filtered by BOTH locale AND squad
|
|
31
|
-
const SQUAD_LOCALE_AGENT_RE = /^\.aioson\/locales\/([^/]+)\/agents\/(squad|orache|genome|profiler-researcher|profiler-enricher|profiler-forge
|
|
31
|
+
const SQUAD_LOCALE_AGENT_RE = /^\.aioson\/locales\/([^/]+)\/agents\/(squad|orache|genome|profiler-researcher|profiler-enricher|profiler-forge)\.md$/;
|
|
32
32
|
|
|
33
33
|
// Design skill IDs disponíveis
|
|
34
34
|
const DESIGN_IDS = [
|
package/src/install-wizard.js
CHANGED
|
@@ -118,7 +118,7 @@ function renderScreen1(cursor, selected, warn, stdout) {
|
|
|
118
118
|
stdout.write('\n');
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
function renderScreen2(cursor, selected, stdout) {
|
|
121
|
+
function renderScreen2(cursor, selected, warn, stdout) {
|
|
122
122
|
header(2, 4, stdout);
|
|
123
123
|
stdout.write(' What will you do with AIOSON?\n');
|
|
124
124
|
stdout.write(' (space to select, enter to continue)\n\n');
|
|
@@ -130,6 +130,7 @@ function renderScreen2(cursor, selected, stdout) {
|
|
|
130
130
|
stdout.write(` ${pointer} [${check}] ${use.label}${lock}\n`);
|
|
131
131
|
stdout.write(` ${use.desc}\n`);
|
|
132
132
|
}
|
|
133
|
+
if (warn) stdout.write('\n ⚠ Select at least one use to continue.\n');
|
|
133
134
|
stdout.write('\n');
|
|
134
135
|
}
|
|
135
136
|
|
|
@@ -413,7 +414,7 @@ async function runInstallWizard(options = {}, io = {}) {
|
|
|
413
414
|
items: USES,
|
|
414
415
|
defaultSelected: defaultUses,
|
|
415
416
|
lockFirst: true,
|
|
416
|
-
render: (cursor, selected,
|
|
417
|
+
render: (cursor, selected, warn, out) => renderScreen2(cursor, selected, warn, out),
|
|
417
418
|
io
|
|
418
419
|
});
|
|
419
420
|
if (!uses) { finalCleanup(); return null; }
|
package/src/installer.js
CHANGED
|
@@ -186,6 +186,7 @@ async function installTemplate(targetDir, options = {}) {
|
|
|
186
186
|
backupOnOverwrite = mode === 'update',
|
|
187
187
|
frameworkDetection = null,
|
|
188
188
|
installProfile = null,
|
|
189
|
+
selectiveUpdate = false,
|
|
189
190
|
onProgress = null
|
|
190
191
|
} = options;
|
|
191
192
|
|
|
@@ -219,6 +220,11 @@ async function installTemplate(targetDir, options = {}) {
|
|
|
219
220
|
continue;
|
|
220
221
|
}
|
|
221
222
|
|
|
223
|
+
if (!destExists && selectiveUpdate) {
|
|
224
|
+
skipped.push({ path: rel, reason: 'not-installed' });
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
|
|
222
228
|
if (destExists && !overwrite && mode !== 'update') {
|
|
223
229
|
skipped.push({ path: rel, reason: 'already-exists' });
|
|
224
230
|
continue;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Ambient Intelligence Health Check — Phase 5.3
|
|
5
|
+
*
|
|
6
|
+
* Aggregates state from multiple SQLite tables and file-system checks
|
|
7
|
+
* to produce a list of items awaiting attention.
|
|
8
|
+
*
|
|
9
|
+
* Used by:
|
|
10
|
+
* - live:start → shows alert at session start
|
|
11
|
+
* - daemon:start → triggers automatic actions in the background loop
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const fs = require('node:fs/promises');
|
|
15
|
+
const path = require('node:path');
|
|
16
|
+
const { openRuntimeDb } = require('../runtime-store');
|
|
17
|
+
|
|
18
|
+
const MIN_LEARNINGS_FOR_EVOLVE = 5;
|
|
19
|
+
const MIN_LEARNING_FREQUENCY = 2;
|
|
20
|
+
const SQUAD_INACTIVE_DAYS = 30;
|
|
21
|
+
const TOOL_UNUSED_DAYS = 60;
|
|
22
|
+
const EVENT_STALE_HOURS = 24;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Run all health checks and return a list of items.
|
|
26
|
+
*
|
|
27
|
+
* @param {string} projectDir
|
|
28
|
+
* @returns {Promise<{ items: HealthItem[], ok: boolean }>}
|
|
29
|
+
*/
|
|
30
|
+
async function runHealthCheck(projectDir) {
|
|
31
|
+
const handle = await openRuntimeDb(projectDir, { mustExist: true });
|
|
32
|
+
if (!handle) return { items: [], ok: true };
|
|
33
|
+
const { db } = handle;
|
|
34
|
+
|
|
35
|
+
const items = [];
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
// ── Check 1: Learnings ready for evolve ────────────────────────────────
|
|
39
|
+
try {
|
|
40
|
+
const learnings = db.prepare(`
|
|
41
|
+
SELECT squad_slug, COUNT(*) as count
|
|
42
|
+
FROM squad_learnings
|
|
43
|
+
WHERE status = 'active' AND frequency >= ?
|
|
44
|
+
GROUP BY squad_slug
|
|
45
|
+
HAVING count >= ?
|
|
46
|
+
`).all(MIN_LEARNING_FREQUENCY, MIN_LEARNINGS_FOR_EVOLVE);
|
|
47
|
+
|
|
48
|
+
for (const row of learnings) {
|
|
49
|
+
items.push({
|
|
50
|
+
type: 'learnings_ready',
|
|
51
|
+
priority: 'high',
|
|
52
|
+
squad: row.squad_slug,
|
|
53
|
+
count: row.count,
|
|
54
|
+
message: `${row.count} learnings prontos para evoluir (squad: ${row.squad_slug})`,
|
|
55
|
+
action: `aioson learning:evolve . --squad=${row.squad_slug} --auto-apply`
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
} catch { /* table might not exist yet */ }
|
|
59
|
+
|
|
60
|
+
// ── Check 2: Inactive squads ───────────────────────────────────────────
|
|
61
|
+
try {
|
|
62
|
+
const inactive = db.prepare(`
|
|
63
|
+
SELECT squad_slug, updated_at
|
|
64
|
+
FROM squads
|
|
65
|
+
WHERE status = 'active'
|
|
66
|
+
AND updated_at < datetime('now', '-${SQUAD_INACTIVE_DAYS} days')
|
|
67
|
+
`).all();
|
|
68
|
+
|
|
69
|
+
for (const row of inactive) {
|
|
70
|
+
const daysSince = Math.round((Date.now() - new Date(row.updated_at).getTime()) / 86400000);
|
|
71
|
+
items.push({
|
|
72
|
+
type: 'squad_inactive',
|
|
73
|
+
priority: 'low',
|
|
74
|
+
squad: row.squad_slug,
|
|
75
|
+
days: daysSince,
|
|
76
|
+
message: `Squad "${row.squad_slug}" inativo há ${daysSince} dias`,
|
|
77
|
+
action: null
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
} catch { /* ok */ }
|
|
81
|
+
|
|
82
|
+
// ── Check 3: Stale inter-squad events ─────────────────────────────────
|
|
83
|
+
try {
|
|
84
|
+
const stale = db.prepare(`
|
|
85
|
+
SELECT id, from_squad, event, created_at
|
|
86
|
+
FROM inter_squad_events
|
|
87
|
+
WHERE datetime(created_at, '+${EVENT_STALE_HOURS} hours') < datetime('now')
|
|
88
|
+
AND consumed_by = '[]'
|
|
89
|
+
`).all();
|
|
90
|
+
|
|
91
|
+
if (stale.length > 0) {
|
|
92
|
+
items.push({
|
|
93
|
+
type: 'stale_events',
|
|
94
|
+
priority: 'medium',
|
|
95
|
+
count: stale.length,
|
|
96
|
+
message: `${stale.length} evento(s) inter-squad pendentes há mais de ${EVENT_STALE_HOURS}h sem consumidor`,
|
|
97
|
+
action: null
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
} catch { /* ok */ }
|
|
101
|
+
|
|
102
|
+
// ── Check 4: Dynamic tools unused for a long time ─────────────────────
|
|
103
|
+
try {
|
|
104
|
+
const unusedTools = db.prepare(`
|
|
105
|
+
SELECT t.name, t.squad_slug, t.registered_at
|
|
106
|
+
FROM dynamic_squad_tools t
|
|
107
|
+
WHERE t.registered_at < datetime('now', '-${TOOL_UNUSED_DAYS} days')
|
|
108
|
+
`).all();
|
|
109
|
+
|
|
110
|
+
if (unusedTools.length > 0) {
|
|
111
|
+
items.push({
|
|
112
|
+
type: 'unused_tools',
|
|
113
|
+
priority: 'low',
|
|
114
|
+
count: unusedTools.length,
|
|
115
|
+
message: `${unusedTools.length} tool(s) dinâmico(s) sem uso há mais de ${TOOL_UNUSED_DAYS} dias`,
|
|
116
|
+
action: `aioson squad:tool:register . --list --squad=<slug>`
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
} catch { /* ok */ }
|
|
120
|
+
} finally {
|
|
121
|
+
db.close();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return { items, ok: true };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Format health items for display in terminal (live:start alert).
|
|
129
|
+
*
|
|
130
|
+
* @param {HealthItem[]} items
|
|
131
|
+
* @returns {string|null} Formatted alert string, or null if nothing to report
|
|
132
|
+
*/
|
|
133
|
+
function formatHealthAlert(items) {
|
|
134
|
+
if (items.length === 0) return null;
|
|
135
|
+
|
|
136
|
+
const high = items.filter((i) => i.priority === 'high');
|
|
137
|
+
const medium = items.filter((i) => i.priority === 'medium');
|
|
138
|
+
const low = items.filter((i) => i.priority === 'low');
|
|
139
|
+
|
|
140
|
+
const lines = [
|
|
141
|
+
`AIOSON — ${items.length} item(s) aguardam atenção:`
|
|
142
|
+
];
|
|
143
|
+
|
|
144
|
+
for (const item of high) {
|
|
145
|
+
lines.push(` ● ${item.message}`);
|
|
146
|
+
if (item.action) lines.push(` → ${item.action}`);
|
|
147
|
+
}
|
|
148
|
+
for (const item of medium) {
|
|
149
|
+
lines.push(` ◐ ${item.message}`);
|
|
150
|
+
}
|
|
151
|
+
for (const item of low) {
|
|
152
|
+
lines.push(` ○ ${item.message}`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return lines.join('\n');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
module.exports = { runHealthCheck, formatHealthAlert };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Hook Exit Code Protocol
|
|
5
|
+
*
|
|
6
|
+
* Standardized exit codes for AIOSON hook scripts:
|
|
7
|
+
* HOOK_ALLOW (0): Allow the operation — continue normally
|
|
8
|
+
* HOOK_DENY (2): Deny the operation — abort with error message from stderr
|
|
9
|
+
* Any other: Warn — log stderr, continue (non-fatal)
|
|
10
|
+
*
|
|
11
|
+
* Used by squad:autorun to run `hooks.pre_run` scripts declared in squad manifests.
|
|
12
|
+
* Allows squads to gate their own execution based on inter-squad state.
|
|
13
|
+
*
|
|
14
|
+
* Example manifest:
|
|
15
|
+
* "hooks": {
|
|
16
|
+
* "pre_run": "sh .aioson/squads/distribution-team/hooks/check-content-ready.sh"
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* Example hook script (exits 2 to deny):
|
|
20
|
+
* #!/bin/sh
|
|
21
|
+
* STATUS=$(aioson squad:status . --squad=content-team --json | jq -r '.status')
|
|
22
|
+
* [ "$STATUS" = "active" ] && exit 0
|
|
23
|
+
* echo "content-team not ready (status: $STATUS)" >&2
|
|
24
|
+
* exit 2
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
const { spawnSync } = require('node:child_process');
|
|
28
|
+
|
|
29
|
+
const HOOK_ALLOW = 0;
|
|
30
|
+
const HOOK_DENY = 2;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Run a hook script and interpret its exit code.
|
|
34
|
+
*
|
|
35
|
+
* @param {string} script Shell command to execute (via `sh -c`)
|
|
36
|
+
* @param {object} context Key-value pairs passed as uppercase env vars to the script
|
|
37
|
+
* @param {object} opts Options: { timeoutMs }
|
|
38
|
+
*
|
|
39
|
+
* @returns {{ allowed: boolean, denied: boolean, exitCode: number, stdout: string, stderr: string, warn?: boolean }}
|
|
40
|
+
*/
|
|
41
|
+
function runHook(script, context = {}, opts = {}) {
|
|
42
|
+
const timeoutMs = opts.timeoutMs || 10_000;
|
|
43
|
+
|
|
44
|
+
const env = {
|
|
45
|
+
...process.env,
|
|
46
|
+
...Object.fromEntries(
|
|
47
|
+
Object.entries(context).map(([k, v]) => [
|
|
48
|
+
'AIOSON_' + k.toUpperCase().replace(/[^A-Z0-9]/g, '_'),
|
|
49
|
+
String(v)
|
|
50
|
+
])
|
|
51
|
+
)
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const result = spawnSync('sh', ['-c', script], {
|
|
55
|
+
env,
|
|
56
|
+
timeout: timeoutMs,
|
|
57
|
+
encoding: 'utf8',
|
|
58
|
+
stdio: 'pipe'
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const exitCode = result.status ?? 1;
|
|
62
|
+
const stdout = (result.stdout || '').trim();
|
|
63
|
+
const stderr = (result.stderr || '').trim();
|
|
64
|
+
|
|
65
|
+
if (exitCode === HOOK_DENY) {
|
|
66
|
+
return { allowed: false, denied: true, exitCode, stdout, stderr };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (exitCode !== HOOK_ALLOW) {
|
|
70
|
+
return { allowed: true, denied: false, exitCode, stdout, stderr, warn: true };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return { allowed: true, denied: false, exitCode, stdout, stderr };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports = { HOOK_ALLOW, HOOK_DENY, runHook };
|