@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
package/src/init.js ADDED
@@ -0,0 +1,442 @@
1
+ import { cp, mkdir, readdir, readFile, writeFile, stat } from 'node:fs/promises';
2
+ import { join, dirname } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { execSync } from 'node:child_process';
5
+ import { createPrompt } from './prompt.js';
6
+ import { loadLocale, t } from './i18n.js';
7
+ import { listAvailable, installSkill } from './skills.js';
8
+ import { logEvent } from './logger.js';
9
+
10
+ const __dirname = dirname(fileURLToPath(import.meta.url));
11
+ const TEMPLATES_DIR = join(__dirname, '..', 'templates');
12
+
13
+ const PACKAGE_ROOT = join(__dirname, '..');
14
+
15
+ const CANONICAL_SOURCES = [
16
+ { src: join(PACKAGE_ROOT, '_opensquad', 'core'), dest: join('_opensquad', 'core') },
17
+ { src: join(PACKAGE_ROOT, '_opensquad', 'config'), dest: join('_opensquad', 'config') },
18
+ { src: join(PACKAGE_ROOT, 'dashboard'), dest: 'dashboard' },
19
+ ];
20
+
21
+ const DASHBOARD_EXCLUDES = ['node_modules', 'dist', 'test-results', 'tsconfig.tsbuildinfo', 'squads'];
22
+
23
+ const LANGUAGES = [
24
+ { label: 'Português (Brasil)', value: 'Português (Brasil)' },
25
+ { label: 'English', value: 'English' },
26
+ { label: 'Español', value: 'Español' },
27
+ ];
28
+
29
+ const IDES = [
30
+ { label: 'Antigravity', value: 'antigravity', checked: true },
31
+ { label: 'Claude Code', value: 'claude-code' },
32
+ { label: 'Codex (OpenAI)', value: 'codex' },
33
+ { label: 'Cursor', value: 'cursor' },
34
+ { label: 'Gemini CLI', value: 'gemini-cli' },
35
+ { label: 'OpenCode', value: 'opencode' },
36
+ { label: 'Qwen Code', value: 'qwen-code' },
37
+ { label: 'Trae', value: 'trae' },
38
+ { label: 'VS Code + Copilot', value: 'vscode-copilot' },
39
+ ];
40
+
41
+ export async function init(targetDir, options = {}) {
42
+
43
+ // Check if already initialized
44
+ let isReInit = false;
45
+ try {
46
+ await stat(join(targetDir, '_opensquad'));
47
+ isReInit = true;
48
+ } catch {
49
+ // Not initialized yet — continue
50
+ }
51
+
52
+ console.log(isReInit ? '\n 🔄 Opensquad — Re-configure\n' : '\n 🟢 Opensquad — Setup\n');
53
+
54
+ // Guided installation (skip in test mode)
55
+ let language = options._language || 'English';
56
+ let ides = options._ides ?? ['claude-code'];
57
+ let userName = '';
58
+
59
+ if (!options._skipPrompts) {
60
+ const prompt = createPrompt();
61
+
62
+ try {
63
+ // Language is asked FIRST (in English, before locale is loaded)
64
+ const langChoice = await prompt.choose('What language do you prefer for outputs?', LANGUAGES);
65
+ language = langChoice.value;
66
+
67
+ // Load locale — all messages from here are translated
68
+ await loadLocale(language);
69
+
70
+ console.log(`\n ${t('welcome')}\n`);
71
+
72
+ userName = (await prompt.ask(` ${t('askName')}`)).trim();
73
+
74
+ ides = await prompt.multiChoose(t('chooseIdes'), IDES);
75
+ } finally {
76
+ prompt.close();
77
+ }
78
+ } else {
79
+ await loadLocale(language);
80
+ }
81
+
82
+ // Copy template files
83
+ await copyCommonTemplates(targetDir);
84
+ await copyCanonicalSources(targetDir);
85
+ await copyIdeTemplates(ides, targetDir);
86
+ await installAllSkills(targetDir);
87
+ if (!options._skipPrompts) {
88
+ await installDependencies(targetDir);
89
+ }
90
+ await writeProjectReadme(targetDir);
91
+
92
+ // Write user preferences
93
+ const prefsPath = join(targetDir, '_opensquad', '_memory', 'preferences.md');
94
+ await mkdir(dirname(prefsPath), { recursive: true });
95
+ const prefsContent = `# Opensquad Preferences
96
+
97
+ - **User Name:** ${userName}
98
+ - **Output Language:** ${language}
99
+ - **IDEs:** ${ides.join(', ')}
100
+ - **Date Format:** YYYY-MM-DD
101
+ `;
102
+ await writeFile(prefsPath, prefsContent, 'utf-8');
103
+
104
+ await logEvent('init', { language, ides: ides.join(',') }, targetDir);
105
+
106
+ console.log(`\n ${t('success')}\n`);
107
+ console.log(` ⚠️ ${t('tokenCostWarning')}\n`);
108
+ console.log(` ${t('nextSteps')}`);
109
+ for (const ide of ides) {
110
+ if (ide === 'claude-code') {
111
+ console.log(` ${t('step1ClaudeCode')}`);
112
+ console.log(` ${t('step2ClaudeCode')}`);
113
+ console.log(` ${t('step3ClaudeCode')}\n`);
114
+ } else if (ide === 'codex') {
115
+ console.log(` ${t('step1Codex')}\n`);
116
+ } else if (ide === 'antigravity') {
117
+ console.log(` ${t('step1Antigravity')}\n`);
118
+ } else if (ide === 'cursor') {
119
+ console.log(` ${t('step1Cursor')}\n`);
120
+ } else if (ide === 'opencode') {
121
+ console.log(` ${t('step1Opencode')}\n`);
122
+ } else if (ide === 'vscode-copilot') {
123
+ console.log(` ${t('step1VsCodeCopilot')}`);
124
+ console.log(` ${t('step2VsCodeCopilot')}`);
125
+ console.log(` ${t('step3VsCodeCopilot')}\n`);
126
+ } else if (ide === 'gemini-cli') {
127
+ console.log(` ${t('step1GeminiCli')}`);
128
+ console.log(` ${t('step2GeminiCli')}\n`);
129
+ } else if (ide === 'qwen-code') {
130
+ console.log(` ${t('step1QwenCode')}`);
131
+ console.log(` ${t('step2QwenCode')}\n`);
132
+ } else if (ide === 'trae') {
133
+ console.log(` ${t('step1Trae')}`);
134
+ console.log(` ${t('step2Trae')}\n`);
135
+ }
136
+ }
137
+ }
138
+
139
+ export async function loadSavedLocale(targetDir) {
140
+ try {
141
+ const prefsPath = join(targetDir, '_opensquad', '_memory', 'preferences.md');
142
+ const content = await readFile(prefsPath, 'utf-8');
143
+ const match = content.match(/\*\*Output Language:\*\*\s*(.+)/);
144
+ if (match) {
145
+ await loadLocale(match[1].trim());
146
+ return;
147
+ }
148
+ } catch {
149
+ // No preferences file yet
150
+ }
151
+ await loadLocale('English');
152
+ }
153
+
154
+ async function installAllSkills(targetDir) {
155
+ const available = await listAvailable();
156
+ for (const id of available) {
157
+ await installSkill(id, targetDir);
158
+ console.log(` ${t('createdFile', { path: `skills/${id}/SKILL.md` })}`);
159
+ }
160
+ }
161
+
162
+ async function installDependencies(targetDir) {
163
+ console.log(`\n Installing dependencies...`);
164
+ execSync('npm install', { cwd: targetDir, stdio: 'inherit' });
165
+ console.log(`\n Installing dashboard dependencies...`);
166
+ execSync('npm install', { cwd: join(targetDir, 'dashboard'), stdio: 'inherit' });
167
+ console.log(`\n Installing Playwright browsers...`);
168
+ execSync('npx playwright install chromium', { cwd: targetDir, stdio: 'inherit' });
169
+ }
170
+
171
+ async function writeProjectReadme(targetDir) {
172
+ const destPath = join(targetDir, 'README.md');
173
+ try {
174
+ await stat(destPath);
175
+ // README already exists — skip to avoid overwriting user content
176
+ return;
177
+ } catch {
178
+ // does not exist — write it
179
+ }
180
+ const readmePath = join(__dirname, 'readme', 'README.md');
181
+ const content = await readFile(readmePath, 'utf-8');
182
+ await writeFile(destPath, content, 'utf-8');
183
+ }
184
+
185
+ async function copyCommonTemplates(targetDir) {
186
+ const entries = await getTemplateEntries(TEMPLATES_DIR);
187
+
188
+ for (const entry of entries) {
189
+ // Skip anything inside ide-templates/ — handled by copyIdeTemplates
190
+ if (entry.replace(/\\/g, '/').includes('/ide-templates/')) continue;
191
+
192
+ const relativePath = entry.slice(TEMPLATES_DIR.length + 1);
193
+ const destPath = join(targetDir, relativePath);
194
+ const destDir = dirname(destPath);
195
+ await mkdir(destDir, { recursive: true });
196
+ try {
197
+ await stat(destPath);
198
+ continue; // file already exists — skip
199
+ } catch {
200
+ // does not exist — copy it
201
+ }
202
+ await cp(entry, destPath);
203
+ console.log(` ${t('createdFile', { path: relativePath })}`);
204
+ }
205
+ }
206
+
207
+ async function copyIdeTemplates(ides, targetDir) {
208
+ const ideTemplatesDir = join(TEMPLATES_DIR, 'ide-templates');
209
+ const writtenPaths = new Set();
210
+
211
+ for (const ide of ides) {
212
+ const ideSrcDir = join(ideTemplatesDir, ide);
213
+ let entries;
214
+ try {
215
+ entries = await getTemplateEntries(ideSrcDir);
216
+ } catch {
217
+ continue; // no template dir for this IDE yet
218
+ }
219
+
220
+ for (const entry of entries) {
221
+ const relativePath = entry.slice(ideSrcDir.length + 1);
222
+ // settings.json for vscode-copilot is handled by mergeVsCodeSettings — skip here
223
+ if (ide === 'vscode-copilot' && relativePath.replace(/\\/g, '/') === '.vscode/settings.json') continue;
224
+ if (ide === 'qwen-code' && relativePath.replace(/\\/g, '/') === '.qwen/settings.json') continue;
225
+ if (ide === 'gemini-cli' && relativePath.replace(/\\/g, '/') === '.gemini/settings.json') continue;
226
+ if (writtenPaths.has(relativePath)) continue;
227
+ writtenPaths.add(relativePath);
228
+
229
+ const destPath = join(targetDir, relativePath);
230
+ const destDir = dirname(destPath);
231
+ await mkdir(destDir, { recursive: true });
232
+ try {
233
+ await stat(destPath);
234
+ continue; // file already exists — skip
235
+ } catch {
236
+ // does not exist — copy it
237
+ }
238
+ await cp(entry, destPath);
239
+ console.log(` ${t('createdFile', { path: relativePath })}`);
240
+ }
241
+ }
242
+
243
+ if (ides.includes('vscode-copilot')) {
244
+ await mergeVsCodeSettings(targetDir);
245
+ }
246
+
247
+ if (ides.includes('qwen-code')) {
248
+ await mergeQwenSettings(targetDir);
249
+ }
250
+ if (ides.includes('gemini-cli')) {
251
+ await mergeGeminiSettings(targetDir);
252
+ }
253
+ }
254
+
255
+ async function mergeVsCodeSettings(targetDir) {
256
+ const settingsPath = join(targetDir, '.vscode', 'settings.json');
257
+
258
+ let exists = false;
259
+ try {
260
+ await stat(settingsPath);
261
+ exists = true;
262
+ } catch {
263
+ // doesn't exist
264
+ }
265
+
266
+ if (!exists) {
267
+ const templateBase = join(TEMPLATES_DIR, 'ide-templates', 'vscode-copilot', '.vscode', 'settings.json');
268
+ await mkdir(join(targetDir, '.vscode'), { recursive: true });
269
+ await cp(templateBase, settingsPath);
270
+ return;
271
+ }
272
+
273
+ const raw = await readFile(settingsPath, 'utf-8');
274
+ let parsed;
275
+ try {
276
+ parsed = JSON.parse(raw);
277
+ } catch {
278
+ console.log(` ⚠️ .vscode/settings.json has invalid JSON — skipping merge. Add manually: "chat.promptFilesLocations": [".github/prompts"]`);
279
+ return;
280
+ }
281
+
282
+ if (!parsed['chat.promptFilesLocations']) {
283
+ parsed['chat.promptFilesLocations'] = ['.github/prompts'];
284
+ } else if (!parsed['chat.promptFilesLocations'].includes('.github/prompts')) {
285
+ parsed['chat.promptFilesLocations'].push('.github/prompts');
286
+ }
287
+
288
+ await writeFile(settingsPath, JSON.stringify(parsed, null, 2), 'utf-8');
289
+ }
290
+
291
+ async function mergeQwenSettings(targetDir) {
292
+ const settingsPath = join(targetDir, '.qwen', 'settings.json');
293
+
294
+ let exists = false;
295
+ try {
296
+ await stat(settingsPath);
297
+ exists = true;
298
+ } catch {
299
+ // doesn't exist
300
+ }
301
+
302
+ if (!exists) {
303
+ const templateBase = join(TEMPLATES_DIR, 'ide-templates', 'qwen-code', '.qwen', 'settings.json');
304
+ await mkdir(join(targetDir, '.qwen'), { recursive: true });
305
+ await cp(templateBase, settingsPath);
306
+ return;
307
+ }
308
+
309
+ const raw = await readFile(settingsPath, 'utf-8');
310
+ let parsed;
311
+ try {
312
+ parsed = JSON.parse(raw);
313
+ } catch {
314
+ console.log(` ⚠️ .qwen/settings.json has invalid JSON — skipping merge. Add manually: "mcpServers": { "playwright": { ... } }`);
315
+ return;
316
+ }
317
+
318
+ if (!parsed.mcpServers) {
319
+ parsed.mcpServers = {};
320
+ }
321
+ if (!parsed.mcpServers.playwright) {
322
+ parsed.mcpServers.playwright = {
323
+ command: 'npx',
324
+ args: ['@playwright/mcp@latest', '--config', '_opensquad/config/playwright.config.json'],
325
+ };
326
+ }
327
+
328
+ await writeFile(settingsPath, JSON.stringify(parsed, null, 2), 'utf-8');
329
+ }
330
+
331
+ async function mergeGeminiSettings(targetDir) {
332
+ const settingsPath = join(targetDir, '.gemini', 'settings.json');
333
+
334
+ let exists = false;
335
+ try {
336
+ await stat(settingsPath);
337
+ exists = true;
338
+ } catch {
339
+ // doesn't exist
340
+ }
341
+
342
+ if (!exists) {
343
+ const templateBase = join(TEMPLATES_DIR, 'ide-templates', 'gemini-cli', '.gemini', 'settings.json');
344
+ await mkdir(join(targetDir, '.gemini'), { recursive: true });
345
+ await cp(templateBase, settingsPath);
346
+ return;
347
+ }
348
+
349
+ const raw = await readFile(settingsPath, 'utf-8');
350
+ let parsed;
351
+ try {
352
+ parsed = JSON.parse(raw);
353
+ } catch {
354
+ console.log(` ⚠️ .gemini/settings.json has invalid JSON — skipping merge. Add manually: "mcpServers": { "playwright": { ... } }`);
355
+ return;
356
+ }
357
+
358
+ if (!parsed.mcpServers) {
359
+ parsed.mcpServers = {};
360
+ }
361
+ if (!parsed.mcpServers.playwright) {
362
+ parsed.mcpServers.playwright = {
363
+ command: 'npx',
364
+ args: ['@playwright/mcp@latest', '--config', '_opensquad/config/playwright.config.json'],
365
+ };
366
+ }
367
+
368
+ await writeFile(settingsPath, JSON.stringify(parsed, null, 2), 'utf-8');
369
+ }
370
+
371
+ export async function getTemplateEntries(dir) {
372
+ const results = [];
373
+ const entries = await readdir(dir, { withFileTypes: true });
374
+
375
+ for (const entry of entries) {
376
+ const fullPath = join(dir, entry.name);
377
+ if (entry.isDirectory()) {
378
+ results.push(...await getTemplateEntries(fullPath));
379
+ } else {
380
+ results.push(fullPath);
381
+ }
382
+ }
383
+
384
+ return results;
385
+ }
386
+
387
+ export async function copyCanonicalSources(targetDir, { overwrite = false, backupFn = null, protectedFn = null } = {}) {
388
+ let count = 0;
389
+
390
+ for (const { src, dest } of CANONICAL_SOURCES) {
391
+ const isDashboard = dest === 'dashboard';
392
+ let entries;
393
+ try {
394
+ entries = await getTemplateEntries(src);
395
+ } catch {
396
+ continue; // source dir doesn't exist (e.g., running from a partial install)
397
+ }
398
+
399
+ for (const entry of entries) {
400
+ const relativeToSrc = entry.slice(src.length + 1);
401
+ const normalizedRel = relativeToSrc.replace(/\\/g, '/');
402
+
403
+ // Skip dashboard-local artifacts
404
+ if (isDashboard && DASHBOARD_EXCLUDES.some(ex => normalizedRel === ex || normalizedRel.startsWith(ex + '/'))) {
405
+ continue;
406
+ }
407
+
408
+ const relativePath = join(dest, relativeToSrc);
409
+ const normalizedPath = relativePath.replace(/\\/g, '/');
410
+
411
+ // Skip protected paths (update mode)
412
+ if (protectedFn && protectedFn(normalizedPath)) continue;
413
+
414
+ const destPath = join(targetDir, relativePath);
415
+ await mkdir(dirname(destPath), { recursive: true });
416
+
417
+ if (!overwrite) {
418
+ // Init mode: skip existing files
419
+ try {
420
+ await stat(destPath);
421
+ continue;
422
+ } catch {
423
+ // does not exist — copy it
424
+ }
425
+ await cp(entry, destPath);
426
+ console.log(` ${t('createdFile', { path: normalizedPath })}`);
427
+ } else {
428
+ // Update mode: backup then overwrite
429
+ const backed = backupFn ? await backupFn(destPath) : false;
430
+ await cp(entry, destPath);
431
+ if (backed) {
432
+ console.log(` ${t('updatedFile', { path: normalizedPath })} (backup: ${normalizedPath}.bak)`);
433
+ } else {
434
+ console.log(` ${t('updatedFile', { path: normalizedPath })}`);
435
+ }
436
+ }
437
+ count++;
438
+ }
439
+ }
440
+
441
+ return count;
442
+ }
@@ -0,0 +1,79 @@
1
+ {
2
+ "welcome": "Welcome! Let's set up Opensquad for your project.",
3
+ "askName": "What's your name? → ",
4
+ "atLeastOneIde": "Please select at least one IDE.",
5
+ "chooseIdes": "Which IDEs/tools do you use? (select all that apply)",
6
+ "step1Codex": "1. See AGENTS.md in your project root for Codex instructions",
7
+ "step1Antigravity": "1. Open Antigravity, type / in the chat and select opensquad to get started.",
8
+ "step1Cursor": "1. Open Cursor, type / in the chat and select opensquad to get started.",
9
+ "step1Opencode": "1. Open OpenCode and type /opensquad to get started.",
10
+ "ideNotAvailable": "⚠️ \"{label}\" is not available yet. Choose another option.",
11
+ "enterNumber": "Please enter a number between 1 and {max}.",
12
+ "alreadyInitialized": "⚠️ Opensquad is already initialized in this directory.",
13
+ "alreadyInitializedHint": "Use Claude Code and type /opensquad to get started.",
14
+ "createdFile": "📄 Created {path}",
15
+ "success": "✅ Opensquad initialized successfully!",
16
+ "nextSteps": "Next steps:",
17
+ "step1ClaudeCode": "1. Open this directory in Claude Code",
18
+ "step2ClaudeCode": "2. Type /opensquad to start the onboarding wizard",
19
+ "step3ClaudeCode": "3. Follow the prompts to set up your company profile",
20
+ "comingSoon": "coming soon",
21
+ "_test_fallback_only": "English fallback works",
22
+ "updateNotInitialized": "No Opensquad installation found. Run 'init' first.",
23
+ "updateStarting": "Updating Opensquad {old} → {new}...",
24
+ "updateStartingUnknown": "Updating Opensquad (unknown version) → {new}...",
25
+ "updatedFile": "📄 Updated {path}",
26
+ "updateSuccess": "✅ Opensquad {version} installed successfully!",
27
+ "updatePreserved": "✓ Preserved: _memory/, _investigations/, squads/",
28
+ "updateFileCount": "✓ Updated: {count} system files",
29
+ "updateLatestHint": "💡 Tip: Use 'npx @julioventura/opensquad@latest update' to always get the newest version.",
30
+ "skillsNotInitialized": "No Opensquad installation found. Run 'init' first.",
31
+ "skillsFetching": "Fetching skills registry...",
32
+ "skillsInstalledHeader": "Installed:",
33
+ "skillsAvailableHeader": "Available:",
34
+ "skillsNoneInstalled": "No skills installed yet.",
35
+ "skillsNoneAvailable": "No skills available in registry.",
36
+ "skillsInstallHint": "Install with: npx @julioventura/opensquad install <id>",
37
+ "skillsInstalling": "Installing {id}...",
38
+ "skillsInstalled": "✅ Installed: {id}",
39
+ "skillsAlreadyInstalled": "⚠️ {id} is already installed. Reinstall? (y/n) ",
40
+ "skillsReinstalled": "✅ Reinstalled: {id}",
41
+ "skillsRemoving": "Removing {id}...",
42
+ "skillsRemoved": "✅ Removed: {id}",
43
+ "skillsNotInstalled": "⚠️ {id} is not installed.",
44
+ "skillsUpdating": "Updating all installed skills...",
45
+ "skillsUpdateDone": "✅ Updated {count} skill(s).",
46
+ "skillsUpdateNone": "No skills installed to update.",
47
+ "skillsError": "❌ Error: {message}",
48
+ "skillsUnknownCommand": "Unknown skills command: {cmd}\n Usage: opensquad skills list|install|remove|update",
49
+ "chooseSkills": "Which skills do you want to install? (optional)",
50
+ "skillsEnvWarning": " Requires: {vars}",
51
+ "skillsSkipped": "You can install skills later with: npx @julioventura/opensquad install <name>",
52
+ "skillsInstalledCount": "Installed {count} skill(s).",
53
+ "agentsNotInitialized": "No Opensquad installation found. Run 'init' first.",
54
+ "agentsInstalledHeader": "Installed:",
55
+ "agentsNoneInstalled": "No agents installed yet.",
56
+ "agentsInstallHint": "Install with: npx @julioventura/opensquad agents install <id>",
57
+ "agentsInstalling": "Installing {id}...",
58
+ "agentsInstalled": "✅ Installed: {id}",
59
+ "agentsAlreadyInstalled": "⚠️ {id} is already installed. Reinstall? (y/n) ",
60
+ "agentsReinstalled": "✅ Reinstalled: {id}",
61
+ "agentsRemoving": "Removing {id}...",
62
+ "agentsRemoved": "✅ Removed: {id}",
63
+ "agentsNotInstalled": "⚠️ {id} is not installed.",
64
+ "agentsUpdating": "Updating all installed agents...",
65
+ "agentsUpdateDone": "✅ Updated {count} agent(s).",
66
+ "agentsUpdateNone": "No agents installed to update.",
67
+ "agentsError": "❌ Error: {message}",
68
+ "agentsUnknownCommand": "Unknown agents command: {cmd}\n Usage: opensquad agents list|install|remove|update",
69
+ "step1VsCodeCopilot": "1. Open this directory in VS Code",
70
+ "step2VsCodeCopilot": "2. Open Copilot Chat (Ctrl+Alt+I)",
71
+ "step3VsCodeCopilot": "3. Type /opensquad to get started",
72
+ "step1QwenCode": "1. Open this directory in Qwen Code",
73
+ "step2QwenCode": "2. Type /opensquad to get started",
74
+ "step1GeminiCli": "1. Open this directory in Gemini CLI",
75
+ "step2GeminiCli": "2. Type /opensquad to get started",
76
+ "step1Trae": "1. Open this project in Trae",
77
+ "step2Trae": "2. Type /opensquad in the chat to get started",
78
+ "tokenCostWarning": "Running squads consumes AI tokens (paid). Monitor your usage in your IDE or AI provider dashboard."
79
+ }
@@ -0,0 +1,78 @@
1
+ {
2
+ "welcome": "¡Bienvenido! Vamos a configurar Opensquad para tu proyecto.",
3
+ "askName": "¿Cuál es tu nombre? → ",
4
+ "atLeastOneIde": "Por favor selecciona al menos una IDE.",
5
+ "chooseIdes": "¿Qué IDEs/herramientas usas? (selecciona todas las que uses)",
6
+ "step1Codex": "1. Consulta AGENTS.md en la raíz del proyecto para instrucciones de Codex",
7
+ "step1Antigravity": "1. Abre Antigravity, escribe / en el chat y selecciona opensquad para comenzar.",
8
+ "step1Cursor": "1. Abre Cursor, escribe / en el chat y selecciona opensquad para comenzar.",
9
+ "step1Opencode": "1. Abre OpenCode y escribe /opensquad para comenzar.",
10
+ "ideNotAvailable": "⚠️ \"{label}\" aún no está disponible. Elige otra opción.",
11
+ "enterNumber": "Por favor, ingresa un número entre 1 y {max}.",
12
+ "alreadyInitialized": "⚠️ Opensquad ya está inicializado en este directorio.",
13
+ "alreadyInitializedHint": "Usa Claude Code y escribe /opensquad para comenzar.",
14
+ "createdFile": "📄 Creado {path}",
15
+ "success": "✅ ¡Opensquad inicializado con éxito!",
16
+ "nextSteps": "Próximos pasos:",
17
+ "step1ClaudeCode": "1. Abre este directorio en Claude Code",
18
+ "step2ClaudeCode": "2. Escribe /opensquad para iniciar el asistente",
19
+ "step3ClaudeCode": "3. Sigue las instrucciones para configurar el perfil de tu empresa",
20
+ "comingSoon": "próximamente",
21
+ "updateNotInitialized": "No se encontró ninguna instalación de Opensquad. Ejecute 'init' primero.",
22
+ "updateStarting": "Actualizando Opensquad {old} → {new}...",
23
+ "updateStartingUnknown": "Actualizando Opensquad (versión desconocida) → {new}...",
24
+ "updatedFile": "📄 Actualizado {path}",
25
+ "updateSuccess": "✅ ¡Opensquad {version} instalado correctamente!",
26
+ "updatePreserved": "✓ Preservado: _memory/, _investigations/, squads/",
27
+ "updateFileCount": "✓ Actualizados: {count} archivos del sistema",
28
+ "updateLatestHint": "💡 Consejo: Use 'npx @julioventura/opensquad@latest update' para obtener siempre la versión más reciente.",
29
+ "skillsNotInitialized": "Instalación de Opensquad no encontrada. Ejecuta 'init' primero.",
30
+ "skillsFetching": "Obteniendo registro de skills...",
31
+ "skillsInstalledHeader": "Instaladas:",
32
+ "skillsAvailableHeader": "Disponibles:",
33
+ "skillsNoneInstalled": "No hay skills instaladas todavía.",
34
+ "skillsNoneAvailable": "No hay skills disponibles en el registro.",
35
+ "skillsInstallHint": "Instala con: npx @julioventura/opensquad install <id>",
36
+ "skillsInstalling": "Instalando {id}...",
37
+ "skillsInstalled": "✅ Instalada: {id}",
38
+ "skillsAlreadyInstalled": "⚠️ {id} ya está instalada. ¿Reinstalar? (s/n) ",
39
+ "skillsReinstalled": "✅ Reinstalada: {id}",
40
+ "skillsRemoving": "Eliminando {id}...",
41
+ "skillsRemoved": "✅ Eliminada: {id}",
42
+ "skillsNotInstalled": "⚠️ {id} no está instalada.",
43
+ "skillsUpdating": "Actualizando todas las skills instaladas...",
44
+ "skillsUpdateDone": "✅ {count} skill(s) actualizada(s).",
45
+ "skillsUpdateNone": "No hay skills instaladas para actualizar.",
46
+ "skillsError": "❌ Error: {message}",
47
+ "skillsUnknownCommand": "Comando desconocido: {cmd}\n Uso: opensquad skills list|install|remove|update",
48
+ "chooseSkills": "¿Qué skills quieres instalar? (opcional)",
49
+ "skillsEnvWarning": " Requiere: {vars}",
50
+ "skillsSkipped": "Puedes instalar skills después con: npx @julioventura/opensquad install <nombre>",
51
+ "skillsInstalledCount": "{count} skill(s) instalada(s).",
52
+ "agentsNotInitialized": "Instalación de Opensquad no encontrada. Ejecuta 'init' primero.",
53
+ "agentsInstalledHeader": "Instalados:",
54
+ "agentsNoneInstalled": "No hay agents instalados todavía.",
55
+ "agentsInstallHint": "Instala con: npx @julioventura/opensquad agents install <id>",
56
+ "agentsInstalling": "Instalando {id}...",
57
+ "agentsInstalled": "✅ Instalado: {id}",
58
+ "agentsAlreadyInstalled": "⚠️ {id} ya está instalado. ¿Reinstalar? (s/n) ",
59
+ "agentsReinstalled": "✅ Reinstalado: {id}",
60
+ "agentsRemoving": "Eliminando {id}...",
61
+ "agentsRemoved": "✅ Eliminado: {id}",
62
+ "agentsNotInstalled": "⚠️ {id} no está instalado.",
63
+ "agentsUpdating": "Actualizando todos los agents instalados...",
64
+ "agentsUpdateDone": "✅ {count} agent(s) actualizado(s).",
65
+ "agentsUpdateNone": "No hay agents instalados para actualizar.",
66
+ "agentsError": "❌ Error: {message}",
67
+ "agentsUnknownCommand": "Comando desconocido: {cmd}\n Uso: opensquad agents list|install|remove|update",
68
+ "step1VsCodeCopilot": "1. Abre este directorio en VS Code",
69
+ "step2VsCodeCopilot": "2. Abre el Copilot Chat (Ctrl+Alt+I)",
70
+ "step3VsCodeCopilot": "3. Escribe /opensquad para empezar",
71
+ "step1QwenCode": "1. Abre este directorio en Qwen Code",
72
+ "step2QwenCode": "2. Escribe /opensquad para comenzar",
73
+ "step1GeminiCli": "1. Abre este directorio en Gemini CLI",
74
+ "step2GeminiCli": "2. Escribe /opensquad para comenzar",
75
+ "step1Trae": "1. Abre este proyecto en Trae",
76
+ "step2Trae": "2. Escribe /opensquad en el chat para comenzar",
77
+ "tokenCostWarning": "Ejecutar squads consume tokens de IA (de pago). Monitorea tu consumo en tu IDE o en el dashboard de tu proveedor de IA."
78
+ }