@onion-ai/cli 1.0.0-beta.1

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 (220) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +529 -0
  3. package/bin/onion.js +6 -0
  4. package/framework/CLAUDE.md +45 -0
  5. package/framework/VERSION +1 -0
  6. package/framework/agents/compliance/iso-22301-specialist.md +985 -0
  7. package/framework/agents/compliance/iso-27001-specialist.md +713 -0
  8. package/framework/agents/compliance/pmbok-specialist.md +739 -0
  9. package/framework/agents/compliance/security-information-master.md +907 -0
  10. package/framework/agents/compliance/soc2-specialist.md +889 -0
  11. package/framework/agents/deployment/docker-specialist.md +1192 -0
  12. package/framework/agents/development/c4-architecture-specialist.md +745 -0
  13. package/framework/agents/development/c4-documentation-specialist.md +695 -0
  14. package/framework/agents/development/clickup-specialist.md +396 -0
  15. package/framework/agents/development/cursor-specialist.md +277 -0
  16. package/framework/agents/development/docs-reverse-engineer.md +417 -0
  17. package/framework/agents/development/gamma-api-specialist.md +1168 -0
  18. package/framework/agents/development/gitflow-specialist.md +1206 -0
  19. package/framework/agents/development/linux-security-specialist.md +675 -0
  20. package/framework/agents/development/mermaid-specialist.md +515 -0
  21. package/framework/agents/development/nodejs-specialist.md +672 -0
  22. package/framework/agents/development/nx-migration-specialist.md +866 -0
  23. package/framework/agents/development/nx-monorepo-specialist.md +618 -0
  24. package/framework/agents/development/postgres-specialist.md +1123 -0
  25. package/framework/agents/development/react-developer.md +131 -0
  26. package/framework/agents/development/runflow-specialist.md +277 -0
  27. package/framework/agents/development/system-documentation-orchestrator.md +1387 -0
  28. package/framework/agents/development/task-specialist.md +677 -0
  29. package/framework/agents/git/branch-code-reviewer.md +225 -0
  30. package/framework/agents/git/branch-documentation-writer.md +161 -0
  31. package/framework/agents/git/branch-metaspec-checker.md +67 -0
  32. package/framework/agents/git/branch-test-planner.md +176 -0
  33. package/framework/agents/meta/agent-creator-specialist.md +1266 -0
  34. package/framework/agents/meta/command-creator-specialist.md +1676 -0
  35. package/framework/agents/meta/metaspec-gate-keeper.md +240 -0
  36. package/framework/agents/meta/onion.md +824 -0
  37. package/framework/agents/product/branding-positioning-specialist.md +1029 -0
  38. package/framework/agents/product/extract-meeting-specialist.md +394 -0
  39. package/framework/agents/product/meeting-consolidator.md +482 -0
  40. package/framework/agents/product/pain-price-specialist.md +508 -0
  41. package/framework/agents/product/presentation-orchestrator.md +1190 -0
  42. package/framework/agents/product/product-agent.md +201 -0
  43. package/framework/agents/product/story-points-framework-specialist.md +538 -0
  44. package/framework/agents/product/storytelling-business-specialist.md +890 -0
  45. package/framework/agents/research/research-agent.md +292 -0
  46. package/framework/agents/review/code-reviewer.md +154 -0
  47. package/framework/agents/review/corporate-compliance-specialist.md +370 -0
  48. package/framework/agents/testing/test-agent.md +424 -0
  49. package/framework/agents/testing/test-engineer.md +294 -0
  50. package/framework/agents/testing/test-planner.md +117 -0
  51. package/framework/commands/common/prompts/README.md +208 -0
  52. package/framework/commands/common/prompts/clickup-patterns.md +144 -0
  53. package/framework/commands/common/prompts/code-review-checklist.md +168 -0
  54. package/framework/commands/common/prompts/git-workflow-patterns.md +235 -0
  55. package/framework/commands/common/prompts/output-formats.md +240 -0
  56. package/framework/commands/common/prompts/technical.md +194 -0
  57. package/framework/commands/common/templates/abstraction-template.md +399 -0
  58. package/framework/commands/common/templates/agent-template.md +353 -0
  59. package/framework/commands/common/templates/business_context_template.md +748 -0
  60. package/framework/commands/common/templates/command-template.md +273 -0
  61. package/framework/commands/common/templates/technical_context_template.md +526 -0
  62. package/framework/commands/design/screen-spec.md +505 -0
  63. package/framework/commands/development/runflow-dev.md +465 -0
  64. package/framework/commands/docs/build-business-docs.md +299 -0
  65. package/framework/commands/docs/build-compliance-docs.md +143 -0
  66. package/framework/commands/docs/build-index.md +119 -0
  67. package/framework/commands/docs/build-tech-docs.md +221 -0
  68. package/framework/commands/docs/docs-health.md +141 -0
  69. package/framework/commands/docs/help.md +278 -0
  70. package/framework/commands/docs/refine-vision.md +25 -0
  71. package/framework/commands/docs/reverse-consolidate.md +158 -0
  72. package/framework/commands/docs/sync-sessions.md +354 -0
  73. package/framework/commands/docs/validate-docs.md +157 -0
  74. package/framework/commands/engineer/bump.md +29 -0
  75. package/framework/commands/engineer/docs.md +11 -0
  76. package/framework/commands/engineer/hotfix.md +183 -0
  77. package/framework/commands/engineer/plan.md +85 -0
  78. package/framework/commands/engineer/pr-update.md +219 -0
  79. package/framework/commands/engineer/pr.md +117 -0
  80. package/framework/commands/engineer/pre-pr.md +81 -0
  81. package/framework/commands/engineer/start.md +254 -0
  82. package/framework/commands/engineer/validate-phase-sync.md +134 -0
  83. package/framework/commands/engineer/warm-up.md +20 -0
  84. package/framework/commands/engineer/work.md +155 -0
  85. package/framework/commands/f/company-context-extractor.md +93 -0
  86. package/framework/commands/f/process-meetings.md +103 -0
  87. package/framework/commands/git/README.md +682 -0
  88. package/framework/commands/git/code-review.md +213 -0
  89. package/framework/commands/git/fast-commit.md +43 -0
  90. package/framework/commands/git/feature/finish.md +88 -0
  91. package/framework/commands/git/feature/publish.md +89 -0
  92. package/framework/commands/git/feature/start.md +172 -0
  93. package/framework/commands/git/help.md +100 -0
  94. package/framework/commands/git/hotfix/finish.md +96 -0
  95. package/framework/commands/git/hotfix/start.md +92 -0
  96. package/framework/commands/git/init.md +111 -0
  97. package/framework/commands/git/release/finish.md +96 -0
  98. package/framework/commands/git/release/start.md +93 -0
  99. package/framework/commands/git/sync.md +199 -0
  100. package/framework/commands/meta/all-tools.md +58 -0
  101. package/framework/commands/meta/analyze-complex-problem.md +186 -0
  102. package/framework/commands/meta/create-abstraction.md +882 -0
  103. package/framework/commands/meta/create-agent-express.md +98 -0
  104. package/framework/commands/meta/create-agent.md +210 -0
  105. package/framework/commands/meta/create-command.md +203 -0
  106. package/framework/commands/meta/create-knowledge-base.md +143 -0
  107. package/framework/commands/meta/create-task-structure.md +150 -0
  108. package/framework/commands/meta/setup-integration.md +274 -0
  109. package/framework/commands/onion.md +169 -0
  110. package/framework/commands/product/README.md +249 -0
  111. package/framework/commands/product/analyze-pain-price.md +694 -0
  112. package/framework/commands/product/branding.md +458 -0
  113. package/framework/commands/product/check.md +46 -0
  114. package/framework/commands/product/checklist-sync.md +239 -0
  115. package/framework/commands/product/collect.md +95 -0
  116. package/framework/commands/product/consolidate-meetings.md +291 -0
  117. package/framework/commands/product/estimate.md +511 -0
  118. package/framework/commands/product/extract-meeting.md +226 -0
  119. package/framework/commands/product/feature.md +416 -0
  120. package/framework/commands/product/light-arch.md +82 -0
  121. package/framework/commands/product/presentation.md +174 -0
  122. package/framework/commands/product/refine.md +161 -0
  123. package/framework/commands/product/spec.md +79 -0
  124. package/framework/commands/product/task-check.md +378 -0
  125. package/framework/commands/product/task.md +603 -0
  126. package/framework/commands/product/validate-task.md +325 -0
  127. package/framework/commands/product/warm-up.md +24 -0
  128. package/framework/commands/quick/analisys.md +17 -0
  129. package/framework/commands/test/e2e.md +377 -0
  130. package/framework/commands/test/integration.md +508 -0
  131. package/framework/commands/test/unit.md +381 -0
  132. package/framework/commands/validate/collab/pair-testing.md +657 -0
  133. package/framework/commands/validate/collab/three-amigos.md +534 -0
  134. package/framework/commands/validate/qa-points/estimate.md +660 -0
  135. package/framework/commands/validate/test-strategy/analyze.md +1201 -0
  136. package/framework/commands/validate/test-strategy/create.md +411 -0
  137. package/framework/commands/validate/workflow.md +370 -0
  138. package/framework/commands/warm-up.md +20 -0
  139. package/framework/docs/architecture/acoplamento-clickup-problema-analise.md +468 -0
  140. package/framework/docs/architecture/desacoplamento-roadmap.md +364 -0
  141. package/framework/docs/architecture/validacao-fase-1.md +235 -0
  142. package/framework/docs/c4/c4-detection-rules.md +395 -0
  143. package/framework/docs/c4/c4-documentation-templates.md +579 -0
  144. package/framework/docs/c4/c4-mermaid-patterns.md +331 -0
  145. package/framework/docs/c4/c4-templates.md +256 -0
  146. package/framework/docs/clickup/clickup-acceptance-criteria-strategy.md +329 -0
  147. package/framework/docs/clickup/clickup-auto-update-strategy.md +340 -0
  148. package/framework/docs/clickup/clickup-comment-formatter.md +239 -0
  149. package/framework/docs/clickup/clickup-description-fix.md +384 -0
  150. package/framework/docs/clickup/clickup-dual-comment-strategy.md +528 -0
  151. package/framework/docs/clickup/clickup-formatting.md +302 -0
  152. package/framework/docs/clickup/separador-tamanho-otimizado.md +258 -0
  153. package/framework/docs/engineer/pre-pr-acceptance-validation.md +256 -0
  154. package/framework/docs/onion/ESPERANTO.md +293 -0
  155. package/framework/docs/onion/agents-reference.md +832 -0
  156. package/framework/docs/onion/clickup-integration.md +780 -0
  157. package/framework/docs/onion/commands-guide.md +924 -0
  158. package/framework/docs/onion/engineering-flows.md +900 -0
  159. package/framework/docs/onion/getting-started.md +803 -0
  160. package/framework/docs/onion/maintenance-checklist.md +421 -0
  161. package/framework/docs/onion/naming-conventions.md +286 -0
  162. package/framework/docs/onion/practical-examples.md +854 -0
  163. package/framework/docs/product/story-points-integration.md +269 -0
  164. package/framework/docs/product/story-points-validation.md +237 -0
  165. package/framework/docs/reviews/task-manager-docs-review-2025-11-24.md +184 -0
  166. package/framework/docs/strategies/clickup-comment-patterns.md +766 -0
  167. package/framework/docs/strategies/clickup-integration-tests.md +602 -0
  168. package/framework/docs/strategies/clickup-mcp-wrappers-tests.md +888 -0
  169. package/framework/docs/strategies/clickup-regression-tests.md +587 -0
  170. package/framework/docs/strategies/visual-patterns.md +315 -0
  171. package/framework/docs/templates/README.md +649 -0
  172. package/framework/docs/templates/adr-template.md +226 -0
  173. package/framework/docs/templates/analysis-template.md +280 -0
  174. package/framework/docs/templates/execution-plan-template.md +430 -0
  175. package/framework/docs/templates/guide-template.md +367 -0
  176. package/framework/docs/templates/phase-execution-prompt-template.md +504 -0
  177. package/framework/docs/templates/reference-template.md +522 -0
  178. package/framework/docs/templates/solution-template.md +390 -0
  179. package/framework/docs/tools/README.md +356 -0
  180. package/framework/docs/tools/agents.md +365 -0
  181. package/framework/docs/tools/commands.md +669 -0
  182. package/framework/docs/tools/cursor.md +539 -0
  183. package/framework/docs/tools/mcps.md +937 -0
  184. package/framework/docs/tools/rules.md +461 -0
  185. package/framework/rules/language-and-documentation.mdc +371 -0
  186. package/framework/rules/nestjs-controllers.md +83 -0
  187. package/framework/rules/nestjs-dtos.md +255 -0
  188. package/framework/rules/nestjs-modules.md +141 -0
  189. package/framework/rules/nestjs-services.md +230 -0
  190. package/framework/rules/nx-rules.mdc +41 -0
  191. package/framework/rules/onion-patterns.mdc +197 -0
  192. package/framework/skills/codebase-visualizer/SKILL.md +26 -0
  193. package/framework/skills/codebase-visualizer/scripts/visualize.py +131 -0
  194. package/framework/skills/collect/SKILL.md +84 -0
  195. package/framework/skills/create-rule/SKILL.md +152 -0
  196. package/framework/skills/db-schema-visualizer/SKILL.md +49 -0
  197. package/framework/skills/db-schema-visualizer/scripts/visualize.py +1191 -0
  198. package/framework/skills/sync-meetings/SKILL.md +239 -0
  199. package/framework/utils/clickup-mcp-wrappers.md +744 -0
  200. package/framework/utils/date-time-standards.md +200 -0
  201. package/framework/utils/task-manager/README.md +94 -0
  202. package/framework/utils/task-manager/adapters/asana.md +377 -0
  203. package/framework/utils/task-manager/adapters/clickup.md +467 -0
  204. package/framework/utils/task-manager/adapters/linear.md +421 -0
  205. package/framework/utils/task-manager/detector.md +299 -0
  206. package/framework/utils/task-manager/factory.md +363 -0
  207. package/framework/utils/task-manager/interface.md +248 -0
  208. package/framework/utils/task-manager/types.md +409 -0
  209. package/package.json +41 -0
  210. package/src/cli.js +73 -0
  211. package/src/commands/doctor.js +191 -0
  212. package/src/commands/init.js +287 -0
  213. package/src/commands/install.js +261 -0
  214. package/src/commands/list.js +152 -0
  215. package/src/commands/uninstall.js +90 -0
  216. package/src/commands/update.js +26 -0
  217. package/src/utils/fs.js +89 -0
  218. package/src/utils/log.js +35 -0
  219. package/src/utils/paths.js +32 -0
  220. package/src/utils/prompt.js +76 -0
package/src/cli.js ADDED
@@ -0,0 +1,73 @@
1
+ import { Command } from 'commander';
2
+ import { readFileSync } from 'fs';
3
+ import { join, dirname } from 'path';
4
+ import { fileURLToPath } from 'url';
5
+
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
8
+
9
+ export function createCli() {
10
+ const program = new Command();
11
+
12
+ program
13
+ .name('onion')
14
+ .description('The Onion Framework - AI-powered development workflow system for Claude Code')
15
+ .version(pkg.version);
16
+
17
+ program
18
+ .command('install')
19
+ .description('Install the Onion Framework into ~/.claude/')
20
+ .option('--force', 'Overwrite existing installation')
21
+ .option('--dry-run', 'Show what would be installed without making changes')
22
+ .action(async (opts) => {
23
+ const { install } = await import('./commands/install.js');
24
+ await install(opts);
25
+ });
26
+
27
+ program
28
+ .command('uninstall')
29
+ .description('Remove the Onion Framework from ~/.claude/')
30
+ .option('--keep-config', 'Keep user customizations in ~/.claude/onion/config/')
31
+ .action(async (opts) => {
32
+ const { uninstall } = await import('./commands/uninstall.js');
33
+ await uninstall(opts);
34
+ });
35
+
36
+ program
37
+ .command('doctor')
38
+ .description('Check installation health and prerequisites')
39
+ .action(async () => {
40
+ const { doctor } = await import('./commands/doctor.js');
41
+ await doctor();
42
+ });
43
+
44
+ program
45
+ .command('update')
46
+ .description('Update the Onion Framework to the latest version')
47
+ .action(async () => {
48
+ const { update } = await import('./commands/update.js');
49
+ await update();
50
+ });
51
+
52
+ program
53
+ .command('list')
54
+ .description('List installed framework components')
55
+ .option('--commands', 'List only commands')
56
+ .option('--agents', 'List only agents')
57
+ .option('--skills', 'List only skills')
58
+ .action(async (opts) => {
59
+ const { list } = await import('./commands/list.js');
60
+ await list(opts);
61
+ });
62
+
63
+ program
64
+ .command('init')
65
+ .description('Initialize Onion configuration for the current project (.onion/)')
66
+ .option('--force', 'Overwrite existing .onion/ configuration')
67
+ .action(async (opts) => {
68
+ const { init } = await import('./commands/init.js');
69
+ await init(opts);
70
+ });
71
+
72
+ return program;
73
+ }
@@ -0,0 +1,191 @@
1
+ import { execSync } from 'child_process';
2
+ import { existsSync } from 'fs';
3
+ import {
4
+ CLAUDE_HOME, ONION_HOME, ONION_MANIFEST,
5
+ ONION_COMMANDS, ONION_AGENTS, CLAUDE_SKILLS, CLAUDE_MD
6
+ } from '../utils/paths.js';
7
+ import { readFile, exists, countFiles } from '../utils/fs.js';
8
+ import * as log from '../utils/log.js';
9
+ import { readdirSync } from 'fs';
10
+
11
+ export async function doctor() {
12
+ log.header('Onion Framework Health Check');
13
+
14
+ let issues = 0;
15
+ let warnings = 0;
16
+
17
+ // 1. Prerequisites
18
+ log.step('Checking prerequisites...');
19
+
20
+ // Claude Code
21
+ if (exists(CLAUDE_HOME)) {
22
+ log.success('Claude Code config directory exists');
23
+ } else {
24
+ log.error('Claude Code config directory not found (~/.claude/)');
25
+ issues++;
26
+ }
27
+
28
+ // Claude CLI
29
+ if (commandExists('claude')) {
30
+ log.success('Claude Code CLI available');
31
+ } else {
32
+ log.warn('Claude Code CLI not found in PATH (optional — may use IDE integration)');
33
+ warnings++;
34
+ }
35
+
36
+ // Git
37
+ if (commandExists('git')) {
38
+ log.success('Git available');
39
+ } else {
40
+ log.error('Git not found — required for GitFlow commands');
41
+ issues++;
42
+ }
43
+
44
+ // Node.js
45
+ if (commandExists('node')) {
46
+ const version = getCommandOutput('node --version');
47
+ const major = parseInt(version.replace('v', '').split('.')[0]);
48
+ if (major >= 18) {
49
+ log.success(`Node.js ${version} (>= 18 required)`);
50
+ } else {
51
+ log.warn(`Node.js ${version} — version 18+ recommended`);
52
+ warnings++;
53
+ }
54
+ } else {
55
+ log.error('Node.js not found');
56
+ issues++;
57
+ }
58
+
59
+ // Python (optional)
60
+ if (commandExists('python3') || commandExists('python')) {
61
+ const cmd = commandExists('python3') ? 'python3' : 'python';
62
+ const version = getCommandOutput(`${cmd} --version`);
63
+ log.success(`${version} (optional dependency)`);
64
+ } else {
65
+ log.info('Python not found (optional — only needed for specific commands)');
66
+ }
67
+
68
+ log.blank();
69
+
70
+ // 2. Installation check
71
+ log.step('Checking installation...');
72
+
73
+ if (!exists(ONION_HOME)) {
74
+ log.error('Onion Framework not installed');
75
+ log.info('Run: npx @onion-ai/cli install');
76
+ process.exit(1);
77
+ }
78
+ log.success('Framework home exists (~/.claude/onion/)');
79
+
80
+ // Manifest
81
+ const manifest = readManifest();
82
+ if (manifest) {
83
+ log.success(`Version ${manifest.version} installed on ${manifest.installedAt.split('T')[0]}`);
84
+ } else {
85
+ log.warn('Installation manifest missing or corrupted');
86
+ warnings++;
87
+ }
88
+
89
+ // Commands
90
+ if (exists(ONION_COMMANDS)) {
91
+ const count = countFiles(ONION_COMMANDS);
92
+ log.success(`${count} commands installed → /onion:*`);
93
+ } else {
94
+ log.error('Commands directory missing (~/.claude/commands/onion/)');
95
+ issues++;
96
+ }
97
+
98
+ // Agents
99
+ if (exists(ONION_AGENTS)) {
100
+ const count = countFiles(ONION_AGENTS);
101
+ log.success(`${count} agents installed`);
102
+ } else {
103
+ log.error('Agents directory missing (~/.claude/agents/onion/)');
104
+ issues++;
105
+ }
106
+
107
+ // Skills
108
+ const skillCount = countOnionSkills();
109
+ if (skillCount > 0) {
110
+ log.success(`${skillCount} skills installed (onion-* prefix)`);
111
+ } else {
112
+ log.warn('No onion skills found in ~/.claude/skills/');
113
+ warnings++;
114
+ }
115
+
116
+ // CLAUDE.md integration
117
+ const claudeMd = readFile(CLAUDE_MD);
118
+ if (claudeMd && claudeMd.includes('Onion Framework')) {
119
+ log.success('CLAUDE.md integration active');
120
+ } else {
121
+ log.error('CLAUDE.md not patched — framework may not load');
122
+ log.info('Run: onion install --force');
123
+ issues++;
124
+ }
125
+
126
+ // Docs
127
+ if (exists(`${ONION_HOME}/docs`)) {
128
+ const docCount = countFiles(`${ONION_HOME}/docs`);
129
+ log.success(`${docCount} documentation files available`);
130
+ } else {
131
+ log.warn('Documentation directory missing');
132
+ warnings++;
133
+ }
134
+
135
+ log.blank();
136
+
137
+ // 3. Summary
138
+ if (issues === 0 && warnings === 0) {
139
+ log.header('All checks passed!');
140
+ log.success('Onion Framework is healthy and ready to use');
141
+ } else if (issues === 0) {
142
+ log.header(`Passed with ${warnings} warning(s)`);
143
+ log.info('Framework is functional but some optional features may be limited');
144
+ } else {
145
+ log.header(`${issues} issue(s) found, ${warnings} warning(s)`);
146
+ log.error('Run "onion install --force" to repair the installation');
147
+ }
148
+
149
+ log.blank();
150
+ return { issues, warnings };
151
+ }
152
+
153
+ function commandExists(cmd) {
154
+ try {
155
+ execSync(`which ${cmd}`, { stdio: 'ignore' });
156
+ return true;
157
+ } catch {
158
+ // Windows fallback
159
+ try {
160
+ execSync(`where ${cmd}`, { stdio: 'ignore' });
161
+ return true;
162
+ } catch {
163
+ return false;
164
+ }
165
+ }
166
+ }
167
+
168
+ function getCommandOutput(cmd) {
169
+ try {
170
+ return execSync(cmd, { encoding: 'utf-8' }).trim();
171
+ } catch {
172
+ return 'unknown';
173
+ }
174
+ }
175
+
176
+ function countOnionSkills() {
177
+ if (!existsSync(CLAUDE_SKILLS)) return 0;
178
+ return readdirSync(CLAUDE_SKILLS, { withFileTypes: true })
179
+ .filter(e => e.isDirectory() && e.name.startsWith('onion-'))
180
+ .length;
181
+ }
182
+
183
+ function readManifest() {
184
+ const content = readFile(ONION_MANIFEST);
185
+ if (!content) return null;
186
+ try {
187
+ return JSON.parse(content);
188
+ } catch {
189
+ return null;
190
+ }
191
+ }
@@ -0,0 +1,287 @@
1
+ import { existsSync, readFileSync, writeFileSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { ensureDir, readFile, writeFile, exists } from '../utils/fs.js';
4
+ import * as log from '../utils/log.js';
5
+ import { ask, confirm, select } from '../utils/prompt.js';
6
+
7
+ const ONION_DIR = '.onion';
8
+ const CONFIG_FILE = 'config.yaml';
9
+ const ENV_FILE = '.env';
10
+ const ENV_EXAMPLE_FILE = '.env.example';
11
+
12
+ export async function init(opts = {}) {
13
+ const projectRoot = process.cwd();
14
+ const onionDir = join(projectRoot, ONION_DIR);
15
+
16
+ log.header('Onion Framework — Project Setup');
17
+
18
+ // Check if already initialized
19
+ if (exists(onionDir) && !opts.force) {
20
+ log.warn(`${ONION_DIR}/ already exists in this project`);
21
+ const overwrite = await confirm('Overwrite existing configuration?', false);
22
+ if (!overwrite) {
23
+ log.info('Setup cancelled. Use --force to overwrite.');
24
+ return;
25
+ }
26
+ }
27
+
28
+ // Interactive configuration
29
+ log.step('Let\'s configure Onion for this project.\n');
30
+
31
+ // 1. Task Manager
32
+ const taskManager = await select('Which task manager does this project use?', [
33
+ { label: 'ClickUp', value: 'clickup', description: 'via MCP integration', default: true },
34
+ { label: 'Jira', value: 'jira', description: 'via API' },
35
+ { label: 'Linear', value: 'linear', description: 'via API' },
36
+ { label: 'Asana', value: 'asana', description: 'via MCP integration' },
37
+ { label: 'None', value: 'none', description: 'offline mode — local task tracking only' },
38
+ ]);
39
+
40
+ // Task manager specific config
41
+ let taskManagerConfig = {};
42
+ if (taskManager !== 'none') {
43
+ if (taskManager === 'clickup') {
44
+ taskManagerConfig.workspace_id = await ask('ClickUp Workspace ID (from URL)', '');
45
+ taskManagerConfig.default_list = await ask('Default List ID for new tasks', '');
46
+ } else if (taskManager === 'jira') {
47
+ taskManagerConfig.base_url = await ask('Jira base URL (e.g., https://company.atlassian.net)', '');
48
+ taskManagerConfig.project_key = await ask('Jira project key (e.g., PROJ)', '');
49
+ } else if (taskManager === 'linear') {
50
+ taskManagerConfig.team_id = await ask('Linear Team ID', '');
51
+ } else if (taskManager === 'asana') {
52
+ taskManagerConfig.workspace_id = await ask('Asana Workspace ID', '');
53
+ taskManagerConfig.project_id = await ask('Asana Project ID', '');
54
+ }
55
+ }
56
+
57
+ console.log('');
58
+
59
+ // 2. Language
60
+ const docsLanguage = await select('Documentation and comments language?', [
61
+ { label: 'English', value: 'en', default: true },
62
+ { label: 'Portuguese (Brazil)', value: 'pt-BR' },
63
+ { label: 'Spanish', value: 'es' },
64
+ { label: 'Other', value: 'other' },
65
+ ]);
66
+
67
+ let docsLang = docsLanguage;
68
+ if (docsLanguage === 'other') {
69
+ docsLang = await ask('Language code (e.g., fr, de, ja)', 'en');
70
+ }
71
+
72
+ console.log('');
73
+
74
+ // 3. Git Workflow
75
+ const gitFlow = await select('Git workflow for this project?', [
76
+ { label: 'GitFlow', value: 'gitflow', description: 'feature/release/hotfix branches', default: true },
77
+ { label: 'GitHub Flow', value: 'github-flow', description: 'feature branches from main' },
78
+ { label: 'Trunk-based', value: 'trunk', description: 'direct commits to main with short-lived branches' },
79
+ ]);
80
+
81
+ const mainBranch = await ask('Main branch name', 'main');
82
+ let developBranch = '';
83
+ if (gitFlow === 'gitflow') {
84
+ developBranch = await ask('Develop branch name', 'develop');
85
+ }
86
+
87
+ console.log('');
88
+
89
+ // 4. Integrations
90
+ const enableGamma = await confirm('Enable Gamma.app integration (presentations)?', false);
91
+ const enableCodeReview = await confirm('Enable automated code review?', true);
92
+
93
+ console.log('');
94
+
95
+ // Generate config
96
+ log.step('Creating configuration...');
97
+ ensureDir(onionDir);
98
+
99
+ // Write config.yaml
100
+ const config = generateConfig({
101
+ taskManager,
102
+ taskManagerConfig,
103
+ docsLang,
104
+ gitFlow,
105
+ mainBranch,
106
+ developBranch,
107
+ enableGamma,
108
+ enableCodeReview,
109
+ });
110
+ writeFile(join(onionDir, CONFIG_FILE), config);
111
+ log.success(`Created ${ONION_DIR}/${CONFIG_FILE}`);
112
+
113
+ // Write .env
114
+ const envContent = generateEnv(taskManager, enableGamma);
115
+ writeFile(join(onionDir, ENV_FILE), envContent);
116
+ log.success(`Created ${ONION_DIR}/${ENV_FILE}`);
117
+
118
+ // Write .env.example (committable reference)
119
+ const envExample = generateEnvExample(taskManager, enableGamma);
120
+ writeFile(join(onionDir, ENV_EXAMPLE_FILE), envExample);
121
+ log.success(`Created ${ONION_DIR}/${ENV_EXAMPLE_FILE}`);
122
+
123
+ // Patch .gitignore
124
+ patchGitignore(projectRoot);
125
+ log.success('Updated .gitignore');
126
+
127
+ // Summary
128
+ log.blank();
129
+ log.header('Project configured!');
130
+ log.blank();
131
+ log.info('Next steps:');
132
+ log.step(`Add your API keys to ${ONION_DIR}/.env`);
133
+ log.step(`Commit ${ONION_DIR}/config.yaml and ${ONION_DIR}/.env.example to share with your team`);
134
+ log.step('Run /onion:warm-up in Claude Code to start');
135
+ log.blank();
136
+ }
137
+
138
+ function generateConfig({ taskManager, taskManagerConfig, docsLang, gitFlow, mainBranch, developBranch, enableGamma, enableCodeReview }) {
139
+ let yaml = `# Onion Framework — Project Configuration
140
+ # Generated by @onion-ai/cli
141
+ # Commit this file to share settings with your team.
142
+
143
+ version: "1.0"
144
+
145
+ # Task Manager
146
+ task_manager:
147
+ provider: ${taskManager}
148
+ `;
149
+
150
+ // Add provider-specific fields
151
+ if (taskManager === 'clickup') {
152
+ yaml += ` workspace_id: "${taskManagerConfig.workspace_id || ''}"
153
+ default_list: "${taskManagerConfig.default_list || ''}"
154
+ `;
155
+ } else if (taskManager === 'jira') {
156
+ yaml += ` base_url: "${taskManagerConfig.base_url || ''}"
157
+ project_key: "${taskManagerConfig.project_key || ''}"
158
+ `;
159
+ } else if (taskManager === 'linear') {
160
+ yaml += ` team_id: "${taskManagerConfig.team_id || ''}"
161
+ `;
162
+ } else if (taskManager === 'asana') {
163
+ yaml += ` workspace_id: "${taskManagerConfig.workspace_id || ''}"
164
+ project_id: "${taskManagerConfig.project_id || ''}"
165
+ `;
166
+ }
167
+
168
+ yaml += `
169
+ # Language
170
+ language:
171
+ code: en
172
+ docs: ${docsLang}
173
+ commits: ${docsLang}
174
+
175
+ # Git Workflow
176
+ git:
177
+ flow: ${gitFlow}
178
+ main_branch: ${mainBranch}
179
+ `;
180
+
181
+ if (gitFlow === 'gitflow' && developBranch) {
182
+ yaml += ` develop_branch: ${developBranch}
183
+ `;
184
+ }
185
+
186
+ yaml += `
187
+ # Integrations
188
+ integrations:
189
+ gamma:
190
+ enabled: ${enableGamma}
191
+ code_review:
192
+ enabled: ${enableCodeReview}
193
+ `;
194
+
195
+ return yaml;
196
+ }
197
+
198
+ function generateEnv(taskManager, enableGamma) {
199
+ let env = `# Onion Framework — Secrets
200
+ # DO NOT COMMIT THIS FILE. It is gitignored.
201
+ # Copy from .env.example and fill in your values.
202
+
203
+ `;
204
+
205
+ if (taskManager === 'clickup') {
206
+ env += `# ClickUp API Token (get from: ClickUp > Settings > Apps)
207
+ CLICKUP_API_TOKEN=
208
+ `;
209
+ } else if (taskManager === 'jira') {
210
+ env += `# Jira API Token (get from: https://id.atlassian.com/manage-profile/security/api-tokens)
211
+ JIRA_API_TOKEN=
212
+ JIRA_USER_EMAIL=
213
+ `;
214
+ } else if (taskManager === 'linear') {
215
+ env += `# Linear API Key (get from: Linear > Settings > API)
216
+ LINEAR_API_KEY=
217
+ `;
218
+ } else if (taskManager === 'asana') {
219
+ env += `# Asana Personal Access Token (get from: Asana > Settings > Apps > Developer)
220
+ ASANA_API_TOKEN=
221
+ `;
222
+ }
223
+
224
+ if (enableGamma) {
225
+ env += `
226
+ # Gamma.app API Key (for presentation generation)
227
+ GAMMA_API_KEY=
228
+ `;
229
+ }
230
+
231
+ return env;
232
+ }
233
+
234
+ function generateEnvExample(taskManager, enableGamma) {
235
+ let env = `# Onion Framework — Environment Variables
236
+ # Copy this file to .env and fill in your values:
237
+ # cp .onion/.env.example .onion/.env
238
+
239
+ `;
240
+
241
+ if (taskManager === 'clickup') {
242
+ env += `CLICKUP_API_TOKEN=pk_your_token_here
243
+ `;
244
+ } else if (taskManager === 'jira') {
245
+ env += `JIRA_API_TOKEN=your_token_here
246
+ JIRA_USER_EMAIL=your_email@company.com
247
+ `;
248
+ } else if (taskManager === 'linear') {
249
+ env += `LINEAR_API_KEY=lin_api_your_key_here
250
+ `;
251
+ } else if (taskManager === 'asana') {
252
+ env += `ASANA_API_TOKEN=your_token_here
253
+ `;
254
+ }
255
+
256
+ if (enableGamma) {
257
+ env += `GAMMA_API_KEY=your_gamma_key_here
258
+ `;
259
+ }
260
+
261
+ return env;
262
+ }
263
+
264
+ /**
265
+ * Patch .gitignore to exclude .onion/.env (but allow .onion/config.yaml).
266
+ */
267
+ function patchGitignore(projectRoot) {
268
+ const gitignorePath = join(projectRoot, '.gitignore');
269
+ let content = '';
270
+
271
+ if (existsSync(gitignorePath)) {
272
+ content = readFileSync(gitignorePath, 'utf-8');
273
+ }
274
+
275
+ const entries = ['.onion/.env'];
276
+ const toAdd = entries.filter(entry => !content.includes(entry));
277
+
278
+ if (toAdd.length === 0) return;
279
+
280
+ const block = `
281
+ # Onion Framework secrets
282
+ ${toAdd.join('\n')}
283
+ `;
284
+
285
+ content = content.trimEnd() + '\n' + block + '\n';
286
+ writeFileSync(gitignorePath, content, 'utf-8');
287
+ }