@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.
- package/LICENSE +21 -0
- package/README.md +529 -0
- package/bin/onion.js +6 -0
- package/framework/CLAUDE.md +45 -0
- package/framework/VERSION +1 -0
- package/framework/agents/compliance/iso-22301-specialist.md +985 -0
- package/framework/agents/compliance/iso-27001-specialist.md +713 -0
- package/framework/agents/compliance/pmbok-specialist.md +739 -0
- package/framework/agents/compliance/security-information-master.md +907 -0
- package/framework/agents/compliance/soc2-specialist.md +889 -0
- package/framework/agents/deployment/docker-specialist.md +1192 -0
- package/framework/agents/development/c4-architecture-specialist.md +745 -0
- package/framework/agents/development/c4-documentation-specialist.md +695 -0
- package/framework/agents/development/clickup-specialist.md +396 -0
- package/framework/agents/development/cursor-specialist.md +277 -0
- package/framework/agents/development/docs-reverse-engineer.md +417 -0
- package/framework/agents/development/gamma-api-specialist.md +1168 -0
- package/framework/agents/development/gitflow-specialist.md +1206 -0
- package/framework/agents/development/linux-security-specialist.md +675 -0
- package/framework/agents/development/mermaid-specialist.md +515 -0
- package/framework/agents/development/nodejs-specialist.md +672 -0
- package/framework/agents/development/nx-migration-specialist.md +866 -0
- package/framework/agents/development/nx-monorepo-specialist.md +618 -0
- package/framework/agents/development/postgres-specialist.md +1123 -0
- package/framework/agents/development/react-developer.md +131 -0
- package/framework/agents/development/runflow-specialist.md +277 -0
- package/framework/agents/development/system-documentation-orchestrator.md +1387 -0
- package/framework/agents/development/task-specialist.md +677 -0
- package/framework/agents/git/branch-code-reviewer.md +225 -0
- package/framework/agents/git/branch-documentation-writer.md +161 -0
- package/framework/agents/git/branch-metaspec-checker.md +67 -0
- package/framework/agents/git/branch-test-planner.md +176 -0
- package/framework/agents/meta/agent-creator-specialist.md +1266 -0
- package/framework/agents/meta/command-creator-specialist.md +1676 -0
- package/framework/agents/meta/metaspec-gate-keeper.md +240 -0
- package/framework/agents/meta/onion.md +824 -0
- package/framework/agents/product/branding-positioning-specialist.md +1029 -0
- package/framework/agents/product/extract-meeting-specialist.md +394 -0
- package/framework/agents/product/meeting-consolidator.md +482 -0
- package/framework/agents/product/pain-price-specialist.md +508 -0
- package/framework/agents/product/presentation-orchestrator.md +1190 -0
- package/framework/agents/product/product-agent.md +201 -0
- package/framework/agents/product/story-points-framework-specialist.md +538 -0
- package/framework/agents/product/storytelling-business-specialist.md +890 -0
- package/framework/agents/research/research-agent.md +292 -0
- package/framework/agents/review/code-reviewer.md +154 -0
- package/framework/agents/review/corporate-compliance-specialist.md +370 -0
- package/framework/agents/testing/test-agent.md +424 -0
- package/framework/agents/testing/test-engineer.md +294 -0
- package/framework/agents/testing/test-planner.md +117 -0
- package/framework/commands/common/prompts/README.md +208 -0
- package/framework/commands/common/prompts/clickup-patterns.md +144 -0
- package/framework/commands/common/prompts/code-review-checklist.md +168 -0
- package/framework/commands/common/prompts/git-workflow-patterns.md +235 -0
- package/framework/commands/common/prompts/output-formats.md +240 -0
- package/framework/commands/common/prompts/technical.md +194 -0
- package/framework/commands/common/templates/abstraction-template.md +399 -0
- package/framework/commands/common/templates/agent-template.md +353 -0
- package/framework/commands/common/templates/business_context_template.md +748 -0
- package/framework/commands/common/templates/command-template.md +273 -0
- package/framework/commands/common/templates/technical_context_template.md +526 -0
- package/framework/commands/design/screen-spec.md +505 -0
- package/framework/commands/development/runflow-dev.md +465 -0
- package/framework/commands/docs/build-business-docs.md +299 -0
- package/framework/commands/docs/build-compliance-docs.md +143 -0
- package/framework/commands/docs/build-index.md +119 -0
- package/framework/commands/docs/build-tech-docs.md +221 -0
- package/framework/commands/docs/docs-health.md +141 -0
- package/framework/commands/docs/help.md +278 -0
- package/framework/commands/docs/refine-vision.md +25 -0
- package/framework/commands/docs/reverse-consolidate.md +158 -0
- package/framework/commands/docs/sync-sessions.md +354 -0
- package/framework/commands/docs/validate-docs.md +157 -0
- package/framework/commands/engineer/bump.md +29 -0
- package/framework/commands/engineer/docs.md +11 -0
- package/framework/commands/engineer/hotfix.md +183 -0
- package/framework/commands/engineer/plan.md +85 -0
- package/framework/commands/engineer/pr-update.md +219 -0
- package/framework/commands/engineer/pr.md +117 -0
- package/framework/commands/engineer/pre-pr.md +81 -0
- package/framework/commands/engineer/start.md +254 -0
- package/framework/commands/engineer/validate-phase-sync.md +134 -0
- package/framework/commands/engineer/warm-up.md +20 -0
- package/framework/commands/engineer/work.md +155 -0
- package/framework/commands/f/company-context-extractor.md +93 -0
- package/framework/commands/f/process-meetings.md +103 -0
- package/framework/commands/git/README.md +682 -0
- package/framework/commands/git/code-review.md +213 -0
- package/framework/commands/git/fast-commit.md +43 -0
- package/framework/commands/git/feature/finish.md +88 -0
- package/framework/commands/git/feature/publish.md +89 -0
- package/framework/commands/git/feature/start.md +172 -0
- package/framework/commands/git/help.md +100 -0
- package/framework/commands/git/hotfix/finish.md +96 -0
- package/framework/commands/git/hotfix/start.md +92 -0
- package/framework/commands/git/init.md +111 -0
- package/framework/commands/git/release/finish.md +96 -0
- package/framework/commands/git/release/start.md +93 -0
- package/framework/commands/git/sync.md +199 -0
- package/framework/commands/meta/all-tools.md +58 -0
- package/framework/commands/meta/analyze-complex-problem.md +186 -0
- package/framework/commands/meta/create-abstraction.md +882 -0
- package/framework/commands/meta/create-agent-express.md +98 -0
- package/framework/commands/meta/create-agent.md +210 -0
- package/framework/commands/meta/create-command.md +203 -0
- package/framework/commands/meta/create-knowledge-base.md +143 -0
- package/framework/commands/meta/create-task-structure.md +150 -0
- package/framework/commands/meta/setup-integration.md +274 -0
- package/framework/commands/onion.md +169 -0
- package/framework/commands/product/README.md +249 -0
- package/framework/commands/product/analyze-pain-price.md +694 -0
- package/framework/commands/product/branding.md +458 -0
- package/framework/commands/product/check.md +46 -0
- package/framework/commands/product/checklist-sync.md +239 -0
- package/framework/commands/product/collect.md +95 -0
- package/framework/commands/product/consolidate-meetings.md +291 -0
- package/framework/commands/product/estimate.md +511 -0
- package/framework/commands/product/extract-meeting.md +226 -0
- package/framework/commands/product/feature.md +416 -0
- package/framework/commands/product/light-arch.md +82 -0
- package/framework/commands/product/presentation.md +174 -0
- package/framework/commands/product/refine.md +161 -0
- package/framework/commands/product/spec.md +79 -0
- package/framework/commands/product/task-check.md +378 -0
- package/framework/commands/product/task.md +603 -0
- package/framework/commands/product/validate-task.md +325 -0
- package/framework/commands/product/warm-up.md +24 -0
- package/framework/commands/quick/analisys.md +17 -0
- package/framework/commands/test/e2e.md +377 -0
- package/framework/commands/test/integration.md +508 -0
- package/framework/commands/test/unit.md +381 -0
- package/framework/commands/validate/collab/pair-testing.md +657 -0
- package/framework/commands/validate/collab/three-amigos.md +534 -0
- package/framework/commands/validate/qa-points/estimate.md +660 -0
- package/framework/commands/validate/test-strategy/analyze.md +1201 -0
- package/framework/commands/validate/test-strategy/create.md +411 -0
- package/framework/commands/validate/workflow.md +370 -0
- package/framework/commands/warm-up.md +20 -0
- package/framework/docs/architecture/acoplamento-clickup-problema-analise.md +468 -0
- package/framework/docs/architecture/desacoplamento-roadmap.md +364 -0
- package/framework/docs/architecture/validacao-fase-1.md +235 -0
- package/framework/docs/c4/c4-detection-rules.md +395 -0
- package/framework/docs/c4/c4-documentation-templates.md +579 -0
- package/framework/docs/c4/c4-mermaid-patterns.md +331 -0
- package/framework/docs/c4/c4-templates.md +256 -0
- package/framework/docs/clickup/clickup-acceptance-criteria-strategy.md +329 -0
- package/framework/docs/clickup/clickup-auto-update-strategy.md +340 -0
- package/framework/docs/clickup/clickup-comment-formatter.md +239 -0
- package/framework/docs/clickup/clickup-description-fix.md +384 -0
- package/framework/docs/clickup/clickup-dual-comment-strategy.md +528 -0
- package/framework/docs/clickup/clickup-formatting.md +302 -0
- package/framework/docs/clickup/separador-tamanho-otimizado.md +258 -0
- package/framework/docs/engineer/pre-pr-acceptance-validation.md +256 -0
- package/framework/docs/onion/ESPERANTO.md +293 -0
- package/framework/docs/onion/agents-reference.md +832 -0
- package/framework/docs/onion/clickup-integration.md +780 -0
- package/framework/docs/onion/commands-guide.md +924 -0
- package/framework/docs/onion/engineering-flows.md +900 -0
- package/framework/docs/onion/getting-started.md +803 -0
- package/framework/docs/onion/maintenance-checklist.md +421 -0
- package/framework/docs/onion/naming-conventions.md +286 -0
- package/framework/docs/onion/practical-examples.md +854 -0
- package/framework/docs/product/story-points-integration.md +269 -0
- package/framework/docs/product/story-points-validation.md +237 -0
- package/framework/docs/reviews/task-manager-docs-review-2025-11-24.md +184 -0
- package/framework/docs/strategies/clickup-comment-patterns.md +766 -0
- package/framework/docs/strategies/clickup-integration-tests.md +602 -0
- package/framework/docs/strategies/clickup-mcp-wrappers-tests.md +888 -0
- package/framework/docs/strategies/clickup-regression-tests.md +587 -0
- package/framework/docs/strategies/visual-patterns.md +315 -0
- package/framework/docs/templates/README.md +649 -0
- package/framework/docs/templates/adr-template.md +226 -0
- package/framework/docs/templates/analysis-template.md +280 -0
- package/framework/docs/templates/execution-plan-template.md +430 -0
- package/framework/docs/templates/guide-template.md +367 -0
- package/framework/docs/templates/phase-execution-prompt-template.md +504 -0
- package/framework/docs/templates/reference-template.md +522 -0
- package/framework/docs/templates/solution-template.md +390 -0
- package/framework/docs/tools/README.md +356 -0
- package/framework/docs/tools/agents.md +365 -0
- package/framework/docs/tools/commands.md +669 -0
- package/framework/docs/tools/cursor.md +539 -0
- package/framework/docs/tools/mcps.md +937 -0
- package/framework/docs/tools/rules.md +461 -0
- package/framework/rules/language-and-documentation.mdc +371 -0
- package/framework/rules/nestjs-controllers.md +83 -0
- package/framework/rules/nestjs-dtos.md +255 -0
- package/framework/rules/nestjs-modules.md +141 -0
- package/framework/rules/nestjs-services.md +230 -0
- package/framework/rules/nx-rules.mdc +41 -0
- package/framework/rules/onion-patterns.mdc +197 -0
- package/framework/skills/codebase-visualizer/SKILL.md +26 -0
- package/framework/skills/codebase-visualizer/scripts/visualize.py +131 -0
- package/framework/skills/collect/SKILL.md +84 -0
- package/framework/skills/create-rule/SKILL.md +152 -0
- package/framework/skills/db-schema-visualizer/SKILL.md +49 -0
- package/framework/skills/db-schema-visualizer/scripts/visualize.py +1191 -0
- package/framework/skills/sync-meetings/SKILL.md +239 -0
- package/framework/utils/clickup-mcp-wrappers.md +744 -0
- package/framework/utils/date-time-standards.md +200 -0
- package/framework/utils/task-manager/README.md +94 -0
- package/framework/utils/task-manager/adapters/asana.md +377 -0
- package/framework/utils/task-manager/adapters/clickup.md +467 -0
- package/framework/utils/task-manager/adapters/linear.md +421 -0
- package/framework/utils/task-manager/detector.md +299 -0
- package/framework/utils/task-manager/factory.md +363 -0
- package/framework/utils/task-manager/interface.md +248 -0
- package/framework/utils/task-manager/types.md +409 -0
- package/package.json +41 -0
- package/src/cli.js +73 -0
- package/src/commands/doctor.js +191 -0
- package/src/commands/init.js +287 -0
- package/src/commands/install.js +261 -0
- package/src/commands/list.js +152 -0
- package/src/commands/uninstall.js +90 -0
- package/src/commands/update.js +26 -0
- package/src/utils/fs.js +89 -0
- package/src/utils/log.js +35 -0
- package/src/utils/paths.js +32 -0
- 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
|
+
}
|