@litmers/cursorflow-orchestrator 0.1.2 → 0.1.5

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 (74) hide show
  1. package/CHANGELOG.md +7 -6
  2. package/dist/cli/clean.d.ts +5 -0
  3. package/dist/cli/clean.js +57 -0
  4. package/dist/cli/clean.js.map +1 -0
  5. package/dist/cli/index.d.ts +6 -0
  6. package/dist/cli/index.js +120 -0
  7. package/dist/cli/index.js.map +1 -0
  8. package/dist/cli/init.d.ts +7 -0
  9. package/dist/cli/init.js +302 -0
  10. package/dist/cli/init.js.map +1 -0
  11. package/dist/cli/monitor.d.ts +8 -0
  12. package/dist/cli/monitor.js +210 -0
  13. package/dist/cli/monitor.js.map +1 -0
  14. package/dist/cli/resume.d.ts +5 -0
  15. package/dist/cli/resume.js +58 -0
  16. package/dist/cli/resume.js.map +1 -0
  17. package/dist/cli/run.d.ts +5 -0
  18. package/dist/cli/run.js +74 -0
  19. package/dist/cli/run.js.map +1 -0
  20. package/dist/cli/setup-commands.d.ts +19 -0
  21. package/dist/cli/setup-commands.js +218 -0
  22. package/dist/cli/setup-commands.js.map +1 -0
  23. package/dist/core/orchestrator.d.ts +47 -0
  24. package/dist/core/orchestrator.js +192 -0
  25. package/dist/core/orchestrator.js.map +1 -0
  26. package/dist/core/reviewer.d.ts +60 -0
  27. package/dist/core/reviewer.js +239 -0
  28. package/dist/core/reviewer.js.map +1 -0
  29. package/dist/core/runner.d.ts +49 -0
  30. package/dist/core/runner.js +475 -0
  31. package/dist/core/runner.js.map +1 -0
  32. package/dist/utils/config.d.ts +31 -0
  33. package/dist/utils/config.js +198 -0
  34. package/dist/utils/config.js.map +1 -0
  35. package/dist/utils/cursor-agent.d.ts +61 -0
  36. package/dist/utils/cursor-agent.js +263 -0
  37. package/dist/utils/cursor-agent.js.map +1 -0
  38. package/dist/utils/git.d.ts +131 -0
  39. package/dist/utils/git.js +272 -0
  40. package/dist/utils/git.js.map +1 -0
  41. package/dist/utils/logger.d.ts +68 -0
  42. package/dist/utils/logger.js +158 -0
  43. package/dist/utils/logger.js.map +1 -0
  44. package/dist/utils/state.d.ts +65 -0
  45. package/dist/utils/state.js +216 -0
  46. package/dist/utils/state.js.map +1 -0
  47. package/dist/utils/types.d.ts +117 -0
  48. package/dist/utils/types.js +6 -0
  49. package/dist/utils/types.js.map +1 -0
  50. package/examples/README.md +155 -0
  51. package/examples/demo-project/README.md +262 -0
  52. package/examples/demo-project/_cursorflow/tasks/demo-test/01-create-utils.json +18 -0
  53. package/examples/demo-project/_cursorflow/tasks/demo-test/02-add-tests.json +18 -0
  54. package/examples/demo-project/_cursorflow/tasks/demo-test/README.md +109 -0
  55. package/package.json +71 -61
  56. package/scripts/ai-security-check.js +11 -4
  57. package/scripts/local-security-gate.sh +76 -0
  58. package/src/cli/{clean.js → clean.ts} +11 -5
  59. package/src/cli/{index.js → index.ts} +22 -16
  60. package/src/cli/{init.js → init.ts} +26 -18
  61. package/src/cli/{monitor.js → monitor.ts} +57 -44
  62. package/src/cli/{resume.js → resume.ts} +11 -5
  63. package/src/cli/run.ts +54 -0
  64. package/src/cli/{setup-commands.js → setup-commands.ts} +19 -18
  65. package/src/core/{orchestrator.js → orchestrator.ts} +44 -26
  66. package/src/core/{reviewer.js → reviewer.ts} +36 -29
  67. package/src/core/{runner.js → runner.ts} +78 -56
  68. package/src/utils/{config.js → config.ts} +17 -25
  69. package/src/utils/{cursor-agent.js → cursor-agent.ts} +38 -47
  70. package/src/utils/{git.js → git.ts} +70 -56
  71. package/src/utils/{logger.js → logger.ts} +170 -178
  72. package/src/utils/{state.js → state.ts} +30 -38
  73. package/src/utils/types.ts +133 -0
  74. package/src/cli/run.js +0 -51
@@ -1,11 +1,17 @@
1
- #!/usr/bin/env node
2
1
  /**
3
2
  * CursorFlow clean command (stub)
4
3
  */
5
4
 
6
- const logger = require('../utils/logger');
5
+ import * as logger from '../utils/logger';
7
6
 
8
- function parseArgs(args) {
7
+ interface CleanOptions {
8
+ type?: string;
9
+ pattern: string | null;
10
+ dryRun: boolean;
11
+ force: boolean;
12
+ }
13
+
14
+ function parseArgs(args: string[]): CleanOptions {
9
15
  return {
10
16
  type: args[0], // branches | worktrees | logs | all
11
17
  pattern: null,
@@ -14,7 +20,7 @@ function parseArgs(args) {
14
20
  };
15
21
  }
16
22
 
17
- async function clean(args) {
23
+ async function clean(args: string[]): Promise<void> {
18
24
  logger.section('🧹 Cleaning CursorFlow Resources');
19
25
 
20
26
  const options = parseArgs(args);
@@ -27,4 +33,4 @@ async function clean(args) {
27
33
  logger.info('This will clean branches, worktrees, and logs');
28
34
  }
29
35
 
30
- module.exports = clean;
36
+ export = clean;
@@ -1,11 +1,14 @@
1
- #!/usr/bin/env node
2
1
  /**
3
2
  * CursorFlow CLI - Main entry point
4
3
  */
5
4
 
6
- const logger = require('../utils/logger');
5
+ import * as logger from '../utils/logger';
7
6
 
8
- const COMMANDS = {
7
+ // Command functions signature
8
+ type CommandFn = (args: string[]) => Promise<void>;
9
+
10
+ // Lazy load commands to speed up help/version output
11
+ const COMMANDS: Record<string, CommandFn> = {
9
12
  init: require('./init'),
10
13
  run: require('./run'),
11
14
  monitor: require('./monitor'),
@@ -13,7 +16,7 @@ const COMMANDS = {
13
16
  resume: require('./resume'),
14
17
  };
15
18
 
16
- function printHelp() {
19
+ function printHelp(): void {
17
20
  console.log(`
18
21
  CursorFlow - Git worktree-based parallel AI agent orchestration
19
22
 
@@ -42,38 +45,40 @@ Documentation:
42
45
  `);
43
46
  }
44
47
 
45
- function printVersion() {
48
+ function printVersion(): void {
46
49
  const pkg = require('../../package.json');
47
50
  console.log(`CursorFlow v${pkg.version}`);
48
51
  }
49
52
 
50
- async function main() {
53
+ async function main(): Promise<void> {
51
54
  const args = process.argv.slice(2);
52
55
 
53
56
  if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
54
57
  printHelp();
55
- process.exit(0);
58
+ return;
56
59
  }
57
60
 
58
61
  if (args.includes('--version') || args.includes('-v')) {
59
62
  printVersion();
60
- process.exit(0);
63
+ return;
61
64
  }
62
65
 
63
- const command = args[0];
66
+ const commandName = args[0]!;
64
67
  const commandArgs = args.slice(1);
65
68
 
66
- if (!COMMANDS[command]) {
67
- logger.error(`Unknown command: ${command}`);
69
+ const command = COMMANDS[commandName];
70
+
71
+ if (!command) {
72
+ logger.error(`Unknown command: ${commandName}`);
68
73
  console.log('\nRun "cursorflow --help" for usage information.');
69
74
  process.exit(1);
70
75
  }
71
76
 
72
77
  try {
73
- await COMMANDS[command](commandArgs);
74
- } catch (error) {
78
+ await command(commandArgs);
79
+ } catch (error: any) {
75
80
  logger.error(error.message);
76
- if (process.env.DEBUG) {
81
+ if (process.env['DEBUG']) {
77
82
  console.error(error.stack);
78
83
  }
79
84
  process.exit(1);
@@ -83,11 +88,12 @@ async function main() {
83
88
  if (require.main === module) {
84
89
  main().catch(error => {
85
90
  logger.error(`Fatal error: ${error.message}`);
86
- if (process.env.DEBUG) {
91
+ if (process.env['DEBUG']) {
87
92
  console.error(error.stack);
88
93
  }
89
94
  process.exit(1);
90
95
  });
91
96
  }
92
97
 
93
- module.exports = main;
98
+ export default main;
99
+ export { main };
@@ -1,18 +1,25 @@
1
- #!/usr/bin/env node
2
1
  /**
3
2
  * CursorFlow init command
4
3
  *
5
4
  * Initialize CursorFlow in a project
6
5
  */
7
6
 
8
- const fs = require('fs');
9
- const path = require('path');
10
- const logger = require('../utils/logger');
11
- const { findProjectRoot, createDefaultConfig } = require('../utils/config');
12
- const { setupCommands } = require('./setup-commands');
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ import * as logger from '../utils/logger';
10
+ import { findProjectRoot, createDefaultConfig, CursorFlowConfig } from '../utils/config';
11
+ import { setupCommands } from './setup-commands';
13
12
 
14
- function parseArgs(args) {
15
- const options = {
13
+ interface InitOptions {
14
+ example: boolean;
15
+ withCommands: boolean;
16
+ configOnly: boolean;
17
+ force: boolean;
18
+ gitignore: boolean;
19
+ }
20
+
21
+ function parseArgs(args: string[]): InitOptions {
22
+ const options: InitOptions = {
16
23
  example: false,
17
24
  withCommands: true,
18
25
  configOnly: false,
@@ -53,7 +60,7 @@ function parseArgs(args) {
53
60
  return options;
54
61
  }
55
62
 
56
- function printHelp() {
63
+ function printHelp(): void {
57
64
  console.log(`
58
65
  Usage: cursorflow init [options]
59
66
 
@@ -76,7 +83,7 @@ Examples:
76
83
  `);
77
84
  }
78
85
 
79
- function createDirectories(projectRoot, config) {
86
+ function createDirectories(projectRoot: string, config: CursorFlowConfig): void {
80
87
  const tasksDir = path.join(projectRoot, config.tasksDir);
81
88
  const logsDir = path.join(projectRoot, config.logsDir);
82
89
 
@@ -95,7 +102,7 @@ function createDirectories(projectRoot, config) {
95
102
  }
96
103
  }
97
104
 
98
- function createExampleTasks(projectRoot, config) {
105
+ function createExampleTasks(projectRoot: string, config: CursorFlowConfig): void {
99
106
  const exampleDir = path.join(projectRoot, config.tasksDir, 'example');
100
107
 
101
108
  if (!fs.existsSync(exampleDir)) {
@@ -164,7 +171,7 @@ cursorflow run ${config.tasksDir}/example/
164
171
  /**
165
172
  * Add _cursorflow to .gitignore
166
173
  */
167
- function updateGitignore(projectRoot) {
174
+ function updateGitignore(projectRoot: string): void {
168
175
  const gitignorePath = path.join(projectRoot, '.gitignore');
169
176
  const entry = '_cursorflow/';
170
177
 
@@ -209,7 +216,7 @@ function updateGitignore(projectRoot) {
209
216
  logger.success('Added _cursorflow/ to .gitignore');
210
217
  }
211
218
 
212
- async function init(args) {
219
+ async function init(args: string[]): Promise<void> {
213
220
  logger.section('🚀 Initializing CursorFlow');
214
221
 
215
222
  const options = parseArgs(args);
@@ -228,7 +235,7 @@ async function init(args) {
228
235
  try {
229
236
  createDefaultConfig(projectRoot, options.force);
230
237
  logger.success(`Created config file: cursorflow.config.js`);
231
- } catch (error) {
238
+ } catch (error: any) {
232
239
  if (error.message.includes('already exists') && !options.force) {
233
240
  logger.warn(error.message);
234
241
  } else {
@@ -237,7 +244,8 @@ async function init(args) {
237
244
  }
238
245
  }
239
246
 
240
- const config = require(configPath);
247
+ // We need to require the config file after it might have been created
248
+ const config: CursorFlowConfig = require(configPath);
241
249
 
242
250
  if (options.configOnly) {
243
251
  logger.section('✅ Configuration initialized');
@@ -256,7 +264,7 @@ async function init(args) {
256
264
  logger.info('\n📝 Updating .gitignore...');
257
265
  try {
258
266
  updateGitignore(projectRoot);
259
- } catch (error) {
267
+ } catch (error: any) {
260
268
  logger.warn(`Failed to update .gitignore: ${error.message}`);
261
269
  logger.info('You can manually add "_cursorflow/" to your .gitignore');
262
270
  }
@@ -267,7 +275,7 @@ async function init(args) {
267
275
  logger.info('\n📋 Installing Cursor commands...');
268
276
  try {
269
277
  await setupCommands({ force: options.force, silent: false });
270
- } catch (error) {
278
+ } catch (error: any) {
271
279
  logger.warn(`Failed to install Cursor commands: ${error.message}`);
272
280
  logger.info('You can install them later with: npx cursorflow-setup');
273
281
  }
@@ -297,4 +305,4 @@ async function init(args) {
297
305
  console.log('');
298
306
  }
299
307
 
300
- module.exports = init;
308
+ export = init;
@@ -1,18 +1,24 @@
1
- #!/usr/bin/env node
2
1
  /**
3
2
  * CursorFlow monitor command
4
3
  */
5
4
 
6
- const fs = require('fs');
7
- const path = require('path');
8
- const logger = require('../utils/logger');
9
- const { loadState } = require('../utils/state');
10
- const { loadConfig } = require('../utils/config');
5
+ import * as fs from 'fs';
6
+ import * as path from 'path';
7
+ import * as logger from '../utils/logger';
8
+ import { loadState } from '../utils/state';
9
+ import { LaneState } from '../utils/types';
10
+ import { loadConfig } from '../utils/config';
11
11
 
12
- function parseArgs(args) {
12
+ interface MonitorOptions {
13
+ runDir?: string;
14
+ watch: boolean;
15
+ interval: number;
16
+ }
17
+
18
+ function parseArgs(args: string[]): MonitorOptions {
13
19
  const watch = args.includes('--watch');
14
20
  const intervalIdx = args.indexOf('--interval');
15
- const interval = intervalIdx >= 0 ? parseInt(args[intervalIdx + 1]) || 2 : 2;
21
+ const interval = intervalIdx >= 0 ? parseInt(args[intervalIdx + 1] || '2') || 2 : 2;
16
22
 
17
23
  // Find run directory (first non-option argument)
18
24
  const runDir = args.find(arg => !arg.startsWith('--') && args.indexOf(arg) !== intervalIdx + 1);
@@ -27,7 +33,7 @@ function parseArgs(args) {
27
33
  /**
28
34
  * Find the latest run directory
29
35
  */
30
- function findLatestRunDir(logsDir) {
36
+ function findLatestRunDir(logsDir: string): string | null {
31
37
  const runsDir = path.join(logsDir, 'runs');
32
38
 
33
39
  if (!fs.existsSync(runsDir)) {
@@ -43,13 +49,13 @@ function findLatestRunDir(logsDir) {
43
49
  }))
44
50
  .sort((a, b) => b.mtime - a.mtime);
45
51
 
46
- return runs.length > 0 ? runs[0].path : null;
52
+ return runs.length > 0 ? runs[0]!.path : null;
47
53
  }
48
54
 
49
55
  /**
50
56
  * List all lanes in a run directory
51
57
  */
52
- function listLanes(runDir) {
58
+ function listLanes(runDir: string): { name: string; path: string }[] {
53
59
  const lanesDir = path.join(runDir, 'lanes');
54
60
 
55
61
  if (!fs.existsSync(lanesDir)) {
@@ -70,9 +76,16 @@ function listLanes(runDir) {
70
76
  /**
71
77
  * Get lane status
72
78
  */
73
- function getLaneStatus(lanePath) {
79
+ function getLaneStatus(lanePath: string): {
80
+ status: string;
81
+ currentTask: number | string;
82
+ totalTasks: number | string;
83
+ progress: string;
84
+ pipelineBranch?: string;
85
+ chatId?: string;
86
+ } {
74
87
  const statePath = path.join(lanePath, 'state.json');
75
- const state = loadState(statePath);
88
+ const state = loadState<LaneState & { chatId?: string }>(statePath);
76
89
 
77
90
  if (!state) {
78
91
  return {
@@ -89,7 +102,7 @@ function getLaneStatus(lanePath) {
89
102
 
90
103
  return {
91
104
  status: state.status || 'unknown',
92
- currentTask: state.currentTaskIndex + 1,
105
+ currentTask: (state.currentTaskIndex || 0) + 1,
93
106
  totalTasks: state.totalTasks || '?',
94
107
  progress: `${progress}%`,
95
108
  pipelineBranch: state.pipelineBranch || '-',
@@ -97,10 +110,25 @@ function getLaneStatus(lanePath) {
97
110
  };
98
111
  }
99
112
 
113
+ /**
114
+ * Get status icon
115
+ */
116
+ function getStatusIcon(status: string): string {
117
+ const icons: Record<string, string> = {
118
+ 'running': '🔄',
119
+ 'completed': '✅',
120
+ 'failed': '❌',
121
+ 'blocked_dependency': '🚫',
122
+ 'no state': '⚪',
123
+ };
124
+
125
+ return icons[status] || '❓';
126
+ }
127
+
100
128
  /**
101
129
  * Display lane status table
102
130
  */
103
- function displayStatus(runDir, lanes) {
131
+ function displayStatus(runDir: string, lanes: { name: string; path: string }[]): void {
104
132
  console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
105
133
  console.log(`📊 Run: ${path.basename(runDir)}`);
106
134
  console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
@@ -131,25 +159,10 @@ function displayStatus(runDir, lanes) {
131
159
  console.log();
132
160
  }
133
161
 
134
- /**
135
- * Get status icon
136
- */
137
- function getStatusIcon(status) {
138
- const icons = {
139
- 'running': '🔄',
140
- 'completed': '✅',
141
- 'failed': '❌',
142
- 'blocked_dependency': '🚫',
143
- 'no state': '⚪',
144
- };
145
-
146
- return icons[status] || '❓';
147
- }
148
-
149
162
  /**
150
163
  * Monitor lanes
151
164
  */
152
- async function monitor(args) {
165
+ async function monitor(args: string[]): Promise<void> {
153
166
  logger.section('📡 Monitoring Lane Execution');
154
167
 
155
168
  const options = parseArgs(args);
@@ -159,20 +172,18 @@ async function monitor(args) {
159
172
  let runDir = options.runDir;
160
173
 
161
174
  if (!runDir || runDir === 'latest') {
162
- runDir = findLatestRunDir(config.logsDir);
175
+ runDir = findLatestRunDir(config.logsDir) || undefined;
163
176
 
164
177
  if (!runDir) {
165
- logger.error('No run directories found');
166
- logger.info(`Runs directory: ${path.join(config.logsDir, 'runs')}`);
167
- process.exit(1);
178
+ logger.error(`Runs directory: ${path.join(config.logsDir, 'runs')}`);
179
+ throw new Error('No run directories found');
168
180
  }
169
181
 
170
182
  logger.info(`Using latest run: ${path.basename(runDir)}`);
171
183
  }
172
184
 
173
185
  if (!fs.existsSync(runDir)) {
174
- logger.error(`Run directory not found: ${runDir}`);
175
- process.exit(1);
186
+ throw new Error(`Run directory not found: ${runDir}`);
176
187
  }
177
188
 
178
189
  // Watch mode
@@ -187,8 +198,8 @@ async function monitor(args) {
187
198
  process.stdout.write('\x1Bc');
188
199
  }
189
200
 
190
- const lanes = listLanes(runDir);
191
- displayStatus(runDir, lanes);
201
+ const lanes = listLanes(runDir!);
202
+ displayStatus(runDir!, lanes);
192
203
 
193
204
  iteration++;
194
205
  };
@@ -200,10 +211,12 @@ async function monitor(args) {
200
211
  const intervalId = setInterval(refresh, options.interval * 1000);
201
212
 
202
213
  // Handle Ctrl+C
203
- process.on('SIGINT', () => {
204
- clearInterval(intervalId);
205
- console.log('\n👋 Monitoring stopped\n');
206
- process.exit(0);
214
+ return new Promise((_, reject) => {
215
+ process.on('SIGINT', () => {
216
+ clearInterval(intervalId);
217
+ console.log('\n👋 Monitoring stopped\n');
218
+ process.exit(0);
219
+ });
207
220
  });
208
221
 
209
222
  } else {
@@ -213,4 +226,4 @@ async function monitor(args) {
213
226
  }
214
227
  }
215
228
 
216
- module.exports = monitor;
229
+ export = monitor;
@@ -1,11 +1,17 @@
1
- #!/usr/bin/env node
2
1
  /**
3
2
  * CursorFlow resume command (stub)
4
3
  */
5
4
 
6
- const logger = require('../utils/logger');
5
+ import * as logger from '../utils/logger';
7
6
 
8
- function parseArgs(args) {
7
+ interface ResumeOptions {
8
+ lane?: string;
9
+ runDir: string | null;
10
+ clean: boolean;
11
+ restart: boolean;
12
+ }
13
+
14
+ function parseArgs(args: string[]): ResumeOptions {
9
15
  return {
10
16
  lane: args[0],
11
17
  runDir: null,
@@ -14,7 +20,7 @@ function parseArgs(args) {
14
20
  };
15
21
  }
16
22
 
17
- async function resume(args) {
23
+ async function resume(args: string[]): Promise<void> {
18
24
  logger.section('🔁 Resuming Lane');
19
25
 
20
26
  const options = parseArgs(args);
@@ -28,4 +34,4 @@ async function resume(args) {
28
34
  logger.info('This will resume interrupted lanes');
29
35
  }
30
36
 
31
- module.exports = resume;
37
+ export = resume;
package/src/cli/run.ts ADDED
@@ -0,0 +1,54 @@
1
+ /**
2
+ * CursorFlow run command
3
+ */
4
+
5
+ import * as path from 'path';
6
+ import * as fs from 'fs';
7
+ import * as logger from '../utils/logger';
8
+ import { orchestrate } from '../core/orchestrator';
9
+ import { loadConfig } from '../utils/config';
10
+
11
+ interface RunOptions {
12
+ tasksDir?: string;
13
+ dryRun: boolean;
14
+ executor: string | null;
15
+ }
16
+
17
+ function parseArgs(args: string[]): RunOptions {
18
+ const tasksDir = args.find(a => !a.startsWith('--'));
19
+ const executorIdx = args.indexOf('--executor');
20
+
21
+ return {
22
+ tasksDir,
23
+ dryRun: args.includes('--dry-run'),
24
+ executor: executorIdx >= 0 ? args[executorIdx + 1] || null : null,
25
+ };
26
+ }
27
+
28
+ async function run(args: string[]): Promise<void> {
29
+ const options = parseArgs(args);
30
+
31
+ if (!options.tasksDir) {
32
+ console.log('\nUsage: cursorflow run <tasks-dir> [options]');
33
+ throw new Error('Tasks directory required');
34
+ }
35
+
36
+ if (!fs.existsSync(options.tasksDir)) {
37
+ throw new Error(`Tasks directory not found: ${options.tasksDir}`);
38
+ }
39
+
40
+ const config = loadConfig();
41
+
42
+ try {
43
+ await orchestrate(options.tasksDir, {
44
+ executor: options.executor || config.executor,
45
+ pollInterval: config.pollInterval * 1000,
46
+ runDir: path.join(config.logsDir, 'runs', `run-${Date.now()}`),
47
+ });
48
+ } catch (error: any) {
49
+ // Re-throw to be handled by the main entry point
50
+ throw new Error(`Orchestration failed: ${error.message}`);
51
+ }
52
+ }
53
+
54
+ export = run;
@@ -1,17 +1,22 @@
1
- #!/usr/bin/env node
2
1
  /**
3
2
  * Setup Cursor commands
4
3
  *
5
4
  * Installs CursorFlow commands to .cursor/commands/cursorflow/
6
5
  */
7
6
 
8
- const fs = require('fs');
9
- const path = require('path');
10
- const logger = require('../utils/logger');
11
- const { findProjectRoot } = require('../utils/config');
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ import * as logger from '../utils/logger';
10
+ import { findProjectRoot } from '../utils/config';
12
11
 
13
- function parseArgs(args) {
14
- const options = {
12
+ interface SetupOptions {
13
+ force?: boolean;
14
+ uninstall?: boolean;
15
+ silent?: boolean;
16
+ }
17
+
18
+ function parseArgs(args: string[]): SetupOptions {
19
+ const options: SetupOptions = {
15
20
  force: false,
16
21
  uninstall: false,
17
22
  silent: false,
@@ -39,7 +44,7 @@ function parseArgs(args) {
39
44
  return options;
40
45
  }
41
46
 
42
- function printHelp() {
47
+ function printHelp(): void {
43
48
  console.log(`
44
49
  Usage: cursorflow-setup [options]
45
50
 
@@ -58,12 +63,12 @@ Examples:
58
63
  `);
59
64
  }
60
65
 
61
- function getCommandsSourceDir() {
66
+ function getCommandsSourceDir(): string {
62
67
  // Commands are in the package directory
63
68
  return path.join(__dirname, '..', '..', 'commands');
64
69
  }
65
70
 
66
- function setupCommands(options = {}) {
71
+ export function setupCommands(options: SetupOptions = {}): { installed: number; backed: number; skipped: number } {
67
72
  const projectRoot = findProjectRoot();
68
73
  const targetDir = path.join(projectRoot, '.cursor', 'commands', 'cursorflow');
69
74
  const sourceDir = getCommandsSourceDir();
@@ -139,7 +144,7 @@ function setupCommands(options = {}) {
139
144
  return { installed, backed, skipped };
140
145
  }
141
146
 
142
- function uninstallCommands(options = {}) {
147
+ export function uninstallCommands(options: SetupOptions = {}): { removed: number } {
143
148
  const projectRoot = findProjectRoot();
144
149
  const targetDir = path.join(projectRoot, '.cursor', 'commands', 'cursorflow');
145
150
 
@@ -178,7 +183,7 @@ function uninstallCommands(options = {}) {
178
183
  return { removed };
179
184
  }
180
185
 
181
- async function main(args) {
186
+ async function main(args: string[]): Promise<any> {
182
187
  const options = parseArgs(args);
183
188
 
184
189
  try {
@@ -187,7 +192,7 @@ async function main(args) {
187
192
  } else {
188
193
  return setupCommands(options);
189
194
  }
190
- } catch (error) {
195
+ } catch (error: any) {
191
196
  if (!options.silent) {
192
197
  logger.error(error.message);
193
198
  }
@@ -198,13 +203,9 @@ async function main(args) {
198
203
  if (require.main === module) {
199
204
  main(process.argv.slice(2)).catch(error => {
200
205
  console.error('❌ Error:', error.message);
201
- if (process.env.DEBUG) {
206
+ if (process.env['DEBUG']) {
202
207
  console.error(error.stack);
203
208
  }
204
209
  process.exit(1);
205
210
  });
206
211
  }
207
-
208
- module.exports = setupCommands;
209
- module.exports.setupCommands = setupCommands;
210
- module.exports.uninstallCommands = uninstallCommands;