goiabaseeds 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/README.md +173 -0
  2. package/bin/goiabaseeds.js +98 -0
  3. package/eslint.config.js +14 -0
  4. package/package.json +61 -0
  5. package/skills/README.md +60 -0
  6. package/skills/apify/SKILL.md +55 -0
  7. package/skills/blotato/SKILL.md +63 -0
  8. package/skills/canva/SKILL.md +60 -0
  9. package/skills/goiabaseeds-agent-creator/SKILL.md +192 -0
  10. package/skills/goiabaseeds-skill-creator/SKILL.md +407 -0
  11. package/skills/goiabaseeds-skill-creator/agents/analyzer.md +274 -0
  12. package/skills/goiabaseeds-skill-creator/agents/comparator.md +202 -0
  13. package/skills/goiabaseeds-skill-creator/agents/grader.md +223 -0
  14. package/skills/goiabaseeds-skill-creator/assets/eval_review.html +146 -0
  15. package/skills/goiabaseeds-skill-creator/eval-viewer/generate_review.py +471 -0
  16. package/skills/goiabaseeds-skill-creator/eval-viewer/viewer.html +1325 -0
  17. package/skills/goiabaseeds-skill-creator/references/schemas.md +430 -0
  18. package/skills/goiabaseeds-skill-creator/references/skill-format.md +235 -0
  19. package/skills/goiabaseeds-skill-creator/scripts/__init__.py +0 -0
  20. package/skills/goiabaseeds-skill-creator/scripts/aggregate_benchmark.py +401 -0
  21. package/skills/goiabaseeds-skill-creator/scripts/quick_validate.py +103 -0
  22. package/skills/goiabaseeds-skill-creator/scripts/run_eval.py +310 -0
  23. package/skills/goiabaseeds-skill-creator/scripts/utils.py +47 -0
  24. package/skills/image-creator/SKILL.md +155 -0
  25. package/skills/image-fetcher/SKILL.md +91 -0
  26. package/skills/image-generator/SKILL.md +124 -0
  27. package/skills/image-generator/scripts/generate.py +175 -0
  28. package/skills/instagram-publisher/SKILL.md +118 -0
  29. package/skills/instagram-publisher/scripts/publish.js +164 -0
  30. package/src/agent-session.js +110 -0
  31. package/src/agents-cli.js +158 -0
  32. package/src/agents.js +134 -0
  33. package/src/bundle-detector.js +75 -0
  34. package/src/bundle.js +286 -0
  35. package/src/context.js +142 -0
  36. package/src/export.js +52 -0
  37. package/src/i18n.js +48 -0
  38. package/src/init.js +367 -0
  39. package/src/locales/en.json +72 -0
  40. package/src/locales/es.json +71 -0
  41. package/src/locales/pt-BR.json +71 -0
  42. package/src/logger.js +38 -0
  43. package/src/models-cli.js +165 -0
  44. package/src/pipeline-runner.js +478 -0
  45. package/src/prompt.js +46 -0
  46. package/src/provider.js +156 -0
  47. package/src/readme/README.md +181 -0
  48. package/src/run.js +100 -0
  49. package/src/runs.js +90 -0
  50. package/src/skills-cli.js +157 -0
  51. package/src/skills.js +146 -0
  52. package/src/state-manager.js +280 -0
  53. package/src/tools.js +158 -0
  54. package/src/update.js +140 -0
  55. package/templates/_goiabaseeds/.goiabaseeds-version +1 -0
  56. package/templates/_goiabaseeds/_investigations/.gitkeep +0 -0
  57. package/templates/_goiabaseeds/config/playwright.config.json +11 -0
  58. package/templates/_goiabaseeds/core/architect.agent.yaml +1141 -0
  59. package/templates/_goiabaseeds/core/best-practices/_catalog.yaml +116 -0
  60. package/templates/_goiabaseeds/core/best-practices/blog-post.md +132 -0
  61. package/templates/_goiabaseeds/core/best-practices/blog-seo.md +127 -0
  62. package/templates/_goiabaseeds/core/best-practices/copywriting.md +428 -0
  63. package/templates/_goiabaseeds/core/best-practices/data-analysis.md +401 -0
  64. package/templates/_goiabaseeds/core/best-practices/email-newsletter.md +118 -0
  65. package/templates/_goiabaseeds/core/best-practices/email-sales.md +110 -0
  66. package/templates/_goiabaseeds/core/best-practices/image-design.md +349 -0
  67. package/templates/_goiabaseeds/core/best-practices/instagram-feed.md +235 -0
  68. package/templates/_goiabaseeds/core/best-practices/instagram-reels.md +112 -0
  69. package/templates/_goiabaseeds/core/best-practices/instagram-stories.md +107 -0
  70. package/templates/_goiabaseeds/core/best-practices/linkedin-article.md +116 -0
  71. package/templates/_goiabaseeds/core/best-practices/linkedin-post.md +121 -0
  72. package/templates/_goiabaseeds/core/best-practices/researching.md +347 -0
  73. package/templates/_goiabaseeds/core/best-practices/review.md +269 -0
  74. package/templates/_goiabaseeds/core/best-practices/social-networks-publishing.md +294 -0
  75. package/templates/_goiabaseeds/core/best-practices/strategist.md +344 -0
  76. package/templates/_goiabaseeds/core/best-practices/technical-writing.md +363 -0
  77. package/templates/_goiabaseeds/core/best-practices/twitter-post.md +105 -0
  78. package/templates/_goiabaseeds/core/best-practices/twitter-thread.md +122 -0
  79. package/templates/_goiabaseeds/core/best-practices/whatsapp-broadcast.md +107 -0
  80. package/templates/_goiabaseeds/core/best-practices/youtube-script.md +122 -0
  81. package/templates/_goiabaseeds/core/best-practices/youtube-shorts.md +112 -0
  82. package/templates/_goiabaseeds/core/prompts/auguste.dupin.prompt.md +1008 -0
  83. package/templates/_goiabaseeds/core/runner.pipeline.md +467 -0
  84. package/templates/_goiabaseeds/core/skills.engine.md +381 -0
  85. package/templates/dashboard/index.html +12 -0
  86. package/templates/dashboard/package-lock.json +2082 -0
  87. package/templates/dashboard/package.json +28 -0
  88. package/templates/dashboard/src/App.tsx +46 -0
  89. package/templates/dashboard/src/components/DepartmentCard.tsx +47 -0
  90. package/templates/dashboard/src/components/DepartmentSelector.tsx +61 -0
  91. package/templates/dashboard/src/components/StatusBadge.tsx +32 -0
  92. package/templates/dashboard/src/components/StatusBar.tsx +97 -0
  93. package/templates/dashboard/src/hooks/useDepartmentSocket.ts +84 -0
  94. package/templates/dashboard/src/lib/formatTime.ts +16 -0
  95. package/templates/dashboard/src/lib/normalizeState.ts +25 -0
  96. package/templates/dashboard/src/main.tsx +10 -0
  97. package/templates/dashboard/src/office/AgentDesk.tsx +151 -0
  98. package/templates/dashboard/src/office/HandoffEnvelope.tsx +108 -0
  99. package/templates/dashboard/src/office/OfficeScene.tsx +147 -0
  100. package/templates/dashboard/src/office/drawDesk.ts +263 -0
  101. package/templates/dashboard/src/office/drawFurniture.ts +129 -0
  102. package/templates/dashboard/src/office/drawRoom.ts +51 -0
  103. package/templates/dashboard/src/office/palette.ts +181 -0
  104. package/templates/dashboard/src/office/textures.ts +254 -0
  105. package/templates/dashboard/src/plugin/departmentWatcher.ts +210 -0
  106. package/templates/dashboard/src/store/useDepartmentStore.ts +56 -0
  107. package/templates/dashboard/src/styles/globals.css +36 -0
  108. package/templates/dashboard/src/types/state.ts +64 -0
  109. package/templates/dashboard/src/vite-env.d.ts +1 -0
  110. package/templates/dashboard/tsconfig.json +24 -0
  111. package/templates/dashboard/vite.config.ts +13 -0
  112. package/templates/departments/.gitkeep +0 -0
  113. package/templates/ide-templates/antigravity/.agent/rules/goiabaseeds.md +55 -0
  114. package/templates/ide-templates/antigravity/.agent/workflows/goiabaseeds.md +102 -0
  115. package/templates/ide-templates/claude-code/.claude/skills/goiabaseeds/SKILL.md +182 -0
  116. package/templates/ide-templates/claude-code/.mcp.json +8 -0
  117. package/templates/ide-templates/claude-code/CLAUDE.md +43 -0
  118. package/templates/ide-templates/codex/.agents/skills/goiabaseeds/SKILL.md +6 -0
  119. package/templates/ide-templates/codex/AGENTS.md +105 -0
  120. package/templates/ide-templates/cursor/.cursor/commands/goiabaseeds.md +9 -0
  121. package/templates/ide-templates/cursor/.cursor/mcp.json +8 -0
  122. package/templates/ide-templates/cursor/.cursor/rules/goiabaseeds.mdc +48 -0
  123. package/templates/ide-templates/cursor/.cursorignore +3 -0
  124. package/templates/ide-templates/opencode/.opencode/commands/goiabaseeds.md +9 -0
  125. package/templates/ide-templates/opencode/AGENTS.md +105 -0
  126. package/templates/ide-templates/vscode-copilot/.github/prompts/goiabaseeds.prompt.md +201 -0
  127. package/templates/ide-templates/vscode-copilot/.vscode/mcp.json +8 -0
  128. package/templates/ide-templates/vscode-copilot/.vscode/settings.json +3 -0
  129. package/templates/package.json +8 -0
package/src/context.js ADDED
@@ -0,0 +1,142 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+
4
+ /**
5
+ * Parse YAML frontmatter from a markdown file.
6
+ * Returns { frontmatter: string, body: string, meta: object }
7
+ */
8
+ export function parseFrontmatter(content) {
9
+ const normalized = content.replace(/\r\n/g, '\n');
10
+ const match = normalized.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
11
+ if (!match) return { frontmatter: '', body: normalized, meta: {} };
12
+
13
+ const frontmatter = match[1];
14
+ const body = match[2];
15
+
16
+ // Simple key-value extraction from frontmatter
17
+ const meta = {};
18
+ for (const line of frontmatter.split('\n')) {
19
+ const kv = line.match(/^(\w[\w_-]*):\s*(.+)$/);
20
+ if (kv) meta[kv[1]] = kv[2].trim();
21
+ }
22
+
23
+ // Parse skills list (YAML array)
24
+ const skillsMatch = frontmatter.match(/^skills:\s*\n((?:\s+-\s+.+\n?)+)/m);
25
+ if (skillsMatch) {
26
+ meta.skills = [];
27
+ for (const line of skillsMatch[1].split('\n')) {
28
+ const item = line.match(/^\s+-\s+(.+)/);
29
+ if (item) meta.skills.push(item[1].trim());
30
+ }
31
+ }
32
+
33
+ // Parse tasks list (YAML array)
34
+ const tasksMatch = frontmatter.match(/^tasks:\s*\n((?:\s+-\s+.+\n?)+)/m);
35
+ if (tasksMatch) {
36
+ meta.tasks = [];
37
+ for (const line of tasksMatch[1].split('\n')) {
38
+ const item = line.match(/^\s+-\s+(.+)/);
39
+ if (item) meta.tasks.push(item[1].trim());
40
+ }
41
+ }
42
+
43
+ return { frontmatter, body, meta };
44
+ }
45
+
46
+ /**
47
+ * Read a file safely, returning empty string if not found.
48
+ */
49
+ async function safeRead(filePath) {
50
+ try {
51
+ return await readFile(filePath, 'utf-8');
52
+ } catch (err) {
53
+ if (err.code === 'ENOENT') return '';
54
+ throw err;
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Compose the full system prompt for an agent step.
60
+ *
61
+ * Composition order (matches runner.pipeline.md lines 83-126):
62
+ * 1. Agent .agent.md full content
63
+ * 2. Agent row from department-party.csv
64
+ * 3. Format best-practices (if step has format: field)
65
+ * 4. Skill instructions (for each skill in agent frontmatter)
66
+ * 5. Company context
67
+ * 6. Department memory
68
+ *
69
+ * @param {object} options
70
+ * @param {string} options.agentPath - Absolute path to the agent .agent.md file
71
+ * @param {object} options.stepMeta - Parsed step frontmatter (step_id, agent, format, etc.)
72
+ * @param {string} options.departmentDir - Absolute path to the department directory
73
+ * @param {string} options.targetDir - Absolute path to the project root
74
+ * @returns {Promise<string>} Composed system prompt
75
+ */
76
+ export async function composeAgentContext({ agentPath, stepMeta, departmentDir, targetDir }) {
77
+ const parts = [];
78
+
79
+ // 1. Agent .agent.md full content
80
+ const agentContent = await safeRead(agentPath);
81
+ if (agentContent) {
82
+ parts.push(agentContent);
83
+ }
84
+
85
+ // 2. Agent row from department-party.csv
86
+ const partyPath = join(departmentDir, 'department-party.csv');
87
+ const partyContent = await safeRead(partyPath);
88
+ if (partyContent && stepMeta.agent) {
89
+ const lines = partyContent.split('\n').filter(l => l.trim());
90
+ const agentRow = lines.find(line => {
91
+ const [id] = line.split(',');
92
+ return id?.trim() === stepMeta.agent;
93
+ });
94
+ if (agentRow) {
95
+ parts.push(`--- AGENT PERSONA (from department party) ---\n${agentRow}`);
96
+ }
97
+ }
98
+
99
+ // 3. Format best-practices
100
+ if (stepMeta.format) {
101
+ const formatPath = join(targetDir, '_goiabaseeds', 'core', 'best-practices', `${stepMeta.format}.md`);
102
+ const formatContent = await safeRead(formatPath);
103
+ if (formatContent) {
104
+ const { body } = parseFrontmatter(formatContent);
105
+ parts.push(`--- FORMAT: ${stepMeta.format} ---\n${body}`);
106
+ }
107
+ }
108
+
109
+ // 4. Skill instructions (from agent's frontmatter skills list)
110
+ const { meta: agentMeta } = parseFrontmatter(agentContent);
111
+ const skills = agentMeta.skills || [];
112
+ if (skills.length > 0) {
113
+ const skillParts = [];
114
+ for (const skillName of skills) {
115
+ const skillPath = join(targetDir, 'skills', skillName, 'SKILL.md');
116
+ const skillContent = await safeRead(skillPath);
117
+ if (skillContent) {
118
+ const { body } = parseFrontmatter(skillContent);
119
+ skillParts.push(`## ${skillName}\n${body}`);
120
+ }
121
+ }
122
+ if (skillParts.length > 0) {
123
+ parts.push(`--- SKILL INSTRUCTIONS ---\n${skillParts.join('\n\n')}`);
124
+ }
125
+ }
126
+
127
+ // 5. Company context
128
+ const companyPath = join(targetDir, '_goiabaseeds', '_memory', 'company.md');
129
+ const companyContent = await safeRead(companyPath);
130
+ if (companyContent) {
131
+ parts.push(`--- COMPANY CONTEXT ---\n${companyContent}`);
132
+ }
133
+
134
+ // 6. Department memory
135
+ const memoryPath = join(departmentDir, '_memory', 'memories.md');
136
+ const memoryContent = await safeRead(memoryPath);
137
+ if (memoryContent) {
138
+ parts.push(`--- DEPARTMENT MEMORY ---\n${memoryContent}`);
139
+ }
140
+
141
+ return parts.join('\n\n');
142
+ }
package/src/export.js ADDED
@@ -0,0 +1,52 @@
1
+ import { bundleDepartment } from './bundle.js';
2
+
3
+ /**
4
+ * Export a department as a standalone bundle
5
+ * @param {string[]} args - Command arguments [departmentName, --format, format, --output, path, etc.]
6
+ * @param {string} projectDir - Project root directory
7
+ * @returns {Object} Result with success status
8
+ */
9
+ export async function exportDepartment(args, projectDir) {
10
+ if (!args || args.length === 0) {
11
+ console.log(`
12
+ Usage: npx goiabaseeds export <department> [options]
13
+
14
+ Options:
15
+ --format [bundle|zip] Output format (default: bundle)
16
+ --output <path> Custom output directory
17
+ --zip Create ZIP file (shorthand)
18
+
19
+ Examples:
20
+ npx goiabaseeds export my-carousel
21
+ npx goiabaseeds export my-carousel --format zip
22
+ npx goiabaseeds export my-carousel --output ~/exports
23
+ `);
24
+ return { success: false };
25
+ }
26
+
27
+ const departmentName = args[0];
28
+ let options = { output: undefined, zip: false };
29
+
30
+ // Parse options
31
+ for (let i = 1; i < args.length; i++) {
32
+ if (args[i] === '--format' && i + 1 < args.length) {
33
+ if (args[i + 1] === 'zip') options.zip = true;
34
+ i++;
35
+ } else if (args[i] === '--zip') {
36
+ options.zip = true;
37
+ } else if (args[i] === '--output' && i + 1 < args.length) {
38
+ options.output = args[i + 1];
39
+ i++;
40
+ }
41
+ }
42
+
43
+ // Bundle the department
44
+ const result = await bundleDepartment(departmentName, projectDir, options);
45
+
46
+ if (!result.success) {
47
+ console.error(`❌ Export failed: ${result.error}`);
48
+ return { success: false };
49
+ }
50
+
51
+ return { success: true };
52
+ }
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
+ }
package/src/init.js ADDED
@@ -0,0 +1,367 @@
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, spawn } from 'node:child_process';
5
+ import { userInfo, platform } from 'node:os';
6
+ import { createPrompt } from './prompt.js';
7
+ import { loadLocale, t } from './i18n.js';
8
+ import { listAvailable, installSkill } from './skills.js';
9
+ import { logEvent } from './logger.js';
10
+
11
+ const __dirname = dirname(fileURLToPath(import.meta.url));
12
+ const TEMPLATES_DIR = join(__dirname, '..', 'templates');
13
+
14
+ const LANGUAGES = [
15
+ { label: 'Português (Brasil)', value: 'Português (Brasil)' },
16
+ { label: 'English', value: 'English' },
17
+ { label: 'Español', value: 'Español' },
18
+ ];
19
+
20
+ const IDES = [
21
+ { label: 'Standalone (recommended)', value: 'standalone', checked: true },
22
+ { label: 'Antigravity', value: 'antigravity' },
23
+ { label: 'Claude Code', value: 'claude-code' },
24
+ { label: 'Codex (OpenAI)', value: 'codex' },
25
+ { label: 'Cursor', value: 'cursor' },
26
+ { label: 'OpenCode', value: 'opencode' },
27
+ { label: 'VS Code + Copilot', value: 'vscode-copilot' },
28
+ ];
29
+
30
+ const PROVIDERS = [
31
+ { label: 'Anthropic (Claude)', value: 'anthropic' },
32
+ { label: 'OpenAI (GPT)', value: 'openai' },
33
+ { label: 'Google (Gemini)', value: 'google' },
34
+ { label: 'GitHub Copilot', value: 'github-copilot' },
35
+ ];
36
+
37
+ const PROVIDER_ENV_KEYS = {
38
+ anthropic: 'ANTHROPIC_API_KEY',
39
+ openai: 'OPENAI_API_KEY',
40
+ google: 'GOOGLE_GENERATIVE_AI_API_KEY',
41
+ 'github-copilot': 'GITHUB_TOKEN',
42
+ };
43
+
44
+ export async function init(targetDir, options = {}) {
45
+
46
+ // Check if already initialized
47
+ let isReInit = false;
48
+ try {
49
+ await stat(join(targetDir, '_goiabaseeds'));
50
+ isReInit = true;
51
+ } catch {
52
+ // Not initialized yet — continue
53
+ }
54
+
55
+ console.log(isReInit ? '\n 🔄 GoiabaSeeds — Re-configure\n' : '\n 🟢 GoiabaSeeds — Setup\n');
56
+
57
+ // Guided installation (skip in test mode)
58
+ let language = options._language || 'English';
59
+ let ides = options._ides ?? ['claude-code'];
60
+ let userName = '';
61
+
62
+ if (options._quick) {
63
+ // Quick mode: no prompts, smart defaults
64
+ userName = userInfo().username;
65
+ await loadLocale(language);
66
+ } else if (!options._skipPrompts) {
67
+ const prompt = createPrompt();
68
+
69
+ try {
70
+ // Language is asked FIRST (in English, before locale is loaded)
71
+ const langChoice = await prompt.choose('What language do you prefer for outputs?', LANGUAGES);
72
+ language = langChoice.value;
73
+
74
+ // Load locale — all messages from here are translated
75
+ await loadLocale(language);
76
+
77
+ console.log(`\n ${t('welcome')}\n`);
78
+
79
+ userName = (await prompt.ask(` ${t('askName')}`)).trim();
80
+
81
+ ides = await prompt.multiChoose(t('chooseIdes'), IDES);
82
+ } finally {
83
+ prompt.close();
84
+ }
85
+ } else {
86
+ await loadLocale(language);
87
+ }
88
+
89
+ // Copy template files
90
+ await copyCommonTemplates(targetDir);
91
+
92
+ // Filter 'standalone' from IDE templates (no IDE-specific dir) and copy IDE templates
93
+ const ideTemplates = ides.filter(ide => ide !== 'standalone');
94
+ await copyIdeTemplates(ideTemplates, targetDir);
95
+ await installAllSkills(targetDir);
96
+ if (!options._skipPrompts && !options._skipDeps) {
97
+ await installDependencies(targetDir);
98
+ }
99
+ await writeProjectReadme(targetDir);
100
+
101
+ // Standalone mode setup — generate provider config
102
+ if (ides.includes('standalone')) {
103
+ await setupStandaloneConfig(targetDir, options);
104
+ }
105
+
106
+ // Write user preferences
107
+ const prefsPath = join(targetDir, '_goiabaseeds', '_memory', 'preferences.md');
108
+ await mkdir(dirname(prefsPath), { recursive: true });
109
+ const prefsContent = `# GoiabaSeeds Preferences
110
+
111
+ - **User Name:** ${userName}
112
+ - **Output Language:** ${language}
113
+ - **IDEs:** ${ides.join(', ')}
114
+ - **Date Format:** YYYY-MM-DD
115
+ `;
116
+ await writeFile(prefsPath, prefsContent, 'utf-8');
117
+
118
+ await logEvent('init', { language, ides: ides.join(',') }, targetDir);
119
+
120
+ console.log(`\n ${t('success')}\n`);
121
+ console.log(` ${t('nextSteps')}`);
122
+ for (const ide of ides) {
123
+ if (ide === 'standalone') {
124
+ const providerName = options._provider || 'anthropic';
125
+ const envKey = PROVIDER_ENV_KEYS[providerName] || 'ANTHROPIC_API_KEY';
126
+ console.log(` 1. Set your API key: export ${envKey}=your-key-here`);
127
+ console.log(` 2. Test connectivity: npx goiabaseeds models test`);
128
+ console.log(` 3. Run a department: npx goiabaseeds run <department-name>\n`);
129
+ } else if (ide === 'claude-code') {
130
+ console.log(` ${t('step1ClaudeCode')}`);
131
+ console.log(` ${t('step2ClaudeCode')}`);
132
+ console.log(` ${t('step3ClaudeCode')}\n`);
133
+ } else if (ide === 'codex') {
134
+ console.log(` ${t('step1Codex')}\n`);
135
+ } else if (ide === 'antigravity') {
136
+ console.log(` ${t('step1Antigravity')}\n`);
137
+ } else if (ide === 'cursor') {
138
+ console.log(` ${t('step1Cursor')}\n`);
139
+ } else if (ide === 'opencode') {
140
+ console.log(` ${t('step1Opencode')}\n`);
141
+ } else if (ide === 'vscode-copilot') {
142
+ console.log(` ${t('step1VsCodeCopilot')}`);
143
+ console.log(` ${t('step2VsCodeCopilot')}`);
144
+ console.log(` ${t('step3VsCodeCopilot')}\n`);
145
+ }
146
+ }
147
+
148
+ // Quick mode: auto-start dashboard and open browser
149
+ if (options._quick && !options._skipDashboardStart) {
150
+ startDashboard(targetDir);
151
+ setTimeout(() => openBrowser('http://localhost:5173'), 3000);
152
+ }
153
+ }
154
+
155
+ export async function loadSavedLocale(targetDir) {
156
+ try {
157
+ const prefsPath = join(targetDir, '_goiabaseeds', '_memory', 'preferences.md');
158
+ const content = await readFile(prefsPath, 'utf-8');
159
+ const match = content.match(/\*\*Output Language:\*\*\s*(.+)/);
160
+ if (match) {
161
+ await loadLocale(match[1].trim());
162
+ return;
163
+ }
164
+ } catch {
165
+ // No preferences file yet
166
+ }
167
+ await loadLocale('English');
168
+ }
169
+
170
+ async function setupStandaloneConfig(targetDir, options) {
171
+ let providerName = options._provider || 'anthropic';
172
+
173
+ // If not skipping prompts, ask for provider
174
+ if (!options._skipPrompts && !options._quick) {
175
+ const prompt = createPrompt();
176
+ try {
177
+ const choice = await prompt.choose('Which AI provider do you want to use?', PROVIDERS);
178
+ providerName = choice.value;
179
+ } finally {
180
+ prompt.close();
181
+ }
182
+ }
183
+
184
+ // Store the chosen provider in options for next-steps display
185
+ options._provider = providerName;
186
+
187
+ const configContent = `# GoiabaSeeds Standalone Configuration
188
+ runtime: standalone
189
+ default_provider: ${providerName}
190
+
191
+ providers:
192
+ anthropic:
193
+ models:
194
+ powerful: claude-sonnet-4-20250514
195
+ fast: claude-haiku-4-5-20251001
196
+ openai:
197
+ models:
198
+ powerful: gpt-4o
199
+ fast: gpt-4o-mini
200
+ google:
201
+ models:
202
+ powerful: gemini-2.5-pro
203
+ fast: gemini-2.0-flash
204
+ github-copilot:
205
+ models:
206
+ powerful: gpt-4o
207
+ fast: gpt-4o-mini
208
+ `;
209
+
210
+ const configPath = join(targetDir, '_goiabaseeds', 'config.yaml');
211
+ await mkdir(dirname(configPath), { recursive: true });
212
+ await writeFile(configPath, configContent, 'utf-8');
213
+ console.log(` ${t('createdFile', { path: '_goiabaseeds/config.yaml' })}`);
214
+ }
215
+
216
+ async function installAllSkills(targetDir) {
217
+ const available = await listAvailable();
218
+ for (const id of available) {
219
+ await installSkill(id, targetDir);
220
+ console.log(` ${t('createdFile', { path: `skills/${id}/SKILL.md` })}`);
221
+ }
222
+ }
223
+
224
+ async function installDependencies(targetDir) {
225
+ console.log(`\n Installing dependencies...`);
226
+ execSync('npm install', { cwd: targetDir, stdio: 'inherit' });
227
+ console.log(`\n Installing dashboard dependencies...`);
228
+ execSync('npm install', { cwd: join(targetDir, 'dashboard'), stdio: 'inherit' });
229
+ console.log(`\n Installing Playwright browsers...`);
230
+ execSync('npx playwright install chromium', { cwd: targetDir, stdio: 'inherit' });
231
+ }
232
+
233
+ async function writeProjectReadme(targetDir) {
234
+ const readmePath = join(__dirname, 'readme', 'README.md');
235
+ const content = await readFile(readmePath, 'utf-8');
236
+ await writeFile(join(targetDir, 'README.md'), content, 'utf-8');
237
+ }
238
+
239
+ async function copyCommonTemplates(targetDir) {
240
+ const entries = await getTemplateEntries(TEMPLATES_DIR);
241
+
242
+ for (const entry of entries) {
243
+ // Skip anything inside ide-templates/ — handled by copyIdeTemplates
244
+ if (entry.replace(/\\/g, '/').includes('/ide-templates/')) continue;
245
+
246
+ const relativePath = entry.slice(TEMPLATES_DIR.length + 1);
247
+ const destPath = join(targetDir, relativePath);
248
+ const destDir = dirname(destPath);
249
+ await mkdir(destDir, { recursive: true });
250
+ try {
251
+ await stat(destPath);
252
+ continue; // file already exists — skip
253
+ } catch {
254
+ // does not exist — copy it
255
+ }
256
+ await cp(entry, destPath);
257
+ console.log(` ${t('createdFile', { path: relativePath })}`);
258
+ }
259
+ }
260
+
261
+ async function copyIdeTemplates(ides, targetDir) {
262
+ const ideTemplatesDir = join(TEMPLATES_DIR, 'ide-templates');
263
+ const writtenPaths = new Set();
264
+
265
+ for (const ide of ides) {
266
+ const ideSrcDir = join(ideTemplatesDir, ide);
267
+ let entries;
268
+ try {
269
+ entries = await getTemplateEntries(ideSrcDir);
270
+ } catch {
271
+ continue; // no template dir for this IDE yet
272
+ }
273
+
274
+ for (const entry of entries) {
275
+ const relativePath = entry.slice(ideSrcDir.length + 1);
276
+ // settings.json for vscode-copilot is handled by mergeVsCodeSettings — skip here
277
+ if (ide === 'vscode-copilot' && relativePath.replace(/\\/g, '/') === '.vscode/settings.json') continue;
278
+ if (writtenPaths.has(relativePath)) continue;
279
+ writtenPaths.add(relativePath);
280
+
281
+ const destPath = join(targetDir, relativePath);
282
+ const destDir = dirname(destPath);
283
+ await mkdir(destDir, { recursive: true });
284
+ await cp(entry, destPath);
285
+ console.log(` ${t('createdFile', { path: relativePath })}`);
286
+ }
287
+ }
288
+
289
+ if (ides.includes('vscode-copilot')) {
290
+ await mergeVsCodeSettings(targetDir);
291
+ }
292
+ }
293
+
294
+ async function mergeVsCodeSettings(targetDir) {
295
+ const settingsPath = join(targetDir, '.vscode', 'settings.json');
296
+
297
+ let exists = false;
298
+ try {
299
+ await stat(settingsPath);
300
+ exists = true;
301
+ } catch {
302
+ // doesn't exist
303
+ }
304
+
305
+ if (!exists) {
306
+ const templateBase = join(TEMPLATES_DIR, 'ide-templates', 'vscode-copilot', '.vscode', 'settings.json');
307
+ await mkdir(join(targetDir, '.vscode'), { recursive: true });
308
+ await cp(templateBase, settingsPath);
309
+ return;
310
+ }
311
+
312
+ const raw = await readFile(settingsPath, 'utf-8');
313
+ let parsed;
314
+ try {
315
+ parsed = JSON.parse(raw);
316
+ } catch {
317
+ console.log(` ⚠️ .vscode/settings.json has invalid JSON — skipping merge. Add manually: "chat.promptFilesLocations": [".github/prompts"]`);
318
+ return;
319
+ }
320
+
321
+ if (!parsed['chat.promptFilesLocations']) {
322
+ parsed['chat.promptFilesLocations'] = ['.github/prompts'];
323
+ } else if (!parsed['chat.promptFilesLocations'].includes('.github/prompts')) {
324
+ parsed['chat.promptFilesLocations'].push('.github/prompts');
325
+ }
326
+
327
+ await writeFile(settingsPath, JSON.stringify(parsed, null, 2), 'utf-8');
328
+ }
329
+
330
+ function startDashboard(targetDir) {
331
+ const dashboardDir = join(targetDir, 'dashboard');
332
+ const child = spawn('npm', ['run', 'dev'], {
333
+ cwd: dashboardDir,
334
+ stdio: 'ignore',
335
+ detached: true,
336
+ shell: true,
337
+ });
338
+ child.unref();
339
+ console.log('\n 🖥️ Dashboard starting at http://localhost:5173\n');
340
+ }
341
+
342
+ function openBrowser(url) {
343
+ const os = platform();
344
+ try {
345
+ if (os === 'darwin') execSync(`open ${url}`);
346
+ else if (os === 'win32') execSync(`start ${url}`, { shell: true });
347
+ else execSync(`xdg-open ${url}`);
348
+ } catch {
349
+ // Browser open failed — not critical
350
+ }
351
+ }
352
+
353
+ export async function getTemplateEntries(dir) {
354
+ const results = [];
355
+ const entries = await readdir(dir, { withFileTypes: true });
356
+
357
+ for (const entry of entries) {
358
+ const fullPath = join(dir, entry.name);
359
+ if (entry.isDirectory()) {
360
+ results.push(...await getTemplateEntries(fullPath));
361
+ } else {
362
+ results.push(fullPath);
363
+ }
364
+ }
365
+
366
+ return results;
367
+ }
@@ -0,0 +1,72 @@
1
+ {
2
+ "welcome": "Welcome! Let's set up GoiabaSeeds 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 goiabaseeds to get started.",
8
+ "step1Cursor": "1. Open Cursor, type / in the chat and select goiabaseeds to get started.",
9
+ "step1Opencode": "1. Open OpenCode and type /goiabaseeds 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": "⚠️ GoiabaSeeds is already initialized in this directory.",
13
+ "alreadyInitializedHint": "Use Claude Code and type /goiabaseeds to get started.",
14
+ "createdFile": "📄 Created {path}",
15
+ "success": "✅ GoiabaSeeds initialized successfully!",
16
+ "nextSteps": "Next steps:",
17
+ "step1ClaudeCode": "1. Open this directory in Claude Code",
18
+ "step2ClaudeCode": "2. Type /goiabaseeds 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 GoiabaSeeds installation found. Run 'init' first.",
23
+ "updateStarting": "Updating GoiabaSeeds {old} → {new}...",
24
+ "updateStartingUnknown": "Updating GoiabaSeeds (unknown version) → {new}...",
25
+ "updatedFile": "📄 Updated {path}",
26
+ "updateSuccess": "✅ GoiabaSeeds {version} installed successfully!",
27
+ "updatePreserved": "✓ Preserved: _memory/, _investigations/, departments/",
28
+ "updateFileCount": "✓ Updated: {count} system files",
29
+ "updateLatestHint": "💡 Tip: Use 'npx goiabaseeds@latest update' to always get the newest version.",
30
+ "skillsNotInitialized": "No GoiabaSeeds 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 goiabaseeds 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: goiabaseeds 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 goiabaseeds install <name>",
52
+ "skillsInstalledCount": "Installed {count} skill(s).",
53
+ "agentsNotInitialized": "No GoiabaSeeds installation found. Run 'init' first.",
54
+ "agentsInstalledHeader": "Installed:",
55
+ "agentsNoneInstalled": "No agents installed yet.",
56
+ "agentsInstallHint": "Install with: npx goiabaseeds 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: goiabaseeds 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 /goiabaseeds to get started"
72
+ }