@litmers/cursorflow-orchestrator 0.1.3 → 0.1.6

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 (90) hide show
  1. package/CHANGELOG.md +17 -7
  2. package/README.md +33 -2
  3. package/commands/cursorflow-doctor.md +24 -0
  4. package/commands/cursorflow-signal.md +19 -0
  5. package/dist/cli/clean.d.ts +5 -0
  6. package/dist/cli/clean.js +57 -0
  7. package/dist/cli/clean.js.map +1 -0
  8. package/dist/cli/doctor.d.ts +15 -0
  9. package/dist/cli/doctor.js +139 -0
  10. package/dist/cli/doctor.js.map +1 -0
  11. package/dist/cli/index.d.ts +6 -0
  12. package/dist/cli/index.js +125 -0
  13. package/dist/cli/index.js.map +1 -0
  14. package/dist/cli/init.d.ts +7 -0
  15. package/dist/cli/init.js +302 -0
  16. package/dist/cli/init.js.map +1 -0
  17. package/dist/cli/monitor.d.ts +8 -0
  18. package/dist/cli/monitor.js +210 -0
  19. package/dist/cli/monitor.js.map +1 -0
  20. package/dist/cli/resume.d.ts +5 -0
  21. package/dist/cli/resume.js +128 -0
  22. package/dist/cli/resume.js.map +1 -0
  23. package/dist/cli/run.d.ts +5 -0
  24. package/dist/cli/run.js +128 -0
  25. package/dist/cli/run.js.map +1 -0
  26. package/dist/cli/setup-commands.d.ts +23 -0
  27. package/dist/cli/setup-commands.js +234 -0
  28. package/dist/cli/setup-commands.js.map +1 -0
  29. package/dist/cli/signal.d.ts +7 -0
  30. package/dist/cli/signal.js +99 -0
  31. package/dist/cli/signal.js.map +1 -0
  32. package/dist/core/orchestrator.d.ts +47 -0
  33. package/dist/core/orchestrator.js +192 -0
  34. package/dist/core/orchestrator.js.map +1 -0
  35. package/dist/core/reviewer.d.ts +60 -0
  36. package/dist/core/reviewer.js +239 -0
  37. package/dist/core/reviewer.js.map +1 -0
  38. package/dist/core/runner.d.ts +51 -0
  39. package/dist/core/runner.js +499 -0
  40. package/dist/core/runner.js.map +1 -0
  41. package/dist/utils/config.d.ts +31 -0
  42. package/dist/utils/config.js +198 -0
  43. package/dist/utils/config.js.map +1 -0
  44. package/dist/utils/cursor-agent.d.ts +61 -0
  45. package/dist/utils/cursor-agent.js +263 -0
  46. package/dist/utils/cursor-agent.js.map +1 -0
  47. package/dist/utils/doctor.d.ts +63 -0
  48. package/dist/utils/doctor.js +280 -0
  49. package/dist/utils/doctor.js.map +1 -0
  50. package/dist/utils/git.d.ts +131 -0
  51. package/dist/utils/git.js +272 -0
  52. package/dist/utils/git.js.map +1 -0
  53. package/dist/utils/logger.d.ts +68 -0
  54. package/dist/utils/logger.js +158 -0
  55. package/dist/utils/logger.js.map +1 -0
  56. package/dist/utils/state.d.ts +65 -0
  57. package/dist/utils/state.js +216 -0
  58. package/dist/utils/state.js.map +1 -0
  59. package/dist/utils/types.d.ts +118 -0
  60. package/dist/utils/types.js +6 -0
  61. package/dist/utils/types.js.map +1 -0
  62. package/examples/README.md +155 -0
  63. package/examples/demo-project/README.md +262 -0
  64. package/examples/demo-project/_cursorflow/tasks/demo-test/01-create-utils.json +18 -0
  65. package/examples/demo-project/_cursorflow/tasks/demo-test/02-add-tests.json +18 -0
  66. package/examples/demo-project/_cursorflow/tasks/demo-test/README.md +109 -0
  67. package/package.json +71 -61
  68. package/scripts/ai-security-check.js +11 -4
  69. package/scripts/local-security-gate.sh +76 -0
  70. package/src/cli/{clean.js → clean.ts} +11 -5
  71. package/src/cli/doctor.ts +127 -0
  72. package/src/cli/{index.js → index.ts} +27 -16
  73. package/src/cli/{init.js → init.ts} +26 -18
  74. package/src/cli/{monitor.js → monitor.ts} +57 -44
  75. package/src/cli/resume.ts +119 -0
  76. package/src/cli/run.ts +109 -0
  77. package/src/cli/{setup-commands.js → setup-commands.ts} +38 -18
  78. package/src/cli/signal.ts +89 -0
  79. package/src/core/{orchestrator.js → orchestrator.ts} +44 -26
  80. package/src/core/{reviewer.js → reviewer.ts} +36 -29
  81. package/src/core/{runner.js → runner.ts} +125 -76
  82. package/src/utils/{config.js → config.ts} +17 -25
  83. package/src/utils/{cursor-agent.js → cursor-agent.ts} +38 -47
  84. package/src/utils/doctor.ts +312 -0
  85. package/src/utils/{git.js → git.ts} +70 -56
  86. package/src/utils/{logger.js → logger.ts} +170 -178
  87. package/src/utils/{state.js → state.ts} +30 -38
  88. package/src/utils/types.ts +134 -0
  89. package/src/cli/resume.js +0 -31
  90. package/src/cli/run.js +0 -51
@@ -7,7 +7,7 @@
7
7
 
8
8
  const fs = require('fs');
9
9
  const path = require('path');
10
- const { execSync } = require('child_process');
10
+ const { spawnSync } = require('child_process');
11
11
 
12
12
  // 색상 정의
13
13
  const colors = {
@@ -29,8 +29,10 @@ if (!OPENAI_API_KEY) {
29
29
  function getChangedFiles() {
30
30
  try {
31
31
  const baseBranch = process.env.GITHUB_BASE_REF || 'main';
32
- const diffCommand = `git diff --name-only origin/${baseBranch}...HEAD`;
33
- const files = execSync(diffCommand, { encoding: 'utf-8' })
32
+ const result = spawnSync('git', ['diff', '--name-only', `origin/${baseBranch}...HEAD`], { encoding: 'utf-8' });
33
+ if (result.status !== 0) throw new Error(result.stderr);
34
+
35
+ const files = result.stdout
34
36
  .split('\n')
35
37
  .filter(f => f.endsWith('.js') || f.endsWith('.ts') || f.endsWith('.jsx') || f.endsWith('.tsx'))
36
38
  .filter(f => f && fs.existsSync(f));
@@ -38,7 +40,10 @@ function getChangedFiles() {
38
40
  } catch (error) {
39
41
  // PR이 아닌 경우 최근 커밋의 파일들
40
42
  try {
41
- const files = execSync('git diff-tree --no-commit-id --name-only -r HEAD', { encoding: 'utf-8' })
43
+ const result = spawnSync('git', ['diff-tree', '--no-commit-id', '--name-only', '-r', 'HEAD'], { encoding: 'utf-8' });
44
+ if (result.status !== 0) return [];
45
+
46
+ const files = result.stdout
42
47
  .split('\n')
43
48
  .filter(f => f.endsWith('.js') || f.endsWith('.ts') || f.endsWith('.jsx') || f.endsWith('.tsx'))
44
49
  .filter(f => f && fs.existsSync(f));
@@ -71,6 +76,8 @@ Please analyze for:
71
76
  8. **Rate limiting or DoS vulnerabilities**
72
77
  9. **CSRF/SSRF vulnerabilities**
73
78
  10. **Any OWASP Top 10 issues**
79
+ 11. **CodeQL-specific patterns** (tainted data flow, improper input validation, dangerous sinks like eval or child_process.exec)
80
+ 12. **Code quality issues** that might trigger CodeQL's "Security and Quality" queries
74
81
 
75
82
  Respond in JSON format:
76
83
  {
@@ -0,0 +1,76 @@
1
+ #!/bin/bash
2
+
3
+ # 로컬 보안 게이트 (Local Security Gate)
4
+ # 커밋 또는 푸시 전에 보안 취약점을 미리 검사합니다.
5
+
6
+ set -e
7
+
8
+ # 색상 정의
9
+ RED='\033[0;31m'
10
+ GREEN='\033[0;32m'
11
+ YELLOW='\033[1;33m'
12
+ BLUE='\033[0;34m'
13
+ NC='\033[0m'
14
+
15
+ echo -e "${BLUE}🔍 Starting Local Security Gate...${NC}"
16
+
17
+ # 1. 의존성 취약점 검사 (npm audit)
18
+ echo -e "\n${BLUE}[1/4] Checking dependencies (npm audit)...${NC}"
19
+ if npm audit --audit-level=high; then
20
+ echo -e "${GREEN}✅ No high-severity dependency issues found.${NC}"
21
+ else
22
+ echo -e "${RED}❌ High-severity dependency issues found!${NC}"
23
+ echo -e "${YELLOW}Please run 'npm audit fix' to resolve them.${NC}"
24
+ exit 1
25
+ fi
26
+
27
+ # 2. 정적 코드 분석 (Semgrep - CodeQL 대안)
28
+ echo -e "\n${BLUE}[2/4] Running static analysis (Semgrep)...${NC}"
29
+ if command -v semgrep &> /dev/null; then
30
+ if semgrep --config=auto --error .; then
31
+ echo -e "${GREEN}✅ Semgrep analysis passed.${NC}"
32
+ else
33
+ echo -e "${RED}❌ Semgrep found potential security issues!${NC}"
34
+ echo -e "${YELLOW}CodeQL과 유사한 보안 이슈들입니다. 위 리포트를 확인하고 수정하세요.${NC}"
35
+ exit 1
36
+ fi
37
+ else
38
+ echo -e "${YELLOW}⚠️ Semgrep not installed. Skipping static analysis.${NC}"
39
+ echo -e "Install it to catch CodeQL-like issues: pip install semgrep"
40
+ fi
41
+
42
+ # 3. 민감 정보 노출 검사 (Simple Secret Scan)
43
+ echo -e "\n${BLUE}[3/4] Checking for hardcoded secrets...${NC}"
44
+ # git에 추적되는 파일들 중 API 키나 비밀번호 패턴 검색
45
+ # .cursorignore나 .gitignore에 있는 파일은 제외
46
+ # .github, *.md, scripts/setup-security.sh 등은 제외
47
+ # 변수 선언이나 에러 메시지에 포함된 키워드는 제외하도록 필터 강화
48
+ SECRETS_FOUND=$(git grep -Ei "api[_-]?key|secret|password|token|bearer|private[_-]?key" -- ":!package-lock.json" ":!*.md" ":!scripts/setup-security.sh" ":!scripts/ai-security-check.js" ":!.github/*" ":!scripts/local-security-gate.sh" | grep -v "process.env" | grep -v "example" | grep -v "\${{" | grep -vE "stderr\.includes|checkCursorApiKey|CURSOR_API_KEY|api key|API_KEY" || true)
49
+
50
+ if [ -z "$SECRETS_FOUND" ]; then
51
+ echo -e "${GREEN}✅ No obvious secrets found in tracked files.${NC}"
52
+ else
53
+ echo -e "${YELLOW}⚠️ Possible secrets found:${NC}"
54
+ echo "$SECRETS_FOUND"
55
+ echo -e "\n${RED}❌ Please remove secrets or move them to .env file before pushing!${NC}"
56
+ exit 1
57
+ fi
58
+
59
+ # 4. AI 기반 코드 보안 분석 (선택적)
60
+ echo -e "\n${BLUE}[4/4] AI-based security analysis...${NC}"
61
+ if [ -z "$OPENAI_API_KEY" ]; then
62
+ echo -e "${YELLOW}⚠️ OPENAI_API_KEY not set. Skipping AI security check.${NC}"
63
+ echo -e "Set the environment variable to enable this step: export OPENAI_API_KEY=your-key"
64
+ else
65
+ if node scripts/ai-security-check.js; then
66
+ echo -e "${GREEN}✅ AI security check passed.${NC}"
67
+ else
68
+ echo -e "${RED}❌ AI security check failed!${NC}"
69
+ exit 1
70
+ fi
71
+ fi
72
+
73
+ echo -e "\n${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
74
+ echo -e "${GREEN}✅ All local security checks passed!${NC}"
75
+ echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n"
76
+
@@ -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;
@@ -0,0 +1,127 @@
1
+ /**
2
+ * CursorFlow doctor command
3
+ *
4
+ * Usage:
5
+ * cursorflow doctor [options]
6
+ *
7
+ * Options:
8
+ * --json Output machine-readable JSON
9
+ * --tasks-dir <path> Also validate lane files (run preflight)
10
+ * --executor <type> cursor-agent | cloud
11
+ * --no-cursor Skip Cursor Agent install/auth checks
12
+ * --help, -h Show help
13
+ */
14
+
15
+ import * as logger from '../utils/logger';
16
+ import { runDoctor } from '../utils/doctor';
17
+
18
+ interface DoctorCliOptions {
19
+ json: boolean;
20
+ tasksDir: string | null;
21
+ executor: string | null;
22
+ includeCursorAgentChecks: boolean;
23
+ }
24
+
25
+ function printHelp(): void {
26
+ console.log(`
27
+ Usage: cursorflow doctor [options]
28
+
29
+ Verify your environment is ready for CursorFlow runs.
30
+
31
+ Options:
32
+ --json Output machine-readable JSON
33
+ --tasks-dir <path> Also validate lane files (run preflight)
34
+ --executor <type> cursor-agent | cloud
35
+ --no-cursor Skip Cursor Agent install/auth checks
36
+ --help, -h Show help
37
+
38
+ Examples:
39
+ cursorflow doctor
40
+ cursorflow doctor --tasks-dir _cursorflow/tasks/demo-test/
41
+ cursorflow doctor --json
42
+ `);
43
+ }
44
+
45
+ function parseArgs(args: string[]): DoctorCliOptions {
46
+ const tasksDirIdx = args.indexOf('--tasks-dir');
47
+ const executorIdx = args.indexOf('--executor');
48
+
49
+ const options: DoctorCliOptions = {
50
+ json: args.includes('--json'),
51
+ tasksDir: tasksDirIdx >= 0 ? (args[tasksDirIdx + 1] || null) : null,
52
+ executor: executorIdx >= 0 ? (args[executorIdx + 1] || null) : null,
53
+ includeCursorAgentChecks: !args.includes('--no-cursor'),
54
+ };
55
+
56
+ if (args.includes('--help') || args.includes('-h')) {
57
+ printHelp();
58
+ process.exit(0);
59
+ }
60
+
61
+ return options;
62
+ }
63
+
64
+ function printHumanReport(report: ReturnType<typeof runDoctor>): void {
65
+ logger.section('🩺 CursorFlow Doctor');
66
+ logger.info(`cwd: ${report.context.cwd}`);
67
+ if (report.context.repoRoot) logger.info(`repo: ${report.context.repoRoot}`);
68
+ if (report.context.tasksDir) logger.info(`tasks: ${report.context.tasksDir}`);
69
+
70
+ if (report.issues.length === 0) {
71
+ logger.success('All checks passed');
72
+ return;
73
+ }
74
+
75
+ for (const issue of report.issues) {
76
+ const header = `${issue.title} (${issue.id})`;
77
+ if (issue.severity === 'error') {
78
+ logger.error(header, '❌');
79
+ } else {
80
+ logger.warn(header, '⚠️');
81
+ }
82
+
83
+ console.log(` ${issue.message}`);
84
+
85
+ if (issue.details) {
86
+ console.log(` Details: ${issue.details}`);
87
+ }
88
+
89
+ if (issue.fixes && issue.fixes.length > 0) {
90
+ console.log(' Fix:');
91
+ for (const fix of issue.fixes) {
92
+ console.log(` - ${fix}`);
93
+ }
94
+ }
95
+
96
+ console.log('');
97
+ }
98
+
99
+ if (report.ok) {
100
+ logger.success('Doctor completed with warnings');
101
+ } else {
102
+ logger.error('Doctor found blocking issues');
103
+ }
104
+ }
105
+
106
+ async function doctor(args: string[]): Promise<void> {
107
+ const options = parseArgs(args);
108
+
109
+ const report = runDoctor({
110
+ cwd: process.cwd(),
111
+ tasksDir: options.tasksDir || undefined,
112
+ executor: options.executor || undefined,
113
+ includeCursorAgentChecks: options.includeCursorAgentChecks,
114
+ });
115
+
116
+ if (options.json) {
117
+ console.log(JSON.stringify(report, null, 2));
118
+ } else {
119
+ printHumanReport(report);
120
+ }
121
+
122
+ process.exit(report.ok ? 0 : 1);
123
+ }
124
+
125
+ export = doctor;
126
+
127
+
@@ -1,19 +1,24 @@
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'),
12
15
  clean: require('./clean'),
13
16
  resume: require('./resume'),
17
+ doctor: require('./doctor'),
18
+ signal: require('./signal'),
14
19
  };
15
20
 
16
- function printHelp() {
21
+ function printHelp(): void {
17
22
  console.log(`
18
23
  CursorFlow - Git worktree-based parallel AI agent orchestration
19
24
 
@@ -25,6 +30,8 @@ Commands:
25
30
  monitor [run-dir] [options] Monitor lane execution
26
31
  clean <type> [options] Clean branches/worktrees/logs
27
32
  resume <lane> [options] Resume interrupted lane
33
+ doctor [options] Check environment and preflight
34
+ signal <lane> <msg> Directly intervene in a running lane
28
35
 
29
36
  Global Options:
30
37
  --config <path> Config file path
@@ -36,44 +43,47 @@ Examples:
36
43
  cursorflow run _cursorflow/tasks/MyFeature/
37
44
  cursorflow monitor --watch
38
45
  cursorflow clean branches --all
46
+ cursorflow doctor
39
47
 
40
48
  Documentation:
41
49
  https://github.com/eungjin-cigro/cursorflow#readme
42
50
  `);
43
51
  }
44
52
 
45
- function printVersion() {
53
+ function printVersion(): void {
46
54
  const pkg = require('../../package.json');
47
55
  console.log(`CursorFlow v${pkg.version}`);
48
56
  }
49
57
 
50
- async function main() {
58
+ async function main(): Promise<void> {
51
59
  const args = process.argv.slice(2);
52
60
 
53
61
  if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
54
62
  printHelp();
55
- process.exit(0);
63
+ return;
56
64
  }
57
65
 
58
66
  if (args.includes('--version') || args.includes('-v')) {
59
67
  printVersion();
60
- process.exit(0);
68
+ return;
61
69
  }
62
70
 
63
- const command = args[0];
71
+ const commandName = args[0]!;
64
72
  const commandArgs = args.slice(1);
65
73
 
66
- if (!COMMANDS[command]) {
67
- logger.error(`Unknown command: ${command}`);
74
+ const command = COMMANDS[commandName];
75
+
76
+ if (!command) {
77
+ logger.error(`Unknown command: ${commandName}`);
68
78
  console.log('\nRun "cursorflow --help" for usage information.');
69
79
  process.exit(1);
70
80
  }
71
81
 
72
82
  try {
73
- await COMMANDS[command](commandArgs);
74
- } catch (error) {
83
+ await command(commandArgs);
84
+ } catch (error: any) {
75
85
  logger.error(error.message);
76
- if (process.env.DEBUG) {
86
+ if (process.env['DEBUG']) {
77
87
  console.error(error.stack);
78
88
  }
79
89
  process.exit(1);
@@ -83,11 +93,12 @@ async function main() {
83
93
  if (require.main === module) {
84
94
  main().catch(error => {
85
95
  logger.error(`Fatal error: ${error.message}`);
86
- if (process.env.DEBUG) {
96
+ if (process.env['DEBUG']) {
87
97
  console.error(error.stack);
88
98
  }
89
99
  process.exit(1);
90
100
  });
91
101
  }
92
102
 
93
- module.exports = main;
103
+ export default main;
104
+ 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;