conectese 0.1.14
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/README.md +265 -0
- package/_conectese/.conectese-version +1 -0
- package/_conectese/config/playwright.config.json +11 -0
- package/_conectese/core/architect.agent.yaml +110 -0
- package/_conectese/core/best-practices/_catalog.yaml +116 -0
- package/_conectese/core/best-practices/blog-post.md +132 -0
- package/_conectese/core/best-practices/blog-seo.md +127 -0
- package/_conectese/core/best-practices/copywriting.md +426 -0
- package/_conectese/core/best-practices/data-analysis.md +401 -0
- package/_conectese/core/best-practices/email-newsletter.md +118 -0
- package/_conectese/core/best-practices/email-sales.md +110 -0
- package/_conectese/core/best-practices/image-design.md +348 -0
- package/_conectese/core/best-practices/instagram-feed.md +235 -0
- package/_conectese/core/best-practices/instagram-reels.md +112 -0
- package/_conectese/core/best-practices/instagram-stories.md +107 -0
- package/_conectese/core/best-practices/linkedin-article.md +116 -0
- package/_conectese/core/best-practices/linkedin-post.md +121 -0
- package/_conectese/core/best-practices/researching.md +349 -0
- package/_conectese/core/best-practices/review.md +269 -0
- package/_conectese/core/best-practices/social-networks-publishing.md +294 -0
- package/_conectese/core/best-practices/strategist.md +344 -0
- package/_conectese/core/best-practices/technical-writing.md +365 -0
- package/_conectese/core/best-practices/twitter-post.md +105 -0
- package/_conectese/core/best-practices/twitter-thread.md +122 -0
- package/_conectese/core/best-practices/whatsapp-broadcast.md +107 -0
- package/_conectese/core/best-practices/youtube-script.md +122 -0
- package/_conectese/core/best-practices/youtube-shorts.md +112 -0
- package/_conectese/core/prompts/build.prompt.md +547 -0
- package/_conectese/core/prompts/design.prompt.md +469 -0
- package/_conectese/core/prompts/discovery.prompt.md +269 -0
- package/_conectese/core/prompts/sherlock-instagram.md +123 -0
- package/_conectese/core/prompts/sherlock-linkedin.md +73 -0
- package/_conectese/core/prompts/sherlock-shared.md +684 -0
- package/_conectese/core/prompts/sherlock-twitter.md +78 -0
- package/_conectese/core/prompts/sherlock-youtube.md +85 -0
- package/_conectese/core/runner.pipeline.md +535 -0
- package/_conectese/core/skills.engine.md +381 -0
- package/agents/data-extractor/AGENT.md +13 -0
- package/agents/direito-adaneiro/AGENT.md +18 -0
- package/agents/direito-administrativo/AGENT.md +18 -0
- package/agents/direito-aeroporta-rio/AGENT.md +18 -0
- package/agents/direito-agra-rio/AGENT.md +18 -0
- package/agents/direito-ambiental/AGENT.md +18 -0
- package/agents/direito-banca-rio/AGENT.md +18 -0
- package/agents/direito-civil/AGENT.md +18 -0
- package/agents/direito-constitcional/AGENT.md +18 -0
- package/agents/direito-da-crianc-a-e-do-adolescente-eca/AGENT.md +18 -0
- package/agents/direito-da-propriedade-intelectal/AGENT.md +18 -0
- package/agents/direito-de-ami-lia/AGENT.md +18 -0
- package/agents/direito-de-tra-nsito/AGENT.md +18 -0
- package/agents/direito-desportivo/AGENT.md +18 -0
- package/agents/direito-digital/AGENT.md +18 -0
- package/agents/direito-do-consmidor/AGENT.md +18 -0
- package/agents/direito-do-trabalho/AGENT.md +18 -0
- package/agents/direito-econo-mico/AGENT.md +18 -0
- package/agents/direito-eleitoral/AGENT.md +18 -0
- package/agents/direito-empresarial/AGENT.md +18 -0
- package/agents/direito-imobilia-rio/AGENT.md +18 -0
- package/agents/direito-inanceiro/AGENT.md +18 -0
- package/agents/direito-internacional/AGENT.md +18 -0
- package/agents/direito-mari-timo/AGENT.md +18 -0
- package/agents/direito-me-dico-e-da-sa-de/AGENT.md +18 -0
- package/agents/direito-militar/AGENT.md +18 -0
- package/agents/direito-ndia-rio/AGENT.md +18 -0
- package/agents/direito-notarial-e-registral/AGENT.md +18 -0
- package/agents/direito-penal/AGENT.md +18 -0
- package/agents/direito-previdencia-rio/AGENT.md +18 -0
- package/agents/direito-processal-civil/AGENT.md +18 -0
- package/agents/direito-processal-do-trabalho/AGENT.md +18 -0
- package/agents/direito-processal-militar/AGENT.md +18 -0
- package/agents/direito-processal-penal/AGENT.md +18 -0
- package/agents/direito-rbani-stico/AGENT.md +18 -0
- package/agents/direito-secrita-rio/AGENT.md +18 -0
- package/agents/direito-sindical/AGENT.md +18 -0
- package/agents/direito-societa-rio/AGENT.md +18 -0
- package/agents/direito-tribta-rio/AGENT.md +18 -0
- package/agents/direitos-hmanos/AGENT.md +18 -0
- package/agents/legal-analyst/AGENT.md +16 -0
- package/agents/legal-synthesizer/AGENT.md +13 -0
- package/agents/lgpd-anonymizer/AGENT.md +14 -0
- package/agents/lgpd-restorer/AGENT.md +14 -0
- package/agents/task-router/AGENT.md +13 -0
- package/bin/conectese.js +73 -0
- package/dashboard/index.html +12 -0
- package/dashboard/package-lock.json +1971 -0
- package/dashboard/package.json +28 -0
- package/dashboard/public/assets/avatars/Female1_1wave.png +0 -0
- package/dashboard/public/assets/avatars/Female1_2wave.png +0 -0
- package/dashboard/public/assets/avatars/Female1_blink.png +0 -0
- package/dashboard/public/assets/avatars/Female1_talk.png +0 -0
- package/dashboard/public/assets/avatars/Female2_1wave.png +0 -0
- package/dashboard/public/assets/avatars/Female2_2wave.png +0 -0
- package/dashboard/public/assets/avatars/Female2_blink.png +0 -0
- package/dashboard/public/assets/avatars/Female2_talk.png +0 -0
- package/dashboard/public/assets/avatars/Female3_blink.png +0 -0
- package/dashboard/public/assets/avatars/Female3_talk.png +0 -0
- package/dashboard/public/assets/avatars/Female3_wave.png +0 -0
- package/dashboard/public/assets/avatars/Female4_blink.png +0 -0
- package/dashboard/public/assets/avatars/Female4_talk.png +0 -0
- package/dashboard/public/assets/avatars/Female4_wave.png +0 -0
- package/dashboard/public/assets/avatars/Female5_blink.png +0 -0
- package/dashboard/public/assets/avatars/Female5_talk.png +0 -0
- package/dashboard/public/assets/avatars/Female5_wave.png +0 -0
- package/dashboard/public/assets/avatars/Female6_blink.png +0 -0
- package/dashboard/public/assets/avatars/Female6_talk.png +0 -0
- package/dashboard/public/assets/avatars/Female6_wave.png +0 -0
- package/dashboard/public/assets/avatars/Male1_1wave.png +0 -0
- package/dashboard/public/assets/avatars/Male1_2wave.png +0 -0
- package/dashboard/public/assets/avatars/Male1_blink.png +0 -0
- package/dashboard/public/assets/avatars/Male1_talk.png +0 -0
- package/dashboard/public/assets/avatars/Male2_1wave.png +0 -0
- package/dashboard/public/assets/avatars/Male2_2wave.png +0 -0
- package/dashboard/public/assets/avatars/Male2_blink.png +0 -0
- package/dashboard/public/assets/avatars/Male2_talk.png +0 -0
- package/dashboard/public/assets/avatars/Male3_blink.png +0 -0
- package/dashboard/public/assets/avatars/Male3_talk.png +0 -0
- package/dashboard/public/assets/avatars/Male3_wave.png +0 -0
- package/dashboard/public/assets/avatars/Male4_blink.png +0 -0
- package/dashboard/public/assets/avatars/Male4_talk.png +0 -0
- package/dashboard/public/assets/avatars/Male4_wave.png +0 -0
- package/dashboard/public/assets/desks/desktop_set_black_down.png +0 -0
- package/dashboard/public/assets/desks/desktop_set_black_down_coding-1.png +0 -0
- package/dashboard/public/assets/desks/desktop_set_black_down_coding.png +0 -0
- package/dashboard/public/assets/desks/desktop_set_black_up.png +0 -0
- package/dashboard/public/assets/desks/desktop_set_white_down.png +0 -0
- package/dashboard/public/assets/desks/desktop_set_white_down_coding-1.png +0 -0
- package/dashboard/public/assets/desks/desktop_set_white_down_coding.png +0 -0
- package/dashboard/public/assets/desks/desktop_set_white_up.png +0 -0
- package/dashboard/public/assets/furniture/armchair_tan.png +0 -0
- package/dashboard/public/assets/furniture/armchair_tan_down.png +0 -0
- package/dashboard/public/assets/furniture/backpack_blue.png +0 -0
- package/dashboard/public/assets/furniture/backpack_red.png +0 -0
- package/dashboard/public/assets/furniture/blinds.png +0 -0
- package/dashboard/public/assets/furniture/blinds_large_closed_white.png +0 -0
- package/dashboard/public/assets/furniture/bookshelf.png +0 -0
- package/dashboard/public/assets/furniture/bookshelf_purple_tall.png +0 -0
- package/dashboard/public/assets/furniture/bulletin_board.png +0 -0
- package/dashboard/public/assets/furniture/clock.png +0 -0
- package/dashboard/public/assets/furniture/coffee_mug.png +0 -0
- package/dashboard/public/assets/furniture/coffee_mug_blue.png +0 -0
- package/dashboard/public/assets/furniture/coffee_table.png +0 -0
- package/dashboard/public/assets/furniture/coffeepot_right.png +0 -0
- package/dashboard/public/assets/furniture/coffeetable_black_horizontal.png +0 -0
- package/dashboard/public/assets/furniture/couch.png +0 -0
- package/dashboard/public/assets/furniture/couch_tan_down.png +0 -0
- package/dashboard/public/assets/furniture/cushion_blue.png +0 -0
- package/dashboard/public/assets/furniture/cushion_tan.png +0 -0
- package/dashboard/public/assets/furniture/desk_wood.png +0 -0
- package/dashboard/public/assets/furniture/fancy_rug.png +0 -0
- package/dashboard/public/assets/furniture/fancy_rug_wide.png +0 -0
- package/dashboard/public/assets/furniture/flowers1.png +0 -0
- package/dashboard/public/assets/furniture/flowers2.png +0 -0
- package/dashboard/public/assets/furniture/lamp_tan.png +0 -0
- package/dashboard/public/assets/furniture/lantern.png +0 -0
- package/dashboard/public/assets/furniture/monstera.png +0 -0
- package/dashboard/public/assets/furniture/monstera_small.png +0 -0
- package/dashboard/public/assets/furniture/picture_frame.png +0 -0
- package/dashboard/public/assets/furniture/plant1.png +0 -0
- package/dashboard/public/assets/furniture/plant2.png +0 -0
- package/dashboard/public/assets/furniture/plant3.png +0 -0
- package/dashboard/public/assets/furniture/plant_poof.png +0 -0
- package/dashboard/public/assets/furniture/plant_spindly.png +0 -0
- package/dashboard/public/assets/furniture/poster_blue.png +0 -0
- package/dashboard/public/assets/furniture/rug.png +0 -0
- package/dashboard/public/assets/furniture/succulent_blue.png +0 -0
- package/dashboard/public/assets/furniture/succulent_green.png +0 -0
- package/dashboard/public/assets/furniture/treasurechest_closed_gold.png +0 -0
- package/dashboard/public/assets/furniture/water_cooler_better.png +0 -0
- package/dashboard/public/assets/furniture/whiteboard.png +0 -0
- package/dashboard/public/assets/furniture/whiteboard_stand_graph.png +0 -0
- package/dashboard/public/assets/furniture/window_blinds_open.png +0 -0
- package/dashboard/src/App.tsx +46 -0
- package/dashboard/src/components/SquadCard.tsx +47 -0
- package/dashboard/src/components/SquadSelector.tsx +61 -0
- package/dashboard/src/components/StatusBadge.tsx +32 -0
- package/dashboard/src/components/StatusBar.tsx +97 -0
- package/dashboard/src/hooks/useSquadSocket.ts +135 -0
- package/dashboard/src/lib/formatTime.ts +16 -0
- package/dashboard/src/lib/normalizeState.ts +25 -0
- package/dashboard/src/main.tsx +10 -0
- package/dashboard/src/office/AgentSprite.ts +241 -0
- package/dashboard/src/office/OfficeScene.ts +153 -0
- package/dashboard/src/office/PhaserGame.tsx +80 -0
- package/dashboard/src/office/RoomBuilder.ts +190 -0
- package/dashboard/src/office/assetKeys.ts +150 -0
- package/dashboard/src/office/palette.ts +32 -0
- package/dashboard/src/plugin/squadWatcher.ts +233 -0
- package/dashboard/src/store/useSquadStore.ts +56 -0
- package/dashboard/src/styles/globals.css +36 -0
- package/dashboard/src/types/state.ts +63 -0
- package/dashboard/src/vite-env.d.ts +1 -0
- package/dashboard/test-results/.last-run.json +4 -0
- package/dashboard/tsconfig.json +24 -0
- package/dashboard/tsconfig.tsbuildinfo +1 -0
- package/dashboard/vite.config.ts +13 -0
- package/package.json +53 -0
- package/skills/README.md +63 -0
- package/skills/apify/SKILL.md +55 -0
- package/skills/blotato/SKILL.md +63 -0
- package/skills/canva/SKILL.md +60 -0
- package/skills/conectese-agent-creator/SKILL.md +192 -0
- package/skills/conectese-skill-creator/SKILL.md +407 -0
- package/skills/conectese-skill-creator/agents/analyzer.md +274 -0
- package/skills/conectese-skill-creator/agents/comparator.md +202 -0
- package/skills/conectese-skill-creator/agents/grader.md +223 -0
- package/skills/conectese-skill-creator/assets/eval_review.html +146 -0
- package/skills/conectese-skill-creator/eval-viewer/generate_review.py +471 -0
- package/skills/conectese-skill-creator/eval-viewer/viewer.html +1325 -0
- package/skills/conectese-skill-creator/references/schemas.md +430 -0
- package/skills/conectese-skill-creator/references/skill-format.md +235 -0
- package/skills/conectese-skill-creator/scripts/__init__.py +0 -0
- package/skills/conectese-skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/skills/conectese-skill-creator/scripts/quick_validate.py +103 -0
- package/skills/conectese-skill-creator/scripts/run_eval.py +310 -0
- package/skills/conectese-skill-creator/scripts/utils.py +47 -0
- package/skills/image-ai-generator/SKILL.md +124 -0
- package/skills/image-ai-generator/scripts/generate.py +175 -0
- package/skills/image-creator/SKILL.md +155 -0
- package/skills/image-fetcher/SKILL.md +91 -0
- package/skills/instagram-publisher/SKILL.md +119 -0
- package/skills/instagram-publisher/scripts/publish.js +165 -0
- package/skills/resend/SKILL.md +80 -0
- package/skills/template-designer/SKILL.md +201 -0
- package/skills/template-designer/base-templates/model-a.html +27 -0
- package/skills/template-designer/base-templates/model-b.html +31 -0
- package/skills/template-designer/base-templates/model-c.html +42 -0
- package/src/agents-cli.js +158 -0
- package/src/agents.js +134 -0
- package/src/i18n.js +48 -0
- package/src/init.js +341 -0
- package/src/locales/en.json +73 -0
- package/src/locales/es.json +72 -0
- package/src/locales/pt-BR.json +72 -0
- package/src/logger.js +38 -0
- package/src/prompt.js +46 -0
- package/src/readme/README.md +119 -0
- package/src/runs.js +90 -0
- package/src/skills-cli.js +157 -0
- package/src/skills.js +146 -0
- package/src/update.js +169 -0
- package/templates/_conectese/.conectese-version +1 -0
- package/templates/_conectese/_investigations/.gitkeep +0 -0
- package/templates/ide-templates/antigravity/.agent/rules/conectese.md +55 -0
- package/templates/ide-templates/antigravity/.agent/workflows/conectese.md +102 -0
- package/templates/ide-templates/claude-code/.claude/skills/conectese/SKILL.md +182 -0
- package/templates/ide-templates/claude-code/.mcp.json +8 -0
- package/templates/ide-templates/claude-code/CLAUDE.md +43 -0
- package/templates/ide-templates/codex/.agents/skills/conectese/SKILL.md +6 -0
- package/templates/ide-templates/codex/AGENTS.md +105 -0
- package/templates/ide-templates/cursor/.cursor/commands/conectese.md +9 -0
- package/templates/ide-templates/cursor/.cursor/mcp.json +8 -0
- package/templates/ide-templates/cursor/.cursor/rules/conectese.mdc +48 -0
- package/templates/ide-templates/cursor/.cursorignore +3 -0
- package/templates/ide-templates/opencode/.opencode/commands/conectese.md +9 -0
- package/templates/ide-templates/opencode/AGENTS.md +105 -0
- package/templates/ide-templates/vscode-copilot/.github/prompts/conectese.prompt.md +201 -0
- package/templates/ide-templates/vscode-copilot/.vscode/mcp.json +8 -0
- package/templates/ide-templates/vscode-copilot/.vscode/settings.json +3 -0
- package/templates/package.json +8 -0
- package/templates/squads/.gitkeep +0 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: template-designer
|
|
3
|
+
description: Visual template selection for image design agents. Generates template variations, renders them as images for user review, and saves the approved visual identity.
|
|
4
|
+
type: prompt
|
|
5
|
+
version: "2.0.0"
|
|
6
|
+
categories: [design, visual, templates]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Template Designer
|
|
10
|
+
|
|
11
|
+
Visual template selection and refinement for squad creation and editing.
|
|
12
|
+
|
|
13
|
+
## When to Use
|
|
14
|
+
|
|
15
|
+
- During squad creation: when the Design phase identifies an image design agent and the user opts to choose a template
|
|
16
|
+
- During squad editing: when the user asks to define, edit, or change the visual identity / template of a design agent
|
|
17
|
+
- Trigger: presence of `image-creator` skill (or similar image-producing skill) in the squad's skill list
|
|
18
|
+
|
|
19
|
+
## Prerequisites
|
|
20
|
+
|
|
21
|
+
- A squad with a design agent that produces images (uses `image-creator` skill)
|
|
22
|
+
- Squad's `_build/` directory must exist (created during Discovery/Design phases)
|
|
23
|
+
- `image-creator` skill installed (for rendering HTML to PNG)
|
|
24
|
+
|
|
25
|
+
## How It Works
|
|
26
|
+
|
|
27
|
+
1. You read context and base templates
|
|
28
|
+
2. You generate 3 adapted HTML template variations
|
|
29
|
+
3. You render each as a PNG image using the `image-creator` skill
|
|
30
|
+
4. You present the image file paths to the user for review
|
|
31
|
+
5. You iterate with feedback until approval
|
|
32
|
+
6. You save the approved template as HTML reference + structured style rules
|
|
33
|
+
|
|
34
|
+
## Generating Templates
|
|
35
|
+
|
|
36
|
+
### Step 0: Read Design Guidelines (MANDATORY)
|
|
37
|
+
|
|
38
|
+
Before generating any template, read and internalize the design best practices:
|
|
39
|
+
- `_conectese/core/best-practices/image-design.md` — **REQUIRED reading**. Contains platform-specific minimum font sizes, typography rules, spacing guidelines, color palette constraints, contrast requirements, and layout methodology. Every template you generate MUST comply with these rules.
|
|
40
|
+
|
|
41
|
+
Key rules to always follow:
|
|
42
|
+
- **Font sizes**: Hero 58px, Heading 43px, Body 34px, Caption 24px minimum for Instagram carousel (1080x1440). Absolute minimum 20px for any readable text on any platform.
|
|
43
|
+
- **Font weight**: 500 or higher for body text and above.
|
|
44
|
+
- **Colors**: Maximum 5 colors per design system (primary, secondary, accent, background, text).
|
|
45
|
+
- **Contrast**: WCAG AA minimum 4.5:1 for all text against background.
|
|
46
|
+
- **Layout**: CSS Grid or Flexbox only. No absolute positioning for primary content.
|
|
47
|
+
- **Self-contained HTML**: Inline CSS only. Only Google Fonts @import allowed as external resource.
|
|
48
|
+
- **No slide counters**: Never include "1/7" or similar. Instagram has native navigation.
|
|
49
|
+
|
|
50
|
+
You should also apply general web design best practices: proper white space, visual hierarchy through scale and weight, consistent spacing rhythm, and balanced composition.
|
|
51
|
+
|
|
52
|
+
### HARD RULES — Dimensions and Typography
|
|
53
|
+
|
|
54
|
+
These rules are NON-NEGOTIABLE. Every template must comply:
|
|
55
|
+
|
|
56
|
+
**Fixed Dimensions (never use height: auto or flexible height):**
|
|
57
|
+
- Instagram Carousel: `width: 1080px; height: 1440px` (3:4 portrait)
|
|
58
|
+
- Instagram Story/Reel: `width: 1080px; height: 1920px` (9:16 portrait)
|
|
59
|
+
- Instagram Post: `width: 1080px; height: 1080px` (1:1 square)
|
|
60
|
+
- LinkedIn Post: `width: 1200px; height: 627px` (1.91:1 horizontal)
|
|
61
|
+
|
|
62
|
+
The root container of every template MUST set explicit `width` and `height` in pixels. The template must render at exactly these dimensions — no overflow, no scrolling, no flexible height.
|
|
63
|
+
|
|
64
|
+
**Minimum Font Sizes (Instagram at 1080px width):**
|
|
65
|
+
- Hero/Title: **58px** minimum
|
|
66
|
+
- Heading: **43px** minimum
|
|
67
|
+
- Body text: **34px** minimum
|
|
68
|
+
- Caption/small text: **24px** minimum
|
|
69
|
+
- Absolute minimum for ANY readable text on ANY platform: **20px**
|
|
70
|
+
|
|
71
|
+
**Font Weight:** 500 or higher for body text and above. Never use font-weight below 400 for any visible text.
|
|
72
|
+
|
|
73
|
+
Templates that violate these rules are rejected — no exceptions.
|
|
74
|
+
|
|
75
|
+
### Step 1: Read Context
|
|
76
|
+
|
|
77
|
+
Read these files to understand the squad:
|
|
78
|
+
- `squads/{code}/_build/discovery.yaml` — platform, domain, tone, language
|
|
79
|
+
- `squads/{code}/_build/design.yaml` — agents, purpose, skills
|
|
80
|
+
- `squads/{code}/_investigations/consolidated-analysis.md` (if exists) — visual patterns from reference profiles
|
|
81
|
+
- `_conectese/_memory/company.md` — company name, brand, industry, target audience
|
|
82
|
+
- `_conectese/_memory/preferences.md` — user preferences (language, style, tone)
|
|
83
|
+
|
|
84
|
+
Use the company context and user preferences to adapt template content: example text should reflect the company's domain and audience, colors should align with brand if available, and language should match the user's Output Language preference.
|
|
85
|
+
|
|
86
|
+
### Step 2: Read Base Templates
|
|
87
|
+
|
|
88
|
+
Read the 3 base templates from `skills/template-designer/base-templates/`:
|
|
89
|
+
- `model-a.html`
|
|
90
|
+
- `model-b.html`
|
|
91
|
+
- `model-c.html`
|
|
92
|
+
|
|
93
|
+
### Step 3: Generate Adapted Variations
|
|
94
|
+
|
|
95
|
+
For each base template, create an adapted version:
|
|
96
|
+
- Adjust colors to match the squad's domain/brand (use Sherlock palette if available, company brand colors from company.md if available)
|
|
97
|
+
- Adjust typography following the platform-specific minimum font sizes from `image-design.md`
|
|
98
|
+
- Replace example content with domain-relevant content that reflects the company's industry, audience, and language
|
|
99
|
+
- Set the root container to the exact fixed dimensions from HARD RULES above. Never use percentage heights or auto heights.
|
|
100
|
+
- Add any visual elements that match the squad's personality
|
|
101
|
+
- Apply proper white space, visual hierarchy, and spacing rhythm per `image-design.md` methodology
|
|
102
|
+
|
|
103
|
+
Write each adapted template as a **complete, self-contained HTML file** (with `<!DOCTYPE html>`, inline CSS, and Google Fonts imports if needed).
|
|
104
|
+
|
|
105
|
+
Save to:
|
|
106
|
+
- `squads/{code}/_build/template-a.html`
|
|
107
|
+
- `squads/{code}/_build/template-b.html`
|
|
108
|
+
- `squads/{code}/_build/template-c.html`
|
|
109
|
+
|
|
110
|
+
### Step 4: Render as Images
|
|
111
|
+
|
|
112
|
+
Use the `image-creator` skill to render each HTML template as a PNG image:
|
|
113
|
+
|
|
114
|
+
1. Read `skills/image-creator/SKILL.md` for rendering instructions
|
|
115
|
+
2. Render each template HTML to PNG using the image-creator workflow
|
|
116
|
+
3. Save rendered images to:
|
|
117
|
+
- `squads/{code}/_build/template-a.png`
|
|
118
|
+
- `squads/{code}/_build/template-b.png`
|
|
119
|
+
- `squads/{code}/_build/template-c.png`
|
|
120
|
+
|
|
121
|
+
### Step 5: Present to User
|
|
122
|
+
|
|
123
|
+
Present the 3 template options to the user using **clickable markdown links with absolute file paths** so they can open and review:
|
|
124
|
+
|
|
125
|
+
> "Here are 3 template options for your squad's visual identity:
|
|
126
|
+
>
|
|
127
|
+
> - [preview-a.png]({absolute_path}/squads/{code}/_build/template-a.png) — Template A
|
|
128
|
+
> - [preview-b.png]({absolute_path}/squads/{code}/_build/template-b.png) — Template B
|
|
129
|
+
> - [preview-c.png]({absolute_path}/squads/{code}/_build/template-c.png) — Template C
|
|
130
|
+
>
|
|
131
|
+
> Click the links above to open each image. Tell me which one you prefer. I can also mix elements from different templates or adjust colors, fonts, and layout."
|
|
132
|
+
|
|
133
|
+
**Important:** Always use the full absolute path (e.g., `d:\Coding Projects\conectese\squads\my-squad\_build\template-a.png`) inside the markdown link — relative paths are not clickable in the IDE.
|
|
134
|
+
|
|
135
|
+
## Iteration Loop
|
|
136
|
+
|
|
137
|
+
1. Present template images with clickable markdown links using absolute file paths
|
|
138
|
+
2. Wait for user feedback in terminal
|
|
139
|
+
3. Generate new version based on feedback — save as `template-v2.html`, render as `template-v2.png`, etc.
|
|
140
|
+
4. Present updated image with clickable markdown link using absolute file path
|
|
141
|
+
5. Repeat until user approves
|
|
142
|
+
|
|
143
|
+
## Saving the Approved Template
|
|
144
|
+
|
|
145
|
+
When the user approves, create two files:
|
|
146
|
+
|
|
147
|
+
### 1. Template Reference HTML
|
|
148
|
+
|
|
149
|
+
Save to: `squads/{code}/pipeline/data/template-reference.html`
|
|
150
|
+
|
|
151
|
+
The complete, self-contained HTML/CSS of the approved template at full resolution (e.g., 1080x1440). This is the literal example the design agent will use.
|
|
152
|
+
|
|
153
|
+
### 2. Visual Identity Rules
|
|
154
|
+
|
|
155
|
+
Save to: `squads/{code}/pipeline/data/visual-identity.md`
|
|
156
|
+
|
|
157
|
+
Extract structured rules from the approved template:
|
|
158
|
+
|
|
159
|
+
~~~markdown
|
|
160
|
+
# Visual Identity
|
|
161
|
+
|
|
162
|
+
## Color Palette
|
|
163
|
+
- **Primary:** #HEXCODE — usage description
|
|
164
|
+
- **Secondary:** #HEXCODE — usage description
|
|
165
|
+
- **Background:** #HEXCODE
|
|
166
|
+
- **Text:** #HEXCODE
|
|
167
|
+
- **Accent:** #HEXCODE — usage description
|
|
168
|
+
|
|
169
|
+
## Typography
|
|
170
|
+
- **Headings:** Font Family, weight, size range
|
|
171
|
+
- **Body:** Font Family, weight, size range
|
|
172
|
+
- **Caption:** Font Family, weight, size range
|
|
173
|
+
- **Minimum sizes:** body 32px, caption 24px, heading 48px
|
|
174
|
+
|
|
175
|
+
## Layout
|
|
176
|
+
- **Viewport:** WIDTHxHEIGHT px
|
|
177
|
+
- **Padding:** value
|
|
178
|
+
- **Grid:** description
|
|
179
|
+
- **Spacing rules:** description
|
|
180
|
+
|
|
181
|
+
## Composition Rules
|
|
182
|
+
- Logo/profile placement: description
|
|
183
|
+
- Image treatment: description
|
|
184
|
+
- Visual hierarchy: description
|
|
185
|
+
- Footer/CTA pattern: description
|
|
186
|
+
|
|
187
|
+
## Adaptation Rules
|
|
188
|
+
- How to handle different viewport sizes
|
|
189
|
+
- What stays fixed vs. what adapts
|
|
190
|
+
- Color usage rules (when to use primary vs accent)
|
|
191
|
+
~~~
|
|
192
|
+
|
|
193
|
+
### 3. Update Squad Files
|
|
194
|
+
|
|
195
|
+
If the squad is being created (Build phase hasn't run yet):
|
|
196
|
+
- The design.yaml context now includes the template data — Build will pick it up
|
|
197
|
+
|
|
198
|
+
If the squad already exists (editing flow):
|
|
199
|
+
- Add `pipeline/data/template-reference.html` and `pipeline/data/visual-identity.md` to `squad.yaml` `data:` list
|
|
200
|
+
- Update the design agent's `.agent.md` to reference both files
|
|
201
|
+
- Update the design agent's tasks to include the rule: "always follow visual-identity.md and use template-reference.html as the base model"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<!-- Model A: Twitter Editorial — approved 2026-03-28 -->
|
|
2
|
+
<!-- Style: Black background, tweet-style layout with avatar, verified badge, editorial text, contextual image -->
|
|
3
|
+
<!-- Fonts: Inter (body), weight 400-700 -->
|
|
4
|
+
<!-- Colors: #000 bg, #fff text, #1D9BF0 verified, #71767B muted, #2a2a2a borders/avatar, #1a1a2e image gradient -->
|
|
5
|
+
<div style="width:1080px;height:1440px;background:#000;color:#fff;font-family:'Inter',sans-serif;display:flex;flex-direction:column;padding:72px;gap:0;position:relative;overflow:hidden;">
|
|
6
|
+
<!-- Tweet header -->
|
|
7
|
+
<div style="display:flex;gap:24px;align-items:center;">
|
|
8
|
+
<div style="width:80px;height:80px;border-radius:50%;background:#2a2a2a;flex-shrink:0;"></div>
|
|
9
|
+
<div>
|
|
10
|
+
<div style="display:flex;align-items:center;gap:8px;">
|
|
11
|
+
<span style="font-weight:700;font-size:34px;">Nome Sobrenome</span>
|
|
12
|
+
<svg width="28" height="28" viewBox="0 0 24 24" fill="#1D9BF0"><path d="M22.25 12c0-1.43-.88-2.67-2.19-3.34.46-1.39.2-2.9-.81-3.91s-2.52-1.27-3.91-.81c-.66-1.31-1.91-2.19-3.34-2.19s-2.67.88-3.34 2.19c-1.39-.46-2.9-.2-3.91.81s-1.27 2.52-.81 3.91C2.63 9.33 1.75 10.57 1.75 12s.88 2.67 2.19 3.34c-.46 1.39-.2 2.9.81 3.91s2.52 1.27 3.91.81c.66 1.31 1.91 2.19 3.34 2.19s2.67-.88 3.34-2.19c1.39.46 2.9.2 3.91-.81s1.27-2.52.81-3.91c1.31-.67 2.19-1.91 2.19-3.34zm-11.08 4.71c-.22.22-.58.22-.8 0L7.4 13.74c-.22-.22-.22-.58 0-.8.22-.22.58-.22.8 0l2.57 2.57 6.03-6.03c.22-.22.58-.22.8 0 .22.22.22.58 0 .8l-6.43 6.43z"/></svg>
|
|
13
|
+
</div>
|
|
14
|
+
<span style="font-size:28px;color:#71767B;">@username</span>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
<!-- Tweet text -->
|
|
18
|
+
<div style="font-size:38px;line-height:1.45;font-weight:400;margin-top:48px;">
|
|
19
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium.
|
|
20
|
+
<br><br>
|
|
21
|
+
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit. Neque porro quisquam est qui dolorem.
|
|
22
|
+
</div>
|
|
23
|
+
<!-- Image -->
|
|
24
|
+
<div style="width:100%;height:35%;background:linear-gradient(180deg,#1a1a2e,#0d0d0d);border-radius:24px;display:flex;align-items:center;justify-content:center;border:1px solid #2a2a2a;flex-shrink:0;margin-top:auto;">
|
|
25
|
+
<span style="color:#555;font-size:34px;">Imagem contextual</span>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<!-- Model B: Clean Visual — approved 2026-03-28 -->
|
|
2
|
+
<!-- Style: Warm cream background, bold uppercase title, numbered cards with warm gradient progression -->
|
|
3
|
+
<!-- Fonts: Montserrat 900 (title), Inter 500-700 (body) -->
|
|
4
|
+
<!-- Colors: #FDF6EE bg, #E85D2A primary orange, #D4742A/#C05A1A/#A04010 gradient steps, #FFF5E6-#D07030 card backgrounds -->
|
|
5
|
+
<div style="width:1080px;height:1440px;background:#FDF6EE;color:#111;font-family:'Inter',sans-serif;display:flex;flex-direction:column;padding:72px;justify-content:center;gap:48px;position:relative;overflow:hidden;">
|
|
6
|
+
<!-- Title -->
|
|
7
|
+
<div style="text-align:center;">
|
|
8
|
+
<h1 style="font-size:58px;font-weight:900;line-height:1.15;margin:0;text-transform:uppercase;font-family:'Montserrat',sans-serif;">
|
|
9
|
+
<span style="color:#E85D2A;">LOREM IPSUM</span> DOLOR SIT AMET CONSECTETUR
|
|
10
|
+
</h1>
|
|
11
|
+
</div>
|
|
12
|
+
<!-- Items -->
|
|
13
|
+
<div style="display:flex;flex-direction:column;gap:20px;">
|
|
14
|
+
<div style="display:flex;align-items:center;gap:28px;background:#FFF5E6;border-radius:20px;padding:28px 32px;">
|
|
15
|
+
<div style="width:64px;height:64px;border-radius:50%;border:3px solid #E85D2A;display:flex;align-items:center;justify-content:center;font-size:28px;font-weight:800;color:#E85D2A;flex-shrink:0;">1</div>
|
|
16
|
+
<div><div style="font-size:34px;font-weight:700;">Proin tempus vehicula</div><div style="font-size:26px;color:#888;font-weight:500;">Sed ut perspiciatis unde omnis iste natus error.</div></div>
|
|
17
|
+
</div>
|
|
18
|
+
<div style="display:flex;align-items:center;gap:28px;background:linear-gradient(90deg,#FDEBD0,#F5C89A);border-radius:20px;padding:28px 32px;">
|
|
19
|
+
<div style="width:64px;height:64px;border-radius:50%;border:3px solid #D4742A;display:flex;align-items:center;justify-content:center;font-size:28px;font-weight:800;color:#D4742A;flex-shrink:0;">2</div>
|
|
20
|
+
<div><div style="font-size:34px;font-weight:700;">Vestibulum ante ipsum</div><div style="font-size:26px;color:#666;font-weight:500;">Nemo enim ipsam voluptatem quia voluptas sit.</div></div>
|
|
21
|
+
</div>
|
|
22
|
+
<div style="display:flex;align-items:center;gap:28px;background:linear-gradient(90deg,#F5C89A,#E8A065);border-radius:20px;padding:28px 32px;">
|
|
23
|
+
<div style="width:64px;height:64px;border-radius:50%;border:3px solid #C05A1A;display:flex;align-items:center;justify-content:center;font-size:28px;font-weight:800;color:#C05A1A;flex-shrink:0;">3</div>
|
|
24
|
+
<div><div style="font-size:34px;font-weight:700;">Maecenas dignissim justo</div><div style="font-size:26px;color:#555;font-weight:500;">Ut enim ad minima veniam nostrum exercitationem.</div></div>
|
|
25
|
+
</div>
|
|
26
|
+
<div style="display:flex;align-items:center;gap:28px;background:linear-gradient(90deg,#E8A065,#D07030);border-radius:20px;padding:28px 32px;">
|
|
27
|
+
<div style="width:64px;height:64px;border-radius:50%;border:3px solid #A04010;display:flex;align-items:center;justify-content:center;font-size:28px;font-weight:800;color:#A04010;flex-shrink:0;">4</div>
|
|
28
|
+
<div><div style="font-size:34px;font-weight:700;color:#fff;">Curabitur pretium tincidunt</div><div style="font-size:26px;color:#ffffffcc;font-weight:500;">Quis autem vel eum iure reprehenderit voluptate.</div></div>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<!-- Model C: Data Dashboard — approved 2026-03-28 -->
|
|
2
|
+
<!-- Style: Purple-dark gradient, data metric cards, decorative glow effects -->
|
|
3
|
+
<!-- Fonts: Montserrat 900 (title, metrics), Inter 500 (body, labels) -->
|
|
4
|
+
<!-- Colors: gradient #0f0326-#1a0a3e-#0d0d0d bg, #F59E0B yellow, #EC4899 pink, #7C3AED purple, #4ADE80 green accents -->
|
|
5
|
+
<div style="width:1080px;height:1440px;background:linear-gradient(160deg,#0f0326,#1a0a3e 40%,#0d0d0d);color:#fff;font-family:'Inter',sans-serif;display:flex;flex-direction:column;padding:72px;position:relative;overflow:hidden;">
|
|
6
|
+
<!-- Glow effects -->
|
|
7
|
+
<div style="position:absolute;top:-120px;right:-120px;width:480px;height:480px;background:radial-gradient(circle,#7C3AED33,transparent 70%);pointer-events:none;"></div>
|
|
8
|
+
<div style="position:absolute;bottom:-100px;left:-100px;width:400px;height:400px;background:radial-gradient(circle,#F59E0B22,transparent 70%);pointer-events:none;"></div>
|
|
9
|
+
<!-- Tag + Title -->
|
|
10
|
+
<div style="position:relative;z-index:1;">
|
|
11
|
+
<div style="display:inline-block;background:#F59E0B33;border-radius:8px;padding:8px 20px;font-size:24px;color:#F59E0B;font-weight:800;text-transform:uppercase;letter-spacing:3px;margin-bottom:28px;">Lorem Ipsum</div>
|
|
12
|
+
<h1 style="font-size:52px;font-weight:900;line-height:1.2;margin:0 0 24px 0;font-family:'Montserrat',sans-serif;">
|
|
13
|
+
Sed ut perspiciatis <span style="background:linear-gradient(90deg,#F59E0B,#EC4899);-webkit-background-clip:text;-webkit-text-fill-color:transparent;">unde omnis</span> iste natus error sit
|
|
14
|
+
</h1>
|
|
15
|
+
<p style="font-size:34px;color:#bbb;line-height:1.55;margin:0;font-weight:500;letter-spacing:0.01em;">Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores.</p>
|
|
16
|
+
</div>
|
|
17
|
+
<!-- Data cards -->
|
|
18
|
+
<div style="position:relative;z-index:1;display:flex;flex-direction:column;gap:16px;margin:40px 0;flex:1;justify-content:center;">
|
|
19
|
+
<div style="background:#ffffff08;border:1px solid #ffffff10;border-radius:16px;padding:28px 32px;display:flex;justify-content:space-between;align-items:center;">
|
|
20
|
+
<span style="font-size:28px;color:#888;font-weight:500;">Lorem ipsum</span>
|
|
21
|
+
<span style="font-size:40px;font-weight:800;color:#F59E0B;font-family:'Montserrat',sans-serif;">U$3.4B</span>
|
|
22
|
+
</div>
|
|
23
|
+
<div style="background:#ffffff08;border:1px solid #ffffff10;border-radius:16px;padding:28px 32px;display:flex;justify-content:space-between;align-items:center;">
|
|
24
|
+
<span style="font-size:28px;color:#888;font-weight:500;">Dolor sit amet</span>
|
|
25
|
+
<span style="font-size:40px;font-weight:800;color:#EC4899;font-family:'Montserrat',sans-serif;">-U$5B</span>
|
|
26
|
+
</div>
|
|
27
|
+
<div style="background:#ffffff08;border:1px solid #ffffff10;border-radius:16px;padding:28px 32px;display:flex;justify-content:space-between;align-items:center;">
|
|
28
|
+
<span style="font-size:28px;color:#888;font-weight:500;">Consectetur</span>
|
|
29
|
+
<span style="font-size:40px;font-weight:800;color:#7C3AED;font-family:'Montserrat',sans-serif;">U$157B</span>
|
|
30
|
+
</div>
|
|
31
|
+
<div style="background:#ffffff08;border:1px solid #ffffff10;border-radius:16px;padding:28px 32px;display:flex;justify-content:space-between;align-items:center;">
|
|
32
|
+
<span style="font-size:28px;color:#888;font-weight:500;">Adipiscing elit</span>
|
|
33
|
+
<span style="font-size:40px;font-weight:800;color:#4ADE80;font-family:'Montserrat',sans-serif;">3.500+</span>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
<!-- Footer -->
|
|
37
|
+
<div style="position:relative;z-index:1;display:flex;align-items:center;gap:20px;padding-top:24px;border-top:1px solid #ffffff12;">
|
|
38
|
+
<div style="width:48px;height:48px;border-radius:50%;background:linear-gradient(135deg,#F59E0B,#EC4899);"></div>
|
|
39
|
+
<span style="font-size:24px;color:#777;">@username</span>
|
|
40
|
+
<span style="margin-left:auto;font-size:24px;color:#555;">ARRASTE →</span>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { createInterface } from 'node:readline';
|
|
2
|
+
import { stat } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { listInstalled, installAgent, removeAgent, getAgentMeta, getLocalizedDescription } from './agents.js';
|
|
5
|
+
import { loadLocale, t, getLocaleCode } from './i18n.js';
|
|
6
|
+
import { loadSavedLocale } from './init.js';
|
|
7
|
+
import { logEvent } from './logger.js';
|
|
8
|
+
|
|
9
|
+
async function confirm(question) {
|
|
10
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
11
|
+
return new Promise((resolve) => {
|
|
12
|
+
rl.question(question, (answer) => {
|
|
13
|
+
rl.close();
|
|
14
|
+
resolve(answer.trim().toLowerCase());
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function agentsCli(subcommand, args, targetDir) {
|
|
20
|
+
// Require initialized project
|
|
21
|
+
try {
|
|
22
|
+
await stat(join(targetDir, '_conectese'));
|
|
23
|
+
} catch {
|
|
24
|
+
await loadLocale('English');
|
|
25
|
+
console.log(`\n ${t('agentsNotInitialized')}\n`);
|
|
26
|
+
return { success: false };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
await loadSavedLocale(targetDir);
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
if (subcommand === 'list' || !subcommand) {
|
|
33
|
+
await runList(targetDir);
|
|
34
|
+
} else if (subcommand === 'install') {
|
|
35
|
+
const installed = await runInstall(args[0], targetDir);
|
|
36
|
+
if (installed === false) return { success: false };
|
|
37
|
+
} else if (subcommand === 'remove') {
|
|
38
|
+
const removed = await runRemove(args[0], targetDir);
|
|
39
|
+
if (removed === false) return { success: false };
|
|
40
|
+
} else if (subcommand === 'update') {
|
|
41
|
+
await runUpdate(targetDir);
|
|
42
|
+
} else if (subcommand === 'update-one') {
|
|
43
|
+
await runUpdateOne(args[0], targetDir);
|
|
44
|
+
} else {
|
|
45
|
+
console.log(`\n ${t('agentsUnknownCommand', { cmd: subcommand })}\n`);
|
|
46
|
+
return { success: false };
|
|
47
|
+
}
|
|
48
|
+
} catch (err) {
|
|
49
|
+
console.log(`\n ${t('agentsError', { message: err.message })}\n`);
|
|
50
|
+
return { success: false };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return { success: true };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function runList(targetDir) {
|
|
57
|
+
console.log(`\n Conectese Agents\n`);
|
|
58
|
+
|
|
59
|
+
const installed = await listInstalled(targetDir);
|
|
60
|
+
|
|
61
|
+
if (installed.length > 0) {
|
|
62
|
+
console.log(` ${t('agentsInstalledHeader')}`);
|
|
63
|
+
for (const id of installed) {
|
|
64
|
+
const meta = await getAgentMeta(id);
|
|
65
|
+
if (meta) {
|
|
66
|
+
const desc = getLocalizedDescription(meta, getLocaleCode());
|
|
67
|
+
const parts = [meta.name];
|
|
68
|
+
if (meta.icon) parts.unshift(meta.icon);
|
|
69
|
+
if (meta.category) parts.push(`(${meta.category})`);
|
|
70
|
+
parts.push(`- ${desc.split('.')[0]}`);
|
|
71
|
+
console.log(` ${parts.join(' ')}`);
|
|
72
|
+
} else {
|
|
73
|
+
console.log(` ${id}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
console.log(` ${t('agentsNoneInstalled')}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
console.log(`\n Browse available agents at: https://github.com/renatoasse/conectese/tree/main/agents\n`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function runInstall(id, targetDir) {
|
|
84
|
+
if (!id) {
|
|
85
|
+
console.log('\n Usage: conectese agents install <id>\n');
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const installed = await listInstalled(targetDir);
|
|
90
|
+
if (installed.includes(id)) {
|
|
91
|
+
const answer = await confirm(`\n ${t('agentsAlreadyInstalled', { id })}`);
|
|
92
|
+
// Accept 'y' (English) or 's' (Portuguese "sim") as affirmative answers
|
|
93
|
+
if (answer !== 'y' && answer !== 's') return false;
|
|
94
|
+
console.log(` ${t('agentsInstalling', { id })}`);
|
|
95
|
+
await installAgent(id, targetDir);
|
|
96
|
+
console.log(` ${t('agentsReinstalled', { id })}\n`);
|
|
97
|
+
await logEvent('agent:install', { name: id, reinstall: true }, targetDir);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.log(`\n ${t('agentsInstalling', { id })}`);
|
|
102
|
+
await installAgent(id, targetDir);
|
|
103
|
+
console.log(` ${t('agentsInstalled', { id })}\n`);
|
|
104
|
+
await logEvent('agent:install', { name: id }, targetDir);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function runRemove(id, targetDir) {
|
|
108
|
+
if (!id) {
|
|
109
|
+
console.log('\n Usage: conectese agents remove <id>\n');
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const installed = await listInstalled(targetDir);
|
|
114
|
+
if (!installed.includes(id)) {
|
|
115
|
+
console.log(`\n ${t('agentsNotInstalled', { id })}\n`);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.log(`\n ${t('agentsRemoving', { id })}`);
|
|
120
|
+
await removeAgent(id, targetDir);
|
|
121
|
+
await logEvent('agent:remove', { name: id }, targetDir);
|
|
122
|
+
console.log(` ${t('agentsRemoved', { id })}\n`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function runUpdate(targetDir) {
|
|
126
|
+
const installed = await listInstalled(targetDir);
|
|
127
|
+
if (installed.length === 0) {
|
|
128
|
+
console.log(`\n ${t('agentsUpdateNone')}\n`);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
console.log(`\n ${t('agentsUpdating')}`);
|
|
133
|
+
for (const id of installed) {
|
|
134
|
+
console.log(` ${t('agentsInstalling', { id })}`);
|
|
135
|
+
await installAgent(id, targetDir);
|
|
136
|
+
console.log(` ${t('agentsInstalled', { id })}`);
|
|
137
|
+
}
|
|
138
|
+
await logEvent('agent:update', { count: installed.length }, targetDir);
|
|
139
|
+
console.log(`\n ${t('agentsUpdateDone', { count: installed.length })}\n`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async function runUpdateOne(id, targetDir) {
|
|
143
|
+
if (!id) {
|
|
144
|
+
console.log('\n Usage: conectese update <name>\n');
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const installed = await listInstalled(targetDir);
|
|
149
|
+
if (!installed.includes(id)) {
|
|
150
|
+
console.log(`\n ${t('agentsNotInstalled', { id })}\n`);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
console.log(`\n ${t('agentsInstalling', { id })}`);
|
|
155
|
+
await installAgent(id, targetDir);
|
|
156
|
+
await logEvent('agent:update', { name: id }, targetDir);
|
|
157
|
+
console.log(` ${t('agentsInstalled', { id })}\n`);
|
|
158
|
+
}
|
package/src/agents.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { copyFile, mkdir, readdir, readFile, rm } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const BUNDLED_AGENTS_DIR = join(__dirname, '..', 'agents');
|
|
7
|
+
|
|
8
|
+
const metaCache = new Map();
|
|
9
|
+
|
|
10
|
+
export async function listInstalled(targetDir) {
|
|
11
|
+
try {
|
|
12
|
+
const agentsDir = join(targetDir, 'agents');
|
|
13
|
+
const entries = await readdir(agentsDir, { withFileTypes: true });
|
|
14
|
+
return entries
|
|
15
|
+
.filter((e) => e.isFile() && e.name.endsWith('.agent.md'))
|
|
16
|
+
.map((e) => e.name.replace(/\.agent\.md$/, ''));
|
|
17
|
+
} catch (err) {
|
|
18
|
+
if (err.code === 'ENOENT') return [];
|
|
19
|
+
throw err;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function listAvailable() {
|
|
24
|
+
try {
|
|
25
|
+
const entries = await readdir(BUNDLED_AGENTS_DIR, { withFileTypes: true });
|
|
26
|
+
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
27
|
+
} catch {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function getAgentMeta(id) {
|
|
33
|
+
if (metaCache.has(id)) return metaCache.get(id);
|
|
34
|
+
try {
|
|
35
|
+
const raw = await readFile(join(BUNDLED_AGENTS_DIR, id, 'AGENT.md'), 'utf-8');
|
|
36
|
+
const content = raw.replace(/\r\n/g, '\n');
|
|
37
|
+
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
38
|
+
if (!fmMatch) return { name: id, description: '', descriptions: {}, category: '', icon: '', version: '' };
|
|
39
|
+
|
|
40
|
+
const fm = fmMatch[1];
|
|
41
|
+
const name = fm.match(/^name:\s*(.+)$/m)?.[1]?.trim() || id;
|
|
42
|
+
const category = fm.match(/^category:\s*(.+)$/m)?.[1]?.trim() || '';
|
|
43
|
+
const icon = fm.match(/^icon:\s*(.+)$/m)?.[1]?.trim() || '';
|
|
44
|
+
const version = fm.match(/^version:\s*(.+)$/m)?.[1]?.trim() || '';
|
|
45
|
+
|
|
46
|
+
// description may use YAML folded scalar (>)
|
|
47
|
+
let description = '';
|
|
48
|
+
const descBlock = fm.match(/^description:\s*>\s*\n((?:\s{2,}.+\n?)+)/m);
|
|
49
|
+
if (descBlock) {
|
|
50
|
+
description = descBlock[1].replace(/\n\s*/g, ' ').trim();
|
|
51
|
+
} else {
|
|
52
|
+
const descInline = fm.match(/^description:\s*(.+)$/m);
|
|
53
|
+
if (descInline) description = descInline[1].trim();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// localized descriptions: description_pt-BR, description_es, etc.
|
|
57
|
+
const descriptions = {};
|
|
58
|
+
for (const code of ['pt-BR', 'es']) {
|
|
59
|
+
const key = `description_${code}`;
|
|
60
|
+
// folded scalar
|
|
61
|
+
const blockMatch = fm.match(new RegExp(`^${key}:\\s*>\\s*\\n((?:\\s{2,}.+\\n?)+)`, 'm'));
|
|
62
|
+
if (blockMatch) {
|
|
63
|
+
descriptions[code] = blockMatch[1].replace(/\n\s*/g, ' ').trim();
|
|
64
|
+
} else {
|
|
65
|
+
// inline
|
|
66
|
+
const inlineMatch = fm.match(new RegExp(`^${key}:\\s*(.+)$`, 'm'));
|
|
67
|
+
if (inlineMatch) descriptions[code] = inlineMatch[1].trim();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const result = { name, description, descriptions, category, icon, version };
|
|
72
|
+
metaCache.set(id, result);
|
|
73
|
+
return result;
|
|
74
|
+
} catch (err) {
|
|
75
|
+
if (err.code === 'ENOENT') {
|
|
76
|
+
metaCache.set(id, null);
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
throw err;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function validateAgentId(id) {
|
|
84
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(id)) {
|
|
85
|
+
throw new Error(`Invalid agent id: '${id}'`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export async function installAgent(id, targetDir) {
|
|
90
|
+
validateAgentId(id);
|
|
91
|
+
const srcFile = join(BUNDLED_AGENTS_DIR, id, 'AGENT.md');
|
|
92
|
+
try {
|
|
93
|
+
await readFile(srcFile);
|
|
94
|
+
} catch (err) {
|
|
95
|
+
if (err.code === 'ENOENT') throw new Error(`Agent '${id}' not found in registry`, { cause: err });
|
|
96
|
+
throw err;
|
|
97
|
+
}
|
|
98
|
+
const destDir = join(targetDir, 'agents');
|
|
99
|
+
await mkdir(destDir, { recursive: true });
|
|
100
|
+
await copyFile(srcFile, join(destDir, `${id}.agent.md`));
|
|
101
|
+
metaCache.delete(id);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export async function removeAgent(id, targetDir) {
|
|
105
|
+
validateAgentId(id);
|
|
106
|
+
const agentFile = join(targetDir, 'agents', `${id}.agent.md`);
|
|
107
|
+
await rm(agentFile, { force: true });
|
|
108
|
+
metaCache.delete(id);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function clearMetaCache() {
|
|
112
|
+
metaCache.clear();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export async function getAgentVersion(id, targetDir) {
|
|
116
|
+
try {
|
|
117
|
+
const agentPath = join(targetDir, 'agents', `${id}.agent.md`);
|
|
118
|
+
const content = await readFile(agentPath, 'utf-8');
|
|
119
|
+
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
120
|
+
if (!fmMatch) return null;
|
|
121
|
+
const versionMatch = fmMatch[1].match(/^version:\s*(.+)$/m);
|
|
122
|
+
return versionMatch ? versionMatch[1].trim() : null;
|
|
123
|
+
} catch (err) {
|
|
124
|
+
if (err.code === 'ENOENT') return null;
|
|
125
|
+
throw err;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function getLocalizedDescription(meta, localeCode) {
|
|
130
|
+
if (localeCode && localeCode !== 'en' && meta.descriptions?.[localeCode]) {
|
|
131
|
+
return meta.descriptions[localeCode];
|
|
132
|
+
}
|
|
133
|
+
return meta.description;
|
|
134
|
+
}
|
package/src/i18n.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { join, dirname } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const LOCALES_DIR = join(__dirname, 'locales');
|
|
7
|
+
|
|
8
|
+
const LANG_MAP = {
|
|
9
|
+
'Português (Brasil)': 'pt-BR',
|
|
10
|
+
'English': 'en',
|
|
11
|
+
'Español': 'es',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
let strings = {};
|
|
15
|
+
let fallback = {};
|
|
16
|
+
let currentCode = 'en';
|
|
17
|
+
|
|
18
|
+
export async function loadLocale(langLabel) {
|
|
19
|
+
const code = LANG_MAP[langLabel] || 'en';
|
|
20
|
+
currentCode = code;
|
|
21
|
+
|
|
22
|
+
const enPath = join(LOCALES_DIR, 'en.json');
|
|
23
|
+
fallback = JSON.parse(await readFile(enPath, 'utf-8'));
|
|
24
|
+
|
|
25
|
+
if (code === 'en') {
|
|
26
|
+
strings = fallback;
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const localePath = join(LOCALES_DIR, `${code}.json`);
|
|
32
|
+
strings = JSON.parse(await readFile(localePath, 'utf-8'));
|
|
33
|
+
} catch {
|
|
34
|
+
strings = fallback;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function getLocaleCode() {
|
|
39
|
+
return currentCode;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function t(key, vars = {}) {
|
|
43
|
+
let str = strings[key] ?? fallback[key] ?? key;
|
|
44
|
+
for (const [k, v] of Object.entries(vars)) {
|
|
45
|
+
str = str.replaceAll(`{${k}}`, v);
|
|
46
|
+
}
|
|
47
|
+
return str;
|
|
48
|
+
}
|