@axiomatic-labs/claudeflow 2.3.9 → 2.4.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/bin/cli.js CHANGED
@@ -1,164 +1,43 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // npm shim: downloads the Go binary if needed, then delegates all commands to it.
3
+ // npx entry point: handles install/update and version commands directly.
4
+ // No Go binary — downloads ZIP and extracts skill files to disk.
4
5
 
5
- const { spawn } = require('child_process');
6
6
  const path = require('path');
7
- const fs = require('fs');
8
- const os = require('os');
9
- const https = require('https');
10
-
11
- const OWNER = 'axiomatic-labs';
12
- const REPO = 'claudeflow-cli';
13
- const BIN_DIR = path.join(os.homedir(), '.claudeflow', 'bin');
14
- const isWindows = os.platform() === 'win32';
15
- const BIN_PATH = path.join(BIN_DIR, isWindows ? 'claudeflow.exe' : 'claudeflow');
16
- const VERSION_PATH = path.join(os.homedir(), '.claudeflow', 'binary-version');
17
-
18
- // Detect platform: darwin-arm64, darwin-amd64, linux-amd64, windows-amd64
19
- function getPlatformBinary() {
20
- const platform = os.platform(); // darwin, linux, win32
21
- const arch = os.arch(); // arm64, x64
22
- const goArch = arch === 'x64' ? 'amd64' : arch;
23
- const goPlatform = platform === 'win32' ? 'windows' : platform;
24
- const ext = platform === 'win32' ? '.exe' : '';
25
- return `claudeflow-${goPlatform}-${goArch}${ext}`;
26
- }
27
-
28
- function fetchUrl(url, headers = {}) {
29
- return new Promise((resolve, reject) => {
30
- const mod = url.startsWith('https') ? https : require('http');
31
- mod.get(url, { headers: { 'User-Agent': 'claudeflow-cli', ...headers } }, (res) => {
32
- if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
33
- return fetchUrl(res.headers.location, {}).then(resolve).catch(reject);
34
- }
35
- if (res.statusCode !== 200) {
36
- let body = '';
37
- res.on('data', (d) => body += d);
38
- res.on('end', () => reject(new Error(`HTTP ${res.statusCode}: ${body.slice(0, 200)}`)));
39
- return;
40
- }
41
- const chunks = [];
42
- res.on('data', (d) => chunks.push(d));
43
- res.on('end', () => resolve(Buffer.concat(chunks)));
44
- }).on('error', reject);
45
- });
46
- }
47
-
48
- async function downloadBinary(token) {
49
- const ui = require('../lib/ui.js');
50
-
51
- ui.step('Fetching latest release...');
52
-
53
- const releaseData = await fetchUrl(
54
- `https://api.github.com/repos/${OWNER}/${REPO}/releases/latest`,
55
- { Authorization: `Bearer ${token}`, Accept: 'application/vnd.github+json' }
56
- );
57
- const release = JSON.parse(releaseData.toString());
58
-
59
- const binaryName = getPlatformBinary();
60
- const asset = release.assets.find((a) => a.name === binaryName);
61
- if (!asset) {
62
- ui.error(`No binary found for your platform: ${binaryName}`);
63
- ui.info(`Available: ${release.assets.map((a) => a.name).join(', ')}`);
64
- process.exit(1);
65
- }
66
-
67
- ui.step(`Downloading ${release.tag_name} (${binaryName})...`);
68
-
69
- const binaryData = await fetchUrl(
70
- `https://api.github.com/repos/${OWNER}/${REPO}/releases/assets/${asset.id}`,
71
- { Authorization: `Bearer ${token}`, Accept: 'application/octet-stream' }
72
- );
73
-
74
- fs.mkdirSync(BIN_DIR, { recursive: true });
75
- fs.writeFileSync(BIN_PATH, binaryData, { mode: 0o755 });
76
-
77
- // Ad-hoc sign on macOS (required by recent macOS versions)
78
- if (os.platform() === 'darwin') {
79
- const { execSync } = require('child_process');
80
- try {
81
- execSync(`codesign --force --sign - "${BIN_PATH}"`, { stdio: 'pipe' });
82
- } catch {}
83
- }
84
-
85
- fs.writeFileSync(VERSION_PATH, release.tag_name + '\n');
86
-
87
- ui.success(`Claudeflow ${release.tag_name} installed to ~/.claudeflow/bin/`);
88
- return release.tag_name;
89
- }
90
-
91
- async function ensureBinary() {
92
- if (!fs.existsSync(BIN_PATH)) {
93
- // First run — interactive auth + download
94
- const ui = require('../lib/ui.js');
95
- const { requireAuth } = require('../lib/auth.js');
96
- ui.banner();
97
- ui.step('First run — downloading Claudeflow binary...');
98
-
99
- const token = await requireAuth();
100
- try {
101
- await downloadBinary(token);
102
- } catch (err) {
103
- ui.error('Could not download Claudeflow binary.');
104
- ui.info('Ensure your token has the "repo" scope and can access axiomatic-labs/claudeflow-cli.');
105
- process.exit(1);
106
- }
107
- return;
108
- }
109
-
110
- // Binary exists — check for updates silently
111
- try {
112
- const { getGitHubToken } = require('../lib/auth.js');
113
- const token = getGitHubToken();
114
- if (!token) return; // No cached token, skip check
115
-
116
- const installed = fs.existsSync(VERSION_PATH)
117
- ? fs.readFileSync(VERSION_PATH, 'utf-8').trim()
118
- : null;
119
-
120
- const releaseData = await fetchUrl(
121
- `https://api.github.com/repos/${OWNER}/${REPO}/releases/latest`,
122
- { Authorization: `Bearer ${token}`, Accept: 'application/vnd.github+json' }
123
- );
124
- const release = JSON.parse(releaseData.toString());
125
- const latest = release.tag_name;
126
-
127
- if (installed && installed === latest) return; // Already up to date
128
-
129
- const ui = require('../lib/ui.js');
130
- ui.banner();
131
- ui.step(`Updating binary to ${latest}...`);
132
- await downloadBinary(token);
133
- } catch {
134
- // Network/API error — skip silently, use existing binary
135
- }
136
- }
137
7
 
138
8
  async function main() {
139
9
  const args = process.argv.slice(2);
140
-
141
- // These commands need the Go binary
142
- await ensureBinary();
143
-
144
- // Delegate to Go binary with transparent I/O
145
- const child = spawn(BIN_PATH, args, {
146
- stdio: 'inherit',
147
- env: process.env,
148
- });
149
-
150
- child.on('exit', (code) => {
151
- process.exit(code || 0);
152
- });
153
-
154
- child.on('error', (err) => {
155
- if (err.code === 'ENOENT') {
156
- console.error('Claudeflow binary not found. Try reinstalling: npx @axiomatic-labs/claudeflow');
157
- } else {
158
- console.error(`Failed to start claudeflow: ${err.message}`);
10
+ const command = args[0] || '';
11
+
12
+ switch (command) {
13
+ case '':
14
+ case 'install':
15
+ case 'init':
16
+ case 'update': {
17
+ const install = require('../lib/install.js');
18
+ await install();
19
+ break;
20
+ }
21
+ case 'version':
22
+ case '--version':
23
+ case '-v': {
24
+ const version = require('../lib/version.js');
25
+ await version();
26
+ break;
159
27
  }
160
- process.exit(1);
161
- });
28
+ default: {
29
+ const ui = require('../lib/ui.js');
30
+ ui.banner();
31
+ console.log(' Usage: npx @axiomatic-labs/claudeflow [command]');
32
+ console.log('');
33
+ console.log(' Commands:');
34
+ console.log(` ${ui.CYAN}(default)${ui.RESET} Install or update Claudeflow`);
35
+ console.log(` ${ui.CYAN}update${ui.RESET} Alias for default (re-download template files)`);
36
+ console.log(` ${ui.CYAN}version${ui.RESET} Show version info`);
37
+ console.log('');
38
+ break;
39
+ }
40
+ }
162
41
  }
163
42
 
164
43
  main().catch((err) => {
package/lib/install.js ADDED
@@ -0,0 +1,230 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { execSync } = require('child_process');
4
+ const { requireAuth } = require('./auth.js');
5
+ const { getLatestRelease, downloadReleaseAsset } = require('./download.js');
6
+ const { writeLocalVersion, readLocalVersion } = require('./version.js');
7
+ const ui = require('./ui.js');
8
+
9
+ // Template skills that ship with the ZIP — only these get overwritten.
10
+ // User-generated skills (from /setup, /update) are preserved.
11
+ const TEMPLATE_SKILLS = new Set([
12
+ 'claudeflow-init',
13
+ 'claudeflow-update',
14
+ 'claudeflow-design-tokens',
15
+ 'claudeflow-create-ui',
16
+ 'claudeflow-checkpoints',
17
+ ]);
18
+
19
+ async function run() {
20
+ const current = readLocalVersion();
21
+ const isUpdate = !!current;
22
+
23
+ ui.banner(current || undefined);
24
+
25
+ ui.step('Authenticating with GitHub...');
26
+ const token = await requireAuth();
27
+
28
+ ui.step('Fetching latest release...');
29
+ const release = await getLatestRelease(token);
30
+ const version = release.tag_name;
31
+
32
+ // Find the ZIP asset
33
+ const asset = release.assets.find((a) => a.name.endsWith('.zip'));
34
+ if (!asset) {
35
+ ui.error('No ZIP asset found in the latest release.');
36
+ process.exit(1);
37
+ }
38
+
39
+ ui.step(`Downloading ${version}...`);
40
+ const zipBuffer = await downloadReleaseAsset(asset, token);
41
+
42
+ // Write ZIP to temp file and extract to a temp directory
43
+ const tmpZip = path.join(require('os').tmpdir(), `claudeflow-${Date.now()}.zip`);
44
+ const tmpExtract = path.join(require('os').tmpdir(), `claudeflow-extract-${Date.now()}`);
45
+ fs.writeFileSync(tmpZip, zipBuffer);
46
+ fs.mkdirSync(tmpExtract, { recursive: true });
47
+
48
+ try {
49
+ ui.step('Extracting template files...');
50
+ execSync(`unzip -o "${tmpZip}" -d "${tmpExtract}"`, { stdio: 'pipe' });
51
+
52
+ const cwd = process.cwd();
53
+ const srcClaude = path.join(tmpExtract, '.claude');
54
+
55
+ // Copy settings.json
56
+ const srcSettings = path.join(srcClaude, 'settings.json');
57
+ const dstSettings = path.join(cwd, '.claude', 'settings.json');
58
+ fs.mkdirSync(path.join(cwd, '.claude'), { recursive: true });
59
+ if (fs.existsSync(srcSettings)) {
60
+ fs.copyFileSync(srcSettings, dstSettings);
61
+ }
62
+
63
+ // Copy template skills only (safe for both fresh + update — fresh has no user skills)
64
+ const srcSkills = path.join(srcClaude, 'skills');
65
+ const dstSkills = path.join(cwd, '.claude', 'skills');
66
+ if (fs.existsSync(srcSkills)) {
67
+ fs.mkdirSync(dstSkills, { recursive: true });
68
+ const skillDirs = fs.readdirSync(srcSkills, { withFileTypes: true });
69
+ for (const entry of skillDirs) {
70
+ if (entry.isDirectory() && TEMPLATE_SKILLS.has(entry.name)) {
71
+ copyDirSync(path.join(srcSkills, entry.name), path.join(dstSkills, entry.name));
72
+ }
73
+ }
74
+ }
75
+
76
+ // Copy all hooks
77
+ const srcHooks = path.join(srcClaude, 'hooks');
78
+ const dstHooks = path.join(cwd, '.claude', 'hooks');
79
+ if (fs.existsSync(srcHooks)) {
80
+ copyDirSync(srcHooks, dstHooks);
81
+ }
82
+
83
+ // Copy all docs
84
+ const srcDocs = path.join(srcClaude, 'docs');
85
+ const dstDocs = path.join(cwd, '.claude', 'docs');
86
+ if (fs.existsSync(srcDocs)) {
87
+ copyDirSync(srcDocs, dstDocs);
88
+ }
89
+
90
+ // Ensure .claude/tmp exists
91
+ fs.mkdirSync(path.join(cwd, '.claude', 'tmp'), { recursive: true });
92
+
93
+ // CLAUDE.md — only copy on fresh install (updates generate it via /setup and /update skills)
94
+ if (!isUpdate) {
95
+ const srcClaude_md = path.join(tmpExtract, 'CLAUDE.md');
96
+ const dstClaude_md = path.join(cwd, 'CLAUDE.md');
97
+ if (fs.existsSync(srcClaude_md)) {
98
+ fs.copyFileSync(srcClaude_md, dstClaude_md);
99
+ }
100
+ }
101
+
102
+ // Copy .mcp.json to project root
103
+ const srcMcp = path.join(tmpExtract, '.mcp.json');
104
+ const dstMcp = path.join(cwd, '.mcp.json');
105
+ if (fs.existsSync(srcMcp)) {
106
+ fs.copyFileSync(srcMcp, dstMcp);
107
+ }
108
+
109
+ // Write version file
110
+ writeLocalVersion(version);
111
+
112
+ } finally {
113
+ fs.unlinkSync(tmpZip);
114
+ fs.rmSync(tmpExtract, { recursive: true, force: true });
115
+ }
116
+
117
+ // Count installed items
118
+ const cwd = process.cwd();
119
+ const skillsDir = path.join(cwd, '.claude', 'skills');
120
+ let skillCount = 0;
121
+ try {
122
+ skillCount = fs.readdirSync(skillsDir, { withFileTypes: true }).filter((e) => e.isDirectory()).length;
123
+ } catch {}
124
+
125
+ const hooksDir = path.join(cwd, '.claude', 'hooks');
126
+ let hookCount = 0;
127
+ try {
128
+ hookCount = fs.readdirSync(hooksDir, { withFileTypes: true }).filter((e) => e.isDirectory()).length;
129
+ } catch {}
130
+
131
+ const docsDir = path.join(cwd, '.claude', 'docs');
132
+ let docCount = 0;
133
+ try {
134
+ docCount = fs.readdirSync(docsDir).filter((f) => !f.startsWith('.')).length;
135
+ } catch {}
136
+
137
+ console.log('');
138
+ if (isUpdate) {
139
+ ui.success(`${skillCount} skills (${TEMPLATE_SKILLS.size} template updated, user skills preserved)`);
140
+ ui.success(`${hookCount} hooks updated`);
141
+ ui.success(`${docCount} docs updated`);
142
+
143
+ if (current === version) {
144
+ ui.done(`Claudeflow ${version} reinstalled.`);
145
+ } else {
146
+ ui.done(`Claudeflow updated: ${current} → ${version}`);
147
+ }
148
+ } else {
149
+ ui.success(`${skillCount} skills installed`);
150
+ ui.success(`${hookCount} hooks installed`);
151
+ ui.success(`${docCount} docs installed`);
152
+
153
+ ui.done(`Claudeflow ${version} installed.`);
154
+
155
+ // Getting started guide with project detection
156
+ showGettingStarted(cwd);
157
+ }
158
+ }
159
+
160
+ function showGettingStarted(cwd) {
161
+ const MANIFESTS = ['package.json', 'pyproject.toml', 'Gemfile', 'go.mod', 'Cargo.toml', 'composer.json'];
162
+ const SKIP_DIRS = new Set(['node_modules', 'vendor', '__pycache__', 'dist', 'build', '.next', '.nuxt', '.output', '.claude']);
163
+
164
+ const rootHasManifest = MANIFESTS.some((f) => fs.existsSync(path.join(cwd, f)));
165
+
166
+ // Scan first-level subdirs for manifests (multi-stack detection)
167
+ const stackDirs = [];
168
+ try {
169
+ const entries = fs.readdirSync(cwd, { withFileTypes: true });
170
+ for (const entry of entries) {
171
+ if (!entry.isDirectory() || entry.name.startsWith('.') || SKIP_DIRS.has(entry.name)) continue;
172
+ if (MANIFESTS.some((f) => fs.existsSync(path.join(cwd, entry.name, f)))) {
173
+ stackDirs.push(entry.name);
174
+ }
175
+ }
176
+ } catch {}
177
+
178
+ const isMultiStack = stackDirs.length > 1 || (rootHasManifest && stackDirs.length > 0);
179
+ const isGreenfield = !rootHasManifest && stackDirs.length === 0;
180
+
181
+ console.log(` ${ui.BOLD}Getting started:${ui.RESET}`);
182
+ console.log('');
183
+ console.log(` 1. Run ${ui.CYAN}claude${ui.RESET} to start Claude Code`);
184
+
185
+ if (isGreenfield) {
186
+ console.log(` 2. Type ${ui.CYAN}/claudeflow-init${ui.RESET} to scaffold your project`);
187
+ console.log('');
188
+ console.log(` ${ui.DIM}Claudeflow will ask what you want to build, research${ui.RESET}`);
189
+ console.log(` ${ui.DIM}the best stack, and generate project-specific skills.${ui.RESET}`);
190
+ } else if (isMultiStack) {
191
+ console.log(` 2. Type ${ui.CYAN}/claudeflow-update${ui.RESET} to detect your stacks and generate project-specific skills`);
192
+ console.log('');
193
+ ui.info(`Multi-stack project detected: ${stackDirs.join(', ')}${rootHasManifest ? ' + root' : ''}`);
194
+ console.log('');
195
+ console.log(` ${ui.BOLD}After setup:${ui.RESET}`);
196
+ console.log(` ${ui.DIM}Just describe what you want — Claudeflow handles the rest.${ui.RESET}`);
197
+ } else {
198
+ // Single-stack existing project
199
+ console.log(` 2. Type ${ui.CYAN}/claudeflow-update${ui.RESET} to detect your stack and generate project-specific skills`);
200
+ console.log(` 3. Tell Claude what you want — it handles the rest`);
201
+ }
202
+
203
+ console.log('');
204
+ console.log(` ${ui.BOLD}Commands:${ui.RESET}`);
205
+ console.log(` ${ui.CYAN}/claudeflow-init${ui.RESET} ${ui.DIM}Scaffold a new project (greenfield)${ui.RESET}`);
206
+ console.log(` ${ui.CYAN}/claudeflow-update${ui.RESET} ${ui.DIM}Detect stack and generate skills for existing project${ui.RESET}`);
207
+ console.log(` ${ui.CYAN}/claudeflow-design-tokens${ui.RESET} ${ui.DIM}Create design reference from a site or screenshot${ui.RESET}`);
208
+ console.log(` ${ui.CYAN}/claudeflow-create-ui${ui.RESET} ${ui.DIM}Build pages from visual references${ui.RESET}`);
209
+ console.log(` ${ui.CYAN}/claudeflow-checkpoints${ui.RESET} ${ui.DIM}Auto-save work with git checkpoints${ui.RESET}`);
210
+ console.log('');
211
+ console.log(` ${ui.DIM}Docs: https://claudeflow.dev${ui.RESET}`);
212
+ console.log('');
213
+ }
214
+
215
+ // Recursively copy a directory, creating parents as needed
216
+ function copyDirSync(src, dst) {
217
+ fs.mkdirSync(dst, { recursive: true });
218
+ const entries = fs.readdirSync(src, { withFileTypes: true });
219
+ for (const entry of entries) {
220
+ const srcPath = path.join(src, entry.name);
221
+ const dstPath = path.join(dst, entry.name);
222
+ if (entry.isDirectory()) {
223
+ copyDirSync(srcPath, dstPath);
224
+ } else {
225
+ fs.copyFileSync(srcPath, dstPath);
226
+ }
227
+ }
228
+ }
229
+
230
+ module.exports = run;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axiomatic-labs/claudeflow",
3
- "version": "2.3.9",
3
+ "version": "2.4.1",
4
4
  "description": "Claudeflow — AI-powered development toolkit for Claude Code. Skills, agents, hooks, and quality gates that ship production apps.",
5
5
  "bin": {
6
6
  "claudeflow": "./bin/cli.js"
package/lib/init.js DELETED
@@ -1,138 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const { execSync } = require('child_process');
4
- const { requireAuth } = require('./auth.js');
5
- const { getLatestRelease, downloadReleaseAsset } = require('./download.js');
6
- const { writeLocalVersion } = require('./version.js');
7
- const ui = require('./ui.js');
8
-
9
- async function run() {
10
- // Check if already initialized
11
- const versionFile = path.join(process.cwd(), '.claude', '.claudeflow-version');
12
- if (fs.existsSync(versionFile)) {
13
- const current = fs.readFileSync(versionFile, 'utf-8').trim();
14
- ui.banner(current);
15
- ui.warn(`Already initialized at ${current}.`);
16
- ui.info('Run: claudeflow update');
17
- console.log('');
18
- process.exit(1);
19
- }
20
-
21
- ui.banner();
22
-
23
- ui.step('Authenticating with GitHub...');
24
- const token = await requireAuth();
25
-
26
- ui.step('Fetching latest release...');
27
- const release = await getLatestRelease(token);
28
- const version = release.tag_name;
29
-
30
- // Find the ZIP asset
31
- const asset = release.assets.find((a) => a.name.endsWith('.zip'));
32
- if (!asset) {
33
- ui.error('No ZIP asset found in the latest release.');
34
- process.exit(1);
35
- }
36
-
37
- ui.step(`Downloading ${version}...`);
38
- const zipBuffer = await downloadReleaseAsset(asset, token);
39
-
40
- // Write ZIP to temp file and extract
41
- const tmpZip = path.join(require('os').tmpdir(), `claudeflow-${Date.now()}.zip`);
42
- fs.writeFileSync(tmpZip, zipBuffer);
43
-
44
- try {
45
- ui.step('Extracting template files...');
46
- execSync(`unzip -o "${tmpZip}" ".claude/*" -d "${process.cwd()}"`, { stdio: 'pipe' });
47
- } finally {
48
- fs.unlinkSync(tmpZip);
49
- }
50
-
51
- // Ensure .claude/tmp exists
52
- fs.mkdirSync(path.join(process.cwd(), '.claude', 'tmp'), { recursive: true });
53
-
54
- // Write version file
55
- writeLocalVersion(version);
56
-
57
- // Count installed items
58
- const skillsDir = path.join(process.cwd(), '.claude', 'skills');
59
- let skillCount = 0;
60
- try {
61
- skillCount = fs.readdirSync(skillsDir, { withFileTypes: true }).filter((e) => e.isDirectory()).length;
62
- } catch {}
63
-
64
- const hooksDir = path.join(process.cwd(), '.claude', 'hooks');
65
- let hookCount = 0;
66
- try {
67
- hookCount = fs.readdirSync(hooksDir, { withFileTypes: true }).filter((e) => e.isDirectory()).length;
68
- } catch {}
69
-
70
- const docsDir = path.join(process.cwd(), '.claude', 'docs');
71
- let docCount = 0;
72
- try {
73
- docCount = fs.readdirSync(docsDir).filter((f) => !f.startsWith('.')).length;
74
- } catch {}
75
-
76
- console.log('');
77
- ui.success(`${skillCount} skills installed`);
78
- ui.success(`${hookCount} hooks installed`);
79
- ui.success(`${docCount} docs installed`);
80
-
81
- ui.done(`Claudeflow ${version} installed.`);
82
-
83
- // Detect project type: greenfield, single-stack, or multi-stack
84
- const MANIFESTS = ['package.json', 'pyproject.toml', 'Gemfile', 'go.mod', 'Cargo.toml', 'composer.json'];
85
- const SKIP_DIRS = new Set(['node_modules', 'vendor', '__pycache__', 'dist', 'build', '.next', '.nuxt', '.output', '.claude']);
86
-
87
- const rootHasManifest = MANIFESTS.some((f) => fs.existsSync(path.join(process.cwd(), f)));
88
-
89
- // Scan first-level subdirs for manifests (multi-stack detection)
90
- const stackDirs = [];
91
- try {
92
- const entries = fs.readdirSync(process.cwd(), { withFileTypes: true });
93
- for (const entry of entries) {
94
- if (!entry.isDirectory() || entry.name.startsWith('.') || SKIP_DIRS.has(entry.name)) continue;
95
- if (MANIFESTS.some((f) => fs.existsSync(path.join(process.cwd(), entry.name, f)))) {
96
- stackDirs.push(entry.name);
97
- }
98
- }
99
- } catch {}
100
-
101
- const isMultiStack = stackDirs.length > 1 || (rootHasManifest && stackDirs.length > 0);
102
- const isGreenfield = !rootHasManifest && stackDirs.length === 0;
103
-
104
- console.log(` ${ui.BOLD}Getting started:${ui.RESET}`);
105
- console.log('');
106
- console.log(` 1. Run ${ui.CYAN}claude${ui.RESET} to start Claude Code`);
107
-
108
- if (isGreenfield) {
109
- console.log(` 2. Type ${ui.CYAN}/claudeflow-init${ui.RESET} to scaffold your project`);
110
- console.log('');
111
- console.log(` ${ui.DIM}Claudeflow will ask what you want to build, research${ui.RESET}`);
112
- console.log(` ${ui.DIM}the best stack, and generate project-specific skills.${ui.RESET}`);
113
- } else if (isMultiStack) {
114
- console.log(` 2. Type ${ui.CYAN}/claudeflow-update${ui.RESET} to detect your stacks and generate project-specific skills`);
115
- console.log('');
116
- ui.info(`Multi-stack project detected: ${stackDirs.join(', ')}${rootHasManifest ? ' + root' : ''}`);
117
- console.log('');
118
- console.log(` ${ui.BOLD}After setup:${ui.RESET}`);
119
- console.log(` ${ui.DIM}Just describe what you want — Claudeflow handles the rest.${ui.RESET}`);
120
- } else {
121
- // Single-stack existing project
122
- console.log(` 2. Type ${ui.CYAN}/claudeflow-update${ui.RESET} to detect your stack and generate project-specific skills`);
123
- console.log(` 3. Tell Claude what you want — it handles the rest`);
124
- }
125
-
126
- console.log('');
127
- console.log(` ${ui.BOLD}Commands:${ui.RESET}`);
128
- console.log(` ${ui.CYAN}/claudeflow-init${ui.RESET} ${ui.DIM}Scaffold a new project (greenfield)${ui.RESET}`);
129
- console.log(` ${ui.CYAN}/claudeflow-update${ui.RESET} ${ui.DIM}Detect stack and generate skills for existing project${ui.RESET}`);
130
- console.log(` ${ui.CYAN}/claudeflow-design-tokens${ui.RESET} ${ui.DIM}Create design reference from a site or screenshot${ui.RESET}`);
131
- console.log(` ${ui.CYAN}/claudeflow-create-ui${ui.RESET} ${ui.DIM}Build pages from visual references${ui.RESET}`);
132
- console.log(` ${ui.CYAN}/claudeflow-checkpoints${ui.RESET} ${ui.DIM}Auto-save work with git checkpoints${ui.RESET}`);
133
- console.log('');
134
- console.log(` ${ui.DIM}Docs: https://claudeflow.dev${ui.RESET}`);
135
- console.log('');
136
- }
137
-
138
- module.exports = run;