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.
Files changed (260) hide show
  1. package/README.md +265 -0
  2. package/_conectese/.conectese-version +1 -0
  3. package/_conectese/config/playwright.config.json +11 -0
  4. package/_conectese/core/architect.agent.yaml +110 -0
  5. package/_conectese/core/best-practices/_catalog.yaml +116 -0
  6. package/_conectese/core/best-practices/blog-post.md +132 -0
  7. package/_conectese/core/best-practices/blog-seo.md +127 -0
  8. package/_conectese/core/best-practices/copywriting.md +426 -0
  9. package/_conectese/core/best-practices/data-analysis.md +401 -0
  10. package/_conectese/core/best-practices/email-newsletter.md +118 -0
  11. package/_conectese/core/best-practices/email-sales.md +110 -0
  12. package/_conectese/core/best-practices/image-design.md +348 -0
  13. package/_conectese/core/best-practices/instagram-feed.md +235 -0
  14. package/_conectese/core/best-practices/instagram-reels.md +112 -0
  15. package/_conectese/core/best-practices/instagram-stories.md +107 -0
  16. package/_conectese/core/best-practices/linkedin-article.md +116 -0
  17. package/_conectese/core/best-practices/linkedin-post.md +121 -0
  18. package/_conectese/core/best-practices/researching.md +349 -0
  19. package/_conectese/core/best-practices/review.md +269 -0
  20. package/_conectese/core/best-practices/social-networks-publishing.md +294 -0
  21. package/_conectese/core/best-practices/strategist.md +344 -0
  22. package/_conectese/core/best-practices/technical-writing.md +365 -0
  23. package/_conectese/core/best-practices/twitter-post.md +105 -0
  24. package/_conectese/core/best-practices/twitter-thread.md +122 -0
  25. package/_conectese/core/best-practices/whatsapp-broadcast.md +107 -0
  26. package/_conectese/core/best-practices/youtube-script.md +122 -0
  27. package/_conectese/core/best-practices/youtube-shorts.md +112 -0
  28. package/_conectese/core/prompts/build.prompt.md +547 -0
  29. package/_conectese/core/prompts/design.prompt.md +469 -0
  30. package/_conectese/core/prompts/discovery.prompt.md +269 -0
  31. package/_conectese/core/prompts/sherlock-instagram.md +123 -0
  32. package/_conectese/core/prompts/sherlock-linkedin.md +73 -0
  33. package/_conectese/core/prompts/sherlock-shared.md +684 -0
  34. package/_conectese/core/prompts/sherlock-twitter.md +78 -0
  35. package/_conectese/core/prompts/sherlock-youtube.md +85 -0
  36. package/_conectese/core/runner.pipeline.md +535 -0
  37. package/_conectese/core/skills.engine.md +381 -0
  38. package/agents/data-extractor/AGENT.md +13 -0
  39. package/agents/direito-adaneiro/AGENT.md +18 -0
  40. package/agents/direito-administrativo/AGENT.md +18 -0
  41. package/agents/direito-aeroporta-rio/AGENT.md +18 -0
  42. package/agents/direito-agra-rio/AGENT.md +18 -0
  43. package/agents/direito-ambiental/AGENT.md +18 -0
  44. package/agents/direito-banca-rio/AGENT.md +18 -0
  45. package/agents/direito-civil/AGENT.md +18 -0
  46. package/agents/direito-constitcional/AGENT.md +18 -0
  47. package/agents/direito-da-crianc-a-e-do-adolescente-eca/AGENT.md +18 -0
  48. package/agents/direito-da-propriedade-intelectal/AGENT.md +18 -0
  49. package/agents/direito-de-ami-lia/AGENT.md +18 -0
  50. package/agents/direito-de-tra-nsito/AGENT.md +18 -0
  51. package/agents/direito-desportivo/AGENT.md +18 -0
  52. package/agents/direito-digital/AGENT.md +18 -0
  53. package/agents/direito-do-consmidor/AGENT.md +18 -0
  54. package/agents/direito-do-trabalho/AGENT.md +18 -0
  55. package/agents/direito-econo-mico/AGENT.md +18 -0
  56. package/agents/direito-eleitoral/AGENT.md +18 -0
  57. package/agents/direito-empresarial/AGENT.md +18 -0
  58. package/agents/direito-imobilia-rio/AGENT.md +18 -0
  59. package/agents/direito-inanceiro/AGENT.md +18 -0
  60. package/agents/direito-internacional/AGENT.md +18 -0
  61. package/agents/direito-mari-timo/AGENT.md +18 -0
  62. package/agents/direito-me-dico-e-da-sa-de/AGENT.md +18 -0
  63. package/agents/direito-militar/AGENT.md +18 -0
  64. package/agents/direito-ndia-rio/AGENT.md +18 -0
  65. package/agents/direito-notarial-e-registral/AGENT.md +18 -0
  66. package/agents/direito-penal/AGENT.md +18 -0
  67. package/agents/direito-previdencia-rio/AGENT.md +18 -0
  68. package/agents/direito-processal-civil/AGENT.md +18 -0
  69. package/agents/direito-processal-do-trabalho/AGENT.md +18 -0
  70. package/agents/direito-processal-militar/AGENT.md +18 -0
  71. package/agents/direito-processal-penal/AGENT.md +18 -0
  72. package/agents/direito-rbani-stico/AGENT.md +18 -0
  73. package/agents/direito-secrita-rio/AGENT.md +18 -0
  74. package/agents/direito-sindical/AGENT.md +18 -0
  75. package/agents/direito-societa-rio/AGENT.md +18 -0
  76. package/agents/direito-tribta-rio/AGENT.md +18 -0
  77. package/agents/direitos-hmanos/AGENT.md +18 -0
  78. package/agents/legal-analyst/AGENT.md +16 -0
  79. package/agents/legal-synthesizer/AGENT.md +13 -0
  80. package/agents/lgpd-anonymizer/AGENT.md +14 -0
  81. package/agents/lgpd-restorer/AGENT.md +14 -0
  82. package/agents/task-router/AGENT.md +13 -0
  83. package/bin/conectese.js +73 -0
  84. package/dashboard/index.html +12 -0
  85. package/dashboard/package-lock.json +1971 -0
  86. package/dashboard/package.json +28 -0
  87. package/dashboard/public/assets/avatars/Female1_1wave.png +0 -0
  88. package/dashboard/public/assets/avatars/Female1_2wave.png +0 -0
  89. package/dashboard/public/assets/avatars/Female1_blink.png +0 -0
  90. package/dashboard/public/assets/avatars/Female1_talk.png +0 -0
  91. package/dashboard/public/assets/avatars/Female2_1wave.png +0 -0
  92. package/dashboard/public/assets/avatars/Female2_2wave.png +0 -0
  93. package/dashboard/public/assets/avatars/Female2_blink.png +0 -0
  94. package/dashboard/public/assets/avatars/Female2_talk.png +0 -0
  95. package/dashboard/public/assets/avatars/Female3_blink.png +0 -0
  96. package/dashboard/public/assets/avatars/Female3_talk.png +0 -0
  97. package/dashboard/public/assets/avatars/Female3_wave.png +0 -0
  98. package/dashboard/public/assets/avatars/Female4_blink.png +0 -0
  99. package/dashboard/public/assets/avatars/Female4_talk.png +0 -0
  100. package/dashboard/public/assets/avatars/Female4_wave.png +0 -0
  101. package/dashboard/public/assets/avatars/Female5_blink.png +0 -0
  102. package/dashboard/public/assets/avatars/Female5_talk.png +0 -0
  103. package/dashboard/public/assets/avatars/Female5_wave.png +0 -0
  104. package/dashboard/public/assets/avatars/Female6_blink.png +0 -0
  105. package/dashboard/public/assets/avatars/Female6_talk.png +0 -0
  106. package/dashboard/public/assets/avatars/Female6_wave.png +0 -0
  107. package/dashboard/public/assets/avatars/Male1_1wave.png +0 -0
  108. package/dashboard/public/assets/avatars/Male1_2wave.png +0 -0
  109. package/dashboard/public/assets/avatars/Male1_blink.png +0 -0
  110. package/dashboard/public/assets/avatars/Male1_talk.png +0 -0
  111. package/dashboard/public/assets/avatars/Male2_1wave.png +0 -0
  112. package/dashboard/public/assets/avatars/Male2_2wave.png +0 -0
  113. package/dashboard/public/assets/avatars/Male2_blink.png +0 -0
  114. package/dashboard/public/assets/avatars/Male2_talk.png +0 -0
  115. package/dashboard/public/assets/avatars/Male3_blink.png +0 -0
  116. package/dashboard/public/assets/avatars/Male3_talk.png +0 -0
  117. package/dashboard/public/assets/avatars/Male3_wave.png +0 -0
  118. package/dashboard/public/assets/avatars/Male4_blink.png +0 -0
  119. package/dashboard/public/assets/avatars/Male4_talk.png +0 -0
  120. package/dashboard/public/assets/avatars/Male4_wave.png +0 -0
  121. package/dashboard/public/assets/desks/desktop_set_black_down.png +0 -0
  122. package/dashboard/public/assets/desks/desktop_set_black_down_coding-1.png +0 -0
  123. package/dashboard/public/assets/desks/desktop_set_black_down_coding.png +0 -0
  124. package/dashboard/public/assets/desks/desktop_set_black_up.png +0 -0
  125. package/dashboard/public/assets/desks/desktop_set_white_down.png +0 -0
  126. package/dashboard/public/assets/desks/desktop_set_white_down_coding-1.png +0 -0
  127. package/dashboard/public/assets/desks/desktop_set_white_down_coding.png +0 -0
  128. package/dashboard/public/assets/desks/desktop_set_white_up.png +0 -0
  129. package/dashboard/public/assets/furniture/armchair_tan.png +0 -0
  130. package/dashboard/public/assets/furniture/armchair_tan_down.png +0 -0
  131. package/dashboard/public/assets/furniture/backpack_blue.png +0 -0
  132. package/dashboard/public/assets/furniture/backpack_red.png +0 -0
  133. package/dashboard/public/assets/furniture/blinds.png +0 -0
  134. package/dashboard/public/assets/furniture/blinds_large_closed_white.png +0 -0
  135. package/dashboard/public/assets/furniture/bookshelf.png +0 -0
  136. package/dashboard/public/assets/furniture/bookshelf_purple_tall.png +0 -0
  137. package/dashboard/public/assets/furniture/bulletin_board.png +0 -0
  138. package/dashboard/public/assets/furniture/clock.png +0 -0
  139. package/dashboard/public/assets/furniture/coffee_mug.png +0 -0
  140. package/dashboard/public/assets/furniture/coffee_mug_blue.png +0 -0
  141. package/dashboard/public/assets/furniture/coffee_table.png +0 -0
  142. package/dashboard/public/assets/furniture/coffeepot_right.png +0 -0
  143. package/dashboard/public/assets/furniture/coffeetable_black_horizontal.png +0 -0
  144. package/dashboard/public/assets/furniture/couch.png +0 -0
  145. package/dashboard/public/assets/furniture/couch_tan_down.png +0 -0
  146. package/dashboard/public/assets/furniture/cushion_blue.png +0 -0
  147. package/dashboard/public/assets/furniture/cushion_tan.png +0 -0
  148. package/dashboard/public/assets/furniture/desk_wood.png +0 -0
  149. package/dashboard/public/assets/furniture/fancy_rug.png +0 -0
  150. package/dashboard/public/assets/furniture/fancy_rug_wide.png +0 -0
  151. package/dashboard/public/assets/furniture/flowers1.png +0 -0
  152. package/dashboard/public/assets/furniture/flowers2.png +0 -0
  153. package/dashboard/public/assets/furniture/lamp_tan.png +0 -0
  154. package/dashboard/public/assets/furniture/lantern.png +0 -0
  155. package/dashboard/public/assets/furniture/monstera.png +0 -0
  156. package/dashboard/public/assets/furniture/monstera_small.png +0 -0
  157. package/dashboard/public/assets/furniture/picture_frame.png +0 -0
  158. package/dashboard/public/assets/furniture/plant1.png +0 -0
  159. package/dashboard/public/assets/furniture/plant2.png +0 -0
  160. package/dashboard/public/assets/furniture/plant3.png +0 -0
  161. package/dashboard/public/assets/furniture/plant_poof.png +0 -0
  162. package/dashboard/public/assets/furniture/plant_spindly.png +0 -0
  163. package/dashboard/public/assets/furniture/poster_blue.png +0 -0
  164. package/dashboard/public/assets/furniture/rug.png +0 -0
  165. package/dashboard/public/assets/furniture/succulent_blue.png +0 -0
  166. package/dashboard/public/assets/furniture/succulent_green.png +0 -0
  167. package/dashboard/public/assets/furniture/treasurechest_closed_gold.png +0 -0
  168. package/dashboard/public/assets/furniture/water_cooler_better.png +0 -0
  169. package/dashboard/public/assets/furniture/whiteboard.png +0 -0
  170. package/dashboard/public/assets/furniture/whiteboard_stand_graph.png +0 -0
  171. package/dashboard/public/assets/furniture/window_blinds_open.png +0 -0
  172. package/dashboard/src/App.tsx +46 -0
  173. package/dashboard/src/components/SquadCard.tsx +47 -0
  174. package/dashboard/src/components/SquadSelector.tsx +61 -0
  175. package/dashboard/src/components/StatusBadge.tsx +32 -0
  176. package/dashboard/src/components/StatusBar.tsx +97 -0
  177. package/dashboard/src/hooks/useSquadSocket.ts +135 -0
  178. package/dashboard/src/lib/formatTime.ts +16 -0
  179. package/dashboard/src/lib/normalizeState.ts +25 -0
  180. package/dashboard/src/main.tsx +10 -0
  181. package/dashboard/src/office/AgentSprite.ts +241 -0
  182. package/dashboard/src/office/OfficeScene.ts +153 -0
  183. package/dashboard/src/office/PhaserGame.tsx +80 -0
  184. package/dashboard/src/office/RoomBuilder.ts +190 -0
  185. package/dashboard/src/office/assetKeys.ts +150 -0
  186. package/dashboard/src/office/palette.ts +32 -0
  187. package/dashboard/src/plugin/squadWatcher.ts +233 -0
  188. package/dashboard/src/store/useSquadStore.ts +56 -0
  189. package/dashboard/src/styles/globals.css +36 -0
  190. package/dashboard/src/types/state.ts +63 -0
  191. package/dashboard/src/vite-env.d.ts +1 -0
  192. package/dashboard/test-results/.last-run.json +4 -0
  193. package/dashboard/tsconfig.json +24 -0
  194. package/dashboard/tsconfig.tsbuildinfo +1 -0
  195. package/dashboard/vite.config.ts +13 -0
  196. package/package.json +53 -0
  197. package/skills/README.md +63 -0
  198. package/skills/apify/SKILL.md +55 -0
  199. package/skills/blotato/SKILL.md +63 -0
  200. package/skills/canva/SKILL.md +60 -0
  201. package/skills/conectese-agent-creator/SKILL.md +192 -0
  202. package/skills/conectese-skill-creator/SKILL.md +407 -0
  203. package/skills/conectese-skill-creator/agents/analyzer.md +274 -0
  204. package/skills/conectese-skill-creator/agents/comparator.md +202 -0
  205. package/skills/conectese-skill-creator/agents/grader.md +223 -0
  206. package/skills/conectese-skill-creator/assets/eval_review.html +146 -0
  207. package/skills/conectese-skill-creator/eval-viewer/generate_review.py +471 -0
  208. package/skills/conectese-skill-creator/eval-viewer/viewer.html +1325 -0
  209. package/skills/conectese-skill-creator/references/schemas.md +430 -0
  210. package/skills/conectese-skill-creator/references/skill-format.md +235 -0
  211. package/skills/conectese-skill-creator/scripts/__init__.py +0 -0
  212. package/skills/conectese-skill-creator/scripts/aggregate_benchmark.py +401 -0
  213. package/skills/conectese-skill-creator/scripts/quick_validate.py +103 -0
  214. package/skills/conectese-skill-creator/scripts/run_eval.py +310 -0
  215. package/skills/conectese-skill-creator/scripts/utils.py +47 -0
  216. package/skills/image-ai-generator/SKILL.md +124 -0
  217. package/skills/image-ai-generator/scripts/generate.py +175 -0
  218. package/skills/image-creator/SKILL.md +155 -0
  219. package/skills/image-fetcher/SKILL.md +91 -0
  220. package/skills/instagram-publisher/SKILL.md +119 -0
  221. package/skills/instagram-publisher/scripts/publish.js +165 -0
  222. package/skills/resend/SKILL.md +80 -0
  223. package/skills/template-designer/SKILL.md +201 -0
  224. package/skills/template-designer/base-templates/model-a.html +27 -0
  225. package/skills/template-designer/base-templates/model-b.html +31 -0
  226. package/skills/template-designer/base-templates/model-c.html +42 -0
  227. package/src/agents-cli.js +158 -0
  228. package/src/agents.js +134 -0
  229. package/src/i18n.js +48 -0
  230. package/src/init.js +341 -0
  231. package/src/locales/en.json +73 -0
  232. package/src/locales/es.json +72 -0
  233. package/src/locales/pt-BR.json +72 -0
  234. package/src/logger.js +38 -0
  235. package/src/prompt.js +46 -0
  236. package/src/readme/README.md +119 -0
  237. package/src/runs.js +90 -0
  238. package/src/skills-cli.js +157 -0
  239. package/src/skills.js +146 -0
  240. package/src/update.js +169 -0
  241. package/templates/_conectese/.conectese-version +1 -0
  242. package/templates/_conectese/_investigations/.gitkeep +0 -0
  243. package/templates/ide-templates/antigravity/.agent/rules/conectese.md +55 -0
  244. package/templates/ide-templates/antigravity/.agent/workflows/conectese.md +102 -0
  245. package/templates/ide-templates/claude-code/.claude/skills/conectese/SKILL.md +182 -0
  246. package/templates/ide-templates/claude-code/.mcp.json +8 -0
  247. package/templates/ide-templates/claude-code/CLAUDE.md +43 -0
  248. package/templates/ide-templates/codex/.agents/skills/conectese/SKILL.md +6 -0
  249. package/templates/ide-templates/codex/AGENTS.md +105 -0
  250. package/templates/ide-templates/cursor/.cursor/commands/conectese.md +9 -0
  251. package/templates/ide-templates/cursor/.cursor/mcp.json +8 -0
  252. package/templates/ide-templates/cursor/.cursor/rules/conectese.mdc +48 -0
  253. package/templates/ide-templates/cursor/.cursorignore +3 -0
  254. package/templates/ide-templates/opencode/.opencode/commands/conectese.md +9 -0
  255. package/templates/ide-templates/opencode/AGENTS.md +105 -0
  256. package/templates/ide-templates/vscode-copilot/.github/prompts/conectese.prompt.md +201 -0
  257. package/templates/ide-templates/vscode-copilot/.vscode/mcp.json +8 -0
  258. package/templates/ide-templates/vscode-copilot/.vscode/settings.json +3 -0
  259. package/templates/package.json +8 -0
  260. 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
+ }