@jahanxu/code-flow 0.2.0 → 0.2.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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/cli.js +91 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jahanxu/code-flow",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "license": "UNLICENSED",
5
5
  "bin": {
6
6
  "code-flow": "src/cli.js"
package/src/cli.js CHANGED
@@ -6,9 +6,12 @@ const fs = require('fs');
6
6
  const path = require('path');
7
7
  const { spawnSync } = require('child_process');
8
8
 
9
+ const pkg = require('../package.json');
10
+
9
11
  const usage = [
10
12
  'Usage: code-flow init',
11
- ' code-flow --help'
13
+ ' code-flow -v | --version',
14
+ ' code-flow -h | --help'
12
15
  ].join('\n');
13
16
 
14
17
  function printUsage(stream) {
@@ -57,6 +60,21 @@ function copyDirRecursive(srcDir, destDir) {
57
60
  }
58
61
  }
59
62
 
63
+ function collectFiles(dir, base) {
64
+ const results = [];
65
+ if (!fs.existsSync(dir)) return results;
66
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
67
+ for (const entry of entries) {
68
+ const rel = path.join(base, entry.name);
69
+ if (entry.isDirectory()) {
70
+ results.push(...collectFiles(path.join(dir, entry.name), rel));
71
+ } else if (entry.isFile()) {
72
+ results.push(rel);
73
+ }
74
+ }
75
+ return results;
76
+ }
77
+
60
78
  function runInit() {
61
79
  ensurePython3();
62
80
 
@@ -65,24 +83,91 @@ function runInit() {
65
83
  const coreDir = path.join(baseDir, 'core');
66
84
  const adaptersDir = path.join(baseDir, 'adapters');
67
85
 
86
+ const created = [];
87
+ const skipped = [];
88
+
89
+ // Track files before copy
90
+ const track = (srcDir, destDir, prefix) => {
91
+ if (!fs.existsSync(srcDir)) return;
92
+ const files = collectFiles(srcDir, '');
93
+ for (const rel of files) {
94
+ const dest = path.join(destDir, rel);
95
+ const label = path.join(prefix, rel);
96
+ if (fs.existsSync(dest)) {
97
+ skipped.push(label);
98
+ } else {
99
+ created.push(label);
100
+ }
101
+ }
102
+ };
103
+
104
+ track(path.join(coreDir, 'code-flow'), path.join(cwd, '.code-flow'), '.code-flow');
105
+ const claudeMdDest = path.join(cwd, 'CLAUDE.md');
106
+ if (fs.existsSync(claudeMdDest)) {
107
+ skipped.push('CLAUDE.md');
108
+ } else {
109
+ created.push('CLAUDE.md');
110
+ }
111
+ track(path.join(adaptersDir, 'claude', 'commands'), path.join(cwd, '.claude', 'commands'), '.claude/commands');
112
+ const settingsDest = path.join(cwd, '.claude', 'settings.local.json');
113
+ if (fs.existsSync(settingsDest)) {
114
+ skipped.push('.claude/settings.local.json');
115
+ } else {
116
+ created.push('.claude/settings.local.json');
117
+ }
118
+
119
+ // Perform copy
68
120
  copyDirRecursive(path.join(coreDir, 'code-flow'), path.join(cwd, '.code-flow'));
69
- copyFileIfMissing(path.join(adaptersDir, 'claude', 'CLAUDE.md'), path.join(cwd, 'CLAUDE.md'));
70
- copyDirRecursive(path.join(adaptersDir, 'claude'), path.join(cwd, '.claude'));
121
+ copyFileIfMissing(path.join(adaptersDir, 'claude', 'CLAUDE.md'), claudeMdDest);
122
+ fs.mkdirSync(path.join(cwd, '.claude', 'commands'), { recursive: true });
123
+ copyDirRecursive(path.join(adaptersDir, 'claude', 'commands'), path.join(cwd, '.claude', 'commands'));
124
+ copyFileIfMissing(path.join(adaptersDir, 'claude', 'settings.local.json'), settingsDest);
71
125
 
72
126
  // Clean up legacy .claude/skills/ if it exists
73
127
  const legacySkills = path.join(cwd, '.claude', 'skills');
74
128
  if (fs.existsSync(legacySkills)) {
75
129
  fs.rmSync(legacySkills, { recursive: true });
130
+ process.stdout.write('Cleaned up legacy .claude/skills/\n');
131
+ }
132
+
133
+ // Install pyyaml
134
+ const pip = spawnSync('python3', ['-m', 'pip', 'install', 'pyyaml'], {
135
+ stdio: 'ignore'
136
+ });
137
+ if (pip.error || pip.status !== 0) {
138
+ process.stderr.write('Warning: pyyaml install failed. Run manually: pip install pyyaml\n');
76
139
  }
77
140
 
78
- process.stdout.write('code-flow initialized.\n');
79
- process.stdout.write('Run /project:cf-init in Claude Code to complete setup.\n');
141
+ // Output summary
142
+ process.stdout.write('\ncode-flow initialized!\n\n');
143
+ if (created.length > 0) {
144
+ process.stdout.write('Created:\n');
145
+ for (const f of created) {
146
+ process.stdout.write(` + ${f}\n`);
147
+ }
148
+ }
149
+ if (skipped.length > 0) {
150
+ process.stdout.write('Skipped (already exist):\n');
151
+ for (const f of skipped) {
152
+ process.stdout.write(` - ${f}\n`);
153
+ }
154
+ }
155
+ process.stdout.write('\nNext steps:\n');
156
+ process.stdout.write(' 1. Edit CLAUDE.md — fill in team/project info\n');
157
+ process.stdout.write(' 2. Edit .code-flow/specs/ — fill in your coding standards\n');
158
+ process.stdout.write(' 3. Run /project:cf-learn in Claude Code to auto-discover constraints\n');
80
159
  process.exit(0);
81
160
  }
82
161
 
83
162
  const args = process.argv.slice(2);
84
163
 
85
- if (args.length === 1 && args[0] === '--help') {
164
+ if (args.includes('-v') || args.includes('--version')) {
165
+ process.stdout.write(`${pkg.version}\n`);
166
+ process.exit(0);
167
+ }
168
+
169
+ if (args.includes('-h') || args.includes('--help')) {
170
+ process.stdout.write(`code-flow v${pkg.version}\n\n`);
86
171
  printUsage(process.stdout);
87
172
  process.exit(0);
88
173
  }