@julioventura/opensquad 0.1.17

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 (247) hide show
  1. package/README.md +433 -0
  2. package/_opensquad/config/playwright.config.json +11 -0
  3. package/_opensquad/core/architect.agent.yaml +112 -0
  4. package/_opensquad/core/best-practices/_catalog.yaml +126 -0
  5. package/_opensquad/core/best-practices/blog-post.md +132 -0
  6. package/_opensquad/core/best-practices/blog-seo.md +127 -0
  7. package/_opensquad/core/best-practices/brand-resolution-checklist.md +172 -0
  8. package/_opensquad/core/best-practices/copywriting.md +441 -0
  9. package/_opensquad/core/best-practices/data-analysis.md +401 -0
  10. package/_opensquad/core/best-practices/email-newsletter.md +118 -0
  11. package/_opensquad/core/best-practices/email-sales.md +110 -0
  12. package/_opensquad/core/best-practices/image-design.md +348 -0
  13. package/_opensquad/core/best-practices/instagram-feed.md +235 -0
  14. package/_opensquad/core/best-practices/instagram-reels.md +112 -0
  15. package/_opensquad/core/best-practices/instagram-stories.md +107 -0
  16. package/_opensquad/core/best-practices/linkedin-article.md +116 -0
  17. package/_opensquad/core/best-practices/linkedin-post.md +121 -0
  18. package/_opensquad/core/best-practices/researching.md +349 -0
  19. package/_opensquad/core/best-practices/review.md +269 -0
  20. package/_opensquad/core/best-practices/run-recovery.md +61 -0
  21. package/_opensquad/core/best-practices/social-networks-publishing.md +327 -0
  22. package/_opensquad/core/best-practices/squad-creation-checklist.md +32 -0
  23. package/_opensquad/core/best-practices/strategist.md +344 -0
  24. package/_opensquad/core/best-practices/technical-writing.md +365 -0
  25. package/_opensquad/core/best-practices/twitter-post.md +105 -0
  26. package/_opensquad/core/best-practices/twitter-thread.md +122 -0
  27. package/_opensquad/core/best-practices/whatsapp-broadcast.md +107 -0
  28. package/_opensquad/core/best-practices/youtube-script.md +122 -0
  29. package/_opensquad/core/best-practices/youtube-shorts.md +112 -0
  30. package/_opensquad/core/defaults/youtube-video-assembly.json +84 -0
  31. package/_opensquad/core/prompts/build.prompt.md +613 -0
  32. package/_opensquad/core/prompts/design.prompt.md +606 -0
  33. package/_opensquad/core/prompts/discovery.prompt.md +377 -0
  34. package/_opensquad/core/prompts/sherlock-instagram.md +123 -0
  35. package/_opensquad/core/prompts/sherlock-linkedin.md +73 -0
  36. package/_opensquad/core/prompts/sherlock-shared.md +684 -0
  37. package/_opensquad/core/prompts/sherlock-twitter.md +78 -0
  38. package/_opensquad/core/prompts/sherlock-youtube.md +85 -0
  39. package/_opensquad/core/runner.pipeline.md +743 -0
  40. package/_opensquad/core/skills.engine.md +384 -0
  41. package/bin/opensquad.js +108 -0
  42. package/dashboard/index.html +15 -0
  43. package/dashboard/package-lock.json +1964 -0
  44. package/dashboard/package.json +28 -0
  45. package/dashboard/public/assets/avatars/Female1_1wave.png +0 -0
  46. package/dashboard/public/assets/avatars/Female1_2wave.png +0 -0
  47. package/dashboard/public/assets/avatars/Female1_blink.png +0 -0
  48. package/dashboard/public/assets/avatars/Female1_talk.png +0 -0
  49. package/dashboard/public/assets/avatars/Female2_1wave.png +0 -0
  50. package/dashboard/public/assets/avatars/Female2_2wave.png +0 -0
  51. package/dashboard/public/assets/avatars/Female2_blink.png +0 -0
  52. package/dashboard/public/assets/avatars/Female2_talk.png +0 -0
  53. package/dashboard/public/assets/avatars/Female3_blink.png +0 -0
  54. package/dashboard/public/assets/avatars/Female3_talk.png +0 -0
  55. package/dashboard/public/assets/avatars/Female3_wave.png +0 -0
  56. package/dashboard/public/assets/avatars/Female4_blink.png +0 -0
  57. package/dashboard/public/assets/avatars/Female4_talk.png +0 -0
  58. package/dashboard/public/assets/avatars/Female4_wave.png +0 -0
  59. package/dashboard/public/assets/avatars/Female5_blink.png +0 -0
  60. package/dashboard/public/assets/avatars/Female5_talk.png +0 -0
  61. package/dashboard/public/assets/avatars/Female5_wave.png +0 -0
  62. package/dashboard/public/assets/avatars/Female6_blink.png +0 -0
  63. package/dashboard/public/assets/avatars/Female6_talk.png +0 -0
  64. package/dashboard/public/assets/avatars/Female6_wave.png +0 -0
  65. package/dashboard/public/assets/avatars/Male1_1wave.png +0 -0
  66. package/dashboard/public/assets/avatars/Male1_2wave.png +0 -0
  67. package/dashboard/public/assets/avatars/Male1_blink.png +0 -0
  68. package/dashboard/public/assets/avatars/Male1_talk.png +0 -0
  69. package/dashboard/public/assets/avatars/Male2_1wave.png +0 -0
  70. package/dashboard/public/assets/avatars/Male2_2wave.png +0 -0
  71. package/dashboard/public/assets/avatars/Male2_blink.png +0 -0
  72. package/dashboard/public/assets/avatars/Male2_talk.png +0 -0
  73. package/dashboard/public/assets/avatars/Male3_blink.png +0 -0
  74. package/dashboard/public/assets/avatars/Male3_talk.png +0 -0
  75. package/dashboard/public/assets/avatars/Male3_wave.png +0 -0
  76. package/dashboard/public/assets/avatars/Male4_blink.png +0 -0
  77. package/dashboard/public/assets/avatars/Male4_talk.png +0 -0
  78. package/dashboard/public/assets/avatars/Male4_wave.png +0 -0
  79. package/dashboard/public/assets/desks/desktop_set_black_down.png +0 -0
  80. package/dashboard/public/assets/desks/desktop_set_black_down_coding-1.png +0 -0
  81. package/dashboard/public/assets/desks/desktop_set_black_down_coding.png +0 -0
  82. package/dashboard/public/assets/desks/desktop_set_black_up.png +0 -0
  83. package/dashboard/public/assets/desks/desktop_set_white_down.png +0 -0
  84. package/dashboard/public/assets/desks/desktop_set_white_down_coding-1.png +0 -0
  85. package/dashboard/public/assets/desks/desktop_set_white_down_coding.png +0 -0
  86. package/dashboard/public/assets/desks/desktop_set_white_up.png +0 -0
  87. package/dashboard/public/assets/furniture/armchair_tan.png +0 -0
  88. package/dashboard/public/assets/furniture/armchair_tan_down.png +0 -0
  89. package/dashboard/public/assets/furniture/backpack_blue.png +0 -0
  90. package/dashboard/public/assets/furniture/backpack_red.png +0 -0
  91. package/dashboard/public/assets/furniture/blinds.png +0 -0
  92. package/dashboard/public/assets/furniture/blinds_large_closed_white.png +0 -0
  93. package/dashboard/public/assets/furniture/bookshelf.png +0 -0
  94. package/dashboard/public/assets/furniture/bookshelf_purple_tall.png +0 -0
  95. package/dashboard/public/assets/furniture/bulletin_board.png +0 -0
  96. package/dashboard/public/assets/furniture/clock.png +0 -0
  97. package/dashboard/public/assets/furniture/coffee_mug.png +0 -0
  98. package/dashboard/public/assets/furniture/coffee_mug_blue.png +0 -0
  99. package/dashboard/public/assets/furniture/coffee_table.png +0 -0
  100. package/dashboard/public/assets/furniture/coffeepot_right.png +0 -0
  101. package/dashboard/public/assets/furniture/coffeetable_black_horizontal.png +0 -0
  102. package/dashboard/public/assets/furniture/couch.png +0 -0
  103. package/dashboard/public/assets/furniture/couch_tan_down.png +0 -0
  104. package/dashboard/public/assets/furniture/cushion_blue.png +0 -0
  105. package/dashboard/public/assets/furniture/cushion_tan.png +0 -0
  106. package/dashboard/public/assets/furniture/desk_wood.png +0 -0
  107. package/dashboard/public/assets/furniture/fancy_rug.png +0 -0
  108. package/dashboard/public/assets/furniture/fancy_rug_wide.png +0 -0
  109. package/dashboard/public/assets/furniture/flowers1.png +0 -0
  110. package/dashboard/public/assets/furniture/flowers2.png +0 -0
  111. package/dashboard/public/assets/furniture/lamp_tan.png +0 -0
  112. package/dashboard/public/assets/furniture/lantern.png +0 -0
  113. package/dashboard/public/assets/furniture/monstera.png +0 -0
  114. package/dashboard/public/assets/furniture/monstera_small.png +0 -0
  115. package/dashboard/public/assets/furniture/picture_frame.png +0 -0
  116. package/dashboard/public/assets/furniture/plant1.png +0 -0
  117. package/dashboard/public/assets/furniture/plant2.png +0 -0
  118. package/dashboard/public/assets/furniture/plant3.png +0 -0
  119. package/dashboard/public/assets/furniture/plant_poof.png +0 -0
  120. package/dashboard/public/assets/furniture/plant_spindly.png +0 -0
  121. package/dashboard/public/assets/furniture/poster_blue.png +0 -0
  122. package/dashboard/public/assets/furniture/rug.png +0 -0
  123. package/dashboard/public/assets/furniture/succulent_blue.png +0 -0
  124. package/dashboard/public/assets/furniture/succulent_green.png +0 -0
  125. package/dashboard/public/assets/furniture/treasurechest_closed_gold.png +0 -0
  126. package/dashboard/public/assets/furniture/water_cooler_better.png +0 -0
  127. package/dashboard/public/assets/furniture/whiteboard.png +0 -0
  128. package/dashboard/public/assets/furniture/whiteboard_stand_graph.png +0 -0
  129. package/dashboard/public/assets/furniture/window_blinds_open.png +0 -0
  130. package/dashboard/src/App.tsx +46 -0
  131. package/dashboard/src/components/RunDashboardButton.tsx +92 -0
  132. package/dashboard/src/components/SquadCard.tsx +49 -0
  133. package/dashboard/src/components/SquadSelector.tsx +67 -0
  134. package/dashboard/src/components/StatusBadge.tsx +32 -0
  135. package/dashboard/src/components/StatusBar.tsx +116 -0
  136. package/dashboard/src/hooks/useSquadSocket.ts +135 -0
  137. package/dashboard/src/lib/formatTime.ts +16 -0
  138. package/dashboard/src/lib/normalizeState.ts +25 -0
  139. package/dashboard/src/main.tsx +10 -0
  140. package/dashboard/src/office/AgentSprite.ts +241 -0
  141. package/dashboard/src/office/OfficeScene.ts +153 -0
  142. package/dashboard/src/office/PhaserGame.tsx +80 -0
  143. package/dashboard/src/office/RoomBuilder.ts +190 -0
  144. package/dashboard/src/office/assetKeys.ts +150 -0
  145. package/dashboard/src/office/palette.ts +32 -0
  146. package/dashboard/src/plugin/squadWatcher.ts +397 -0
  147. package/dashboard/src/store/useSquadStore.ts +56 -0
  148. package/dashboard/src/styles/globals.css +36 -0
  149. package/dashboard/src/types/state.ts +63 -0
  150. package/dashboard/src/vite-env.d.ts +1 -0
  151. package/dashboard/tsconfig.json +24 -0
  152. package/dashboard/vite.config.ts +13 -0
  153. package/package.json +59 -0
  154. package/public/sfx/slide-transition-sfx.mp3 +0 -0
  155. package/skills/README.md +84 -0
  156. package/skills/apify/SKILL.md +55 -0
  157. package/skills/blotato/SKILL.md +63 -0
  158. package/skills/canva/SKILL.md +60 -0
  159. package/skills/higgsfield/SKILL.md +147 -0
  160. package/skills/image-ai-generator/SKILL.md +124 -0
  161. package/skills/image-ai-generator/scripts/generate.py +175 -0
  162. package/skills/image-creator/SKILL.md +166 -0
  163. package/skills/image-creator/editorial-slide-template.js +645 -0
  164. package/skills/image-fetcher/SKILL.md +91 -0
  165. package/skills/imgbb-uploader/SKILL.md +73 -0
  166. package/skills/imgbb-uploader/scripts/upload.js +125 -0
  167. package/skills/instagram-publisher/README.md +36 -0
  168. package/skills/instagram-publisher/SKILL.md +231 -0
  169. package/skills/instagram-publisher/scripts/publish-playwright.js +418 -0
  170. package/skills/instagram-publisher/scripts/publish.js +521 -0
  171. package/skills/opensquad-agent-creator/SKILL.md +192 -0
  172. package/skills/opensquad-skill-creator/SKILL.md +420 -0
  173. package/skills/opensquad-skill-creator/agents/analyzer.md +274 -0
  174. package/skills/opensquad-skill-creator/agents/comparator.md +202 -0
  175. package/skills/opensquad-skill-creator/agents/grader.md +223 -0
  176. package/skills/opensquad-skill-creator/assets/eval_review.html +146 -0
  177. package/skills/opensquad-skill-creator/eval-viewer/generate_review.py +471 -0
  178. package/skills/opensquad-skill-creator/eval-viewer/viewer.html +1325 -0
  179. package/skills/opensquad-skill-creator/references/schemas.md +430 -0
  180. package/skills/opensquad-skill-creator/references/skill-format.md +235 -0
  181. package/skills/opensquad-skill-creator/scripts/__init__.py +0 -0
  182. package/skills/opensquad-skill-creator/scripts/aggregate_benchmark.py +401 -0
  183. package/skills/opensquad-skill-creator/scripts/quick_validate.py +103 -0
  184. package/skills/opensquad-skill-creator/scripts/run_eval.py +310 -0
  185. package/skills/opensquad-skill-creator/scripts/utils.py +47 -0
  186. package/skills/pdf-extractor/SKILL.md +57 -0
  187. package/skills/pdf-extractor/scripts/extract.py +82 -0
  188. package/skills/resend/SKILL.md +80 -0
  189. package/skills/run-dashboard/README.md +93 -0
  190. package/skills/run-dashboard/SKILL.md +173 -0
  191. package/skills/run-dashboard/scripts/finalize-state.js +273 -0
  192. package/skills/run-dashboard/scripts/generate.js +1296 -0
  193. package/skills/run-dashboard/scripts/serve.js +135 -0
  194. package/skills/run-dashboard/templates/run-dashboard-simple.template.html +191 -0
  195. package/skills/run-dashboard/templates/run-dashboard.template.html +1164 -0
  196. package/skills/smtp-sender/SKILL.md +88 -0
  197. package/skills/smtp-sender/scripts/send.js +478 -0
  198. package/skills/template-designer/SKILL.md +201 -0
  199. package/skills/template-designer/base-templates/model-a.html +27 -0
  200. package/skills/template-designer/base-templates/model-b.html +31 -0
  201. package/skills/template-designer/base-templates/model-c.html +42 -0
  202. package/skills/youtube-publisher/SKILL.md +232 -0
  203. package/skills/youtube-publisher/scripts/publish.js +2078 -0
  204. package/src/agents-cli.js +158 -0
  205. package/src/agents.js +134 -0
  206. package/src/i18n.js +48 -0
  207. package/src/init.js +442 -0
  208. package/src/locales/en.json +79 -0
  209. package/src/locales/es.json +78 -0
  210. package/src/locales/pt-BR.json +78 -0
  211. package/src/logger.js +38 -0
  212. package/src/prompt.js +46 -0
  213. package/src/readme/README.md +146 -0
  214. package/src/runs.js +318 -0
  215. package/src/skills-cli.js +157 -0
  216. package/src/skills.js +146 -0
  217. package/src/supabase-cli.js +584 -0
  218. package/src/update.js +169 -0
  219. package/templates/_opensquad/.opensquad-version +1 -0
  220. package/templates/_opensquad/_investigations/.gitkeep +0 -0
  221. package/templates/ide-templates/antigravity/.agent/rules/opensquad.md +68 -0
  222. package/templates/ide-templates/antigravity/.agent/workflows/opensquad.md +102 -0
  223. package/templates/ide-templates/claude-code/.claude/skills/opensquad/SKILL.md +182 -0
  224. package/templates/ide-templates/claude-code/.mcp.json +8 -0
  225. package/templates/ide-templates/claude-code/CLAUDE.md +57 -0
  226. package/templates/ide-templates/codex/.agents/skills/opensquad/SKILL.md +6 -0
  227. package/templates/ide-templates/codex/AGENTS.md +120 -0
  228. package/templates/ide-templates/cursor/.cursor/commands/opensquad.md +9 -0
  229. package/templates/ide-templates/cursor/.cursor/mcp.json +8 -0
  230. package/templates/ide-templates/cursor/.cursor/rules/opensquad.mdc +62 -0
  231. package/templates/ide-templates/cursor/.cursorignore +3 -0
  232. package/templates/ide-templates/gemini-cli/.gemini/settings.json +8 -0
  233. package/templates/ide-templates/gemini-cli/.gemini/skills/opensquad/SKILL.md +186 -0
  234. package/templates/ide-templates/gemini-cli/GEMINI.md +57 -0
  235. package/templates/ide-templates/opencode/.opencode/commands/opensquad.md +9 -0
  236. package/templates/ide-templates/opencode/AGENTS.md +120 -0
  237. package/templates/ide-templates/qwen-code/.qwen/settings.json +8 -0
  238. package/templates/ide-templates/qwen-code/.qwen/skills/opensquad/SKILL.md +182 -0
  239. package/templates/ide-templates/qwen-code/QWEN.md +57 -0
  240. package/templates/ide-templates/trae/.trae/mcp.json +8 -0
  241. package/templates/ide-templates/trae/.trae/rules/opensquad.md +64 -0
  242. package/templates/ide-templates/vscode-copilot/.github/copilot-instructions.md +59 -0
  243. package/templates/ide-templates/vscode-copilot/.github/prompts/opensquad.prompt.md +209 -0
  244. package/templates/ide-templates/vscode-copilot/.vscode/mcp.json +8 -0
  245. package/templates/ide-templates/vscode-copilot/.vscode/settings.json +3 -0
  246. package/templates/package.json +8 -0
  247. package/templates/squads/.gitkeep +0 -0
@@ -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, '_opensquad'));
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 Opensquad 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/julioventura/opensquad/tree/main/agents\n`);
81
+ }
82
+
83
+ async function runInstall(id, targetDir) {
84
+ if (!id) {
85
+ console.log('\n Usage: opensquad 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: opensquad 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: opensquad 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
+ }