@litmers/cursorflow-orchestrator 0.1.8 → 0.1.12

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 (66) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +113 -319
  3. package/commands/cursorflow-clean.md +24 -135
  4. package/commands/cursorflow-doctor.md +74 -18
  5. package/commands/cursorflow-init.md +33 -50
  6. package/commands/cursorflow-models.md +51 -0
  7. package/commands/cursorflow-monitor.md +56 -118
  8. package/commands/cursorflow-prepare.md +410 -108
  9. package/commands/cursorflow-resume.md +51 -148
  10. package/commands/cursorflow-review.md +38 -202
  11. package/commands/cursorflow-run.md +208 -86
  12. package/commands/cursorflow-signal.md +38 -12
  13. package/dist/cli/clean.d.ts +3 -1
  14. package/dist/cli/clean.js +145 -8
  15. package/dist/cli/clean.js.map +1 -1
  16. package/dist/cli/doctor.js +14 -1
  17. package/dist/cli/doctor.js.map +1 -1
  18. package/dist/cli/index.js +32 -21
  19. package/dist/cli/index.js.map +1 -1
  20. package/dist/cli/init.js +5 -4
  21. package/dist/cli/init.js.map +1 -1
  22. package/dist/cli/models.d.ts +7 -0
  23. package/dist/cli/models.js +104 -0
  24. package/dist/cli/models.js.map +1 -0
  25. package/dist/cli/monitor.js +56 -1
  26. package/dist/cli/monitor.js.map +1 -1
  27. package/dist/cli/prepare.d.ts +7 -0
  28. package/dist/cli/prepare.js +748 -0
  29. package/dist/cli/prepare.js.map +1 -0
  30. package/dist/cli/resume.js +56 -0
  31. package/dist/cli/resume.js.map +1 -1
  32. package/dist/cli/run.js +30 -1
  33. package/dist/cli/run.js.map +1 -1
  34. package/dist/cli/signal.js +18 -0
  35. package/dist/cli/signal.js.map +1 -1
  36. package/dist/core/runner.d.ts +9 -1
  37. package/dist/core/runner.js +139 -23
  38. package/dist/core/runner.js.map +1 -1
  39. package/dist/utils/cursor-agent.d.ts +4 -0
  40. package/dist/utils/cursor-agent.js +58 -10
  41. package/dist/utils/cursor-agent.js.map +1 -1
  42. package/dist/utils/doctor.d.ts +10 -0
  43. package/dist/utils/doctor.js +581 -1
  44. package/dist/utils/doctor.js.map +1 -1
  45. package/dist/utils/types.d.ts +11 -0
  46. package/examples/README.md +114 -59
  47. package/examples/demo-project/README.md +61 -79
  48. package/examples/demo-project/_cursorflow/tasks/demo-test/01-create-utils.json +17 -6
  49. package/examples/demo-project/_cursorflow/tasks/demo-test/02-add-tests.json +17 -6
  50. package/examples/demo-project/_cursorflow/tasks/demo-test/README.md +66 -25
  51. package/package.json +1 -1
  52. package/scripts/patches/test-cursor-agent.js +203 -0
  53. package/src/cli/clean.ts +156 -9
  54. package/src/cli/doctor.ts +18 -2
  55. package/src/cli/index.ts +33 -21
  56. package/src/cli/init.ts +6 -4
  57. package/src/cli/models.ts +83 -0
  58. package/src/cli/monitor.ts +60 -1
  59. package/src/cli/prepare.ts +844 -0
  60. package/src/cli/resume.ts +66 -0
  61. package/src/cli/run.ts +36 -2
  62. package/src/cli/signal.ts +22 -0
  63. package/src/core/runner.ts +164 -23
  64. package/src/utils/cursor-agent.ts +62 -10
  65. package/src/utils/doctor.ts +633 -5
  66. package/src/utils/types.ts +11 -0
@@ -1,129 +1,251 @@
1
1
  # CursorFlow Run
2
2
 
3
3
  ## Overview
4
- Execute prepared tasks with single-lane or multi-lane orchestration.
5
4
 
6
- ## Steps
5
+ Execute AI agent orchestration using task configurations generated by `prepare`. CursorFlow uses a DAG (Directed Acyclic Graph) scheduler to handle lane dependencies and automatic branch merging.
7
6
 
8
- 1. **Check the task directory**
9
- ```bash
10
- ls _cursorflow/tasks/
11
- ```
7
+ ## Workflow
12
8
 
13
- 2. **Run multiple lanes**
14
- ```bash
15
- cursorflow run _cursorflow/tasks/MyFeature/
16
- ```
9
+ ```
10
+ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
11
+ 1. Create Lanes │ ──▶ │ 2. Add Tasks │ ──▶ │ 3. Validate │ ──▶ │ 4. Run │
12
+ │ (prepare) │ │ (prepare) │ │ (doctor) │ │ (run) │
13
+ └─────────────────┘ └─────────────────┘ └─────────────────┘ └─────────────────┘
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ ```bash
19
+ cursorflow run <tasks-dir> [options]
20
+ ```
17
21
 
18
- 3. **Run a single lane**
19
- ```bash
20
- cursorflow lane _cursorflow/tasks/MyFeature/01-task.json
21
- ```
22
+ ### Quick Start
22
23
 
23
- 4. **Dry run (preview the plan)**
24
- ```bash
25
- cursorflow run _cursorflow/tasks/MyFeature/ --dry-run
26
- ```
24
+ ```bash
25
+ # Step 1: Create lanes
26
+ cursorflow prepare AddAPI --prompt "Create REST API for users" --criteria "CRUD works,Tests pass"
27
+
28
+ # Step 2: (Optional) Add more lanes or tasks
29
+ cursorflow prepare --add-lane _cursorflow/tasks/2412211530_AddAPI \
30
+ --prompt "Add authentication" --depends-on "01-lane-1"
31
+
32
+ # Step 3: Validate configuration
33
+ cursorflow doctor --tasks-dir _cursorflow/tasks/2412211530_AddAPI
34
+
35
+ # Step 4: Run
36
+ cursorflow run _cursorflow/tasks/2412211530_AddAPI
37
+
38
+ # Or run the latest prepared task
39
+ cursorflow run latest
40
+ ```
27
41
 
28
- 5. **Monitor execution**
42
+ ## How It Works
29
43
 
30
- Watch progress from another terminal while the run is in progress:
31
- ```bash
32
- cursorflow monitor --watch
33
- ```
44
+ 1. **Load**: Read all JSON files from the tasks directory
45
+ 2. **Validate**: Check `tasks` array, required fields (`name`, `prompt`)
46
+ 3. **Resolve**: Build execution order from `dependsOn` dependencies
47
+ 4. **Execute**:
48
+ - Start lanes with no dependencies in parallel
49
+ - When a lane completes, unlock dependent lanes
50
+ - **Dependent lanes auto-merge predecessor branches before starting**
51
+ 5. **Monitor**: Heartbeat logs every 30 seconds
34
52
 
35
53
  ## Options
36
54
 
37
55
  | Option | Description |
38
- |------|------|
39
- | `--dry-run` | Preview the plan without executing |
40
- | `--executor <type>` | Execution mode (`cursor-agent` \| `cloud`) |
41
- | `--no-review` | Disable code review |
42
- | `--config <path>` | Use a custom config file |
56
+ |--------|-------------|
57
+ | `<tasks-dir>` | Directory containing JSON task files |
58
+ | `--max-concurrent <num>` | Limit concurrent lane execution |
59
+ | `--executor <type>` | `cursor-agent` (default) or `cloud` |
60
+ | `--skip-doctor` | Skip environment checks (not recommended) |
61
+ | `--dry-run` | Show execution plan without running |
43
62
 
44
- ## Examples
63
+ ## Execution Flow
64
+
65
+ ### Single Lane
45
66
 
46
- ### Standard run
47
67
  ```bash
48
- cursorflow run _cursorflow/tasks/2512191700_MyFeature/
68
+ cursorflow prepare SimpleFix --prompt "Fix the bug"
69
+ cursorflow run _cursorflow/tasks/2412211530_SimpleFix
49
70
  ```
50
71
 
51
- ### Cloud run (requires API key)
52
- ```bash
53
- export CURSOR_API_KEY=your_key
54
- cursorflow run _cursorflow/tasks/MyFeature/ --executor cloud
72
+ ```
73
+ ┌─────────────────────────────────────────────────────────┐
74
+ │ 01-lane-1 │
75
+ │ ┌─────────┐ │
76
+ │ │implement│ → AI executes → Review → Complete │
77
+ │ └─────────┘ │
78
+ └─────────────────────────────────────────────────────────┘
55
79
  ```
56
80
 
57
- ### Fast run without review
81
+ ### Multiple Tasks in Lane
82
+
58
83
  ```bash
59
- cursorflow run _cursorflow/tasks/MyFeature/ --no-review
84
+ cursorflow prepare Feature \
85
+ --task "plan|sonnet-4.5-thinking|Create plan|Plan ready" \
86
+ --task "implement|sonnet-4.5|Build feature|Code done"
60
87
  ```
61
88
 
62
- ## Execution process
89
+ ```
90
+ ┌─────────────────────────────────────────────────────────┐
91
+ │ 01-lane-1 │
92
+ │ ┌────┐ ┌─────────┐ │
93
+ │ │plan│ ──▶ │implement│ → Review → Complete │
94
+ │ └────┘ └─────────┘ │
95
+ └─────────────────────────────────────────────────────────┘
96
+ ```
63
97
 
64
- 1. **Initialization**
65
- - Load configuration
66
- - Verify the `cursor-agent` CLI
67
- - Confirm Git repository status
98
+ ### Sequential Lanes (with `--sequential`)
68
99
 
69
- 2. **Prepare lanes**
70
- - Create worktrees
71
- - Check out branches
72
- - Configure the environment
100
+ ```bash
101
+ cursorflow prepare FullStack --lanes 3 --sequential \
102
+ --prompt "Implement your layer"
103
+ ```
73
104
 
74
- 3. **Run tasks**
75
- - Execute tasks sequentially
76
- - Commit after each task
77
- - Trigger automatic review when enabled
105
+ ```
106
+ ┌───────────┐ ┌───────────┐ ┌───────────┐
107
+ │ 01-lane-1 ──▶ 02-lane-2 │ ──▶ │ 03-lane-3 │
108
+ (DB) │ │ (API) │ │ (UI) │
109
+ └───────────┘ └───────────┘ └───────────┘
110
+ │ │
111
+ merges 01 merges 01,02
112
+ ```
78
113
 
79
- 4. **Complete**
80
- - Push changes
81
- - Create a PR (depending on settings)
82
- - Store logs
114
+ ### Parallel Lanes
83
115
 
84
- ## Log location
116
+ ```bash
117
+ cursorflow prepare FrontBack --lanes 2 \
118
+ --prompt "Implement your layer"
119
+ ```
85
120
 
86
- Run logs are stored in `_cursorflow/logs/runs/`:
121
+ ```
122
+ ┌───────────┐
123
+ │ 01-lane-1 │ (Frontend)
124
+ └───────────┘
125
+ ─── both run in parallel
126
+ ┌───────────┐
127
+ │ 02-lane-2 │ (Backend)
128
+ └───────────┘
129
+ ```
87
130
 
131
+ ## JSON Schema (RunnerConfig)
132
+
133
+ Each JSON file in the tasks directory follows this schema:
134
+
135
+ ```json
136
+ {
137
+ "baseBranch": "main",
138
+ "branchPrefix": "feature/lane-1-",
139
+ "timeout": 300000,
140
+ "enableIntervention": false,
141
+ "dependsOn": ["01-lane-1"],
142
+ "dependencyPolicy": {
143
+ "allowDependencyChange": false,
144
+ "lockfileReadOnly": true
145
+ },
146
+ "enableReview": true,
147
+ "reviewModel": "sonnet-4.5-thinking",
148
+ "maxReviewIterations": 3,
149
+ "tasks": [
150
+ {
151
+ "name": "implement",
152
+ "prompt": "Create a reusable button component...",
153
+ "model": "sonnet-4.5",
154
+ "acceptanceCriteria": ["Build passes", "Tests pass"]
155
+ }
156
+ ]
157
+ }
88
158
  ```
89
- _cursorflow/logs/runs/<lane>-<timestamp>/
90
- ├── state.json # Lane status
91
- ├── results.json # Task results
92
- ├── conversation.jsonl # Agent conversation
93
- ├── git-operations.jsonl # Git activity log
94
- └── events.jsonl # Event log
159
+
160
+ ### Configuration Reference
161
+
162
+ | Field | Type | Required | Description |
163
+ |-------|------|----------|-------------|
164
+ | `baseBranch` | string | Yes | Branch to create worktree from |
165
+ | `branchPrefix` | string | Yes | Prefix for feature branch naming |
166
+ | `tasks` | Task[] | Yes | Array of task objects to execute |
167
+ | `dependsOn` | string[] | No | Lane names to wait for and merge |
168
+ | `timeout` | number | No | Task timeout in ms (default: 300000) |
169
+ | `enableIntervention` | boolean | No | Allow stdin injection during execution |
170
+ | `dependencyPolicy.allowDependencyChange` | boolean | No | Allow package.json modifications |
171
+ | `dependencyPolicy.lockfileReadOnly` | boolean | No | Keep lockfile read-only |
172
+ | `enableReview` | boolean | No | Enable AI code review (default: true) |
173
+ | `reviewModel` | string | No | Model for code review |
174
+ | `maxReviewIterations` | number | No | Max review cycles (default: 3) |
175
+
176
+ ### Task Object
177
+
178
+ | Field | Type | Required | Description |
179
+ |-------|------|----------|-------------|
180
+ | `name` | string | Yes | Task identifier (alphanumeric, `-`, `_`) |
181
+ | `prompt` | string | Yes | Instructions for the AI agent |
182
+ | `model` | string | No | Model override for this task |
183
+ | `acceptanceCriteria` | string[] | No | Criteria for AI reviewer validation |
184
+
185
+ ## Monitoring During Execution
186
+
187
+ ```bash
188
+ # In another terminal
189
+ cursorflow monitor latest
190
+
191
+ # Or specify the task directory
192
+ cursorflow monitor _cursorflow/tasks/2412211530_AddAPI
95
193
  ```
96
194
 
97
- ## Checklist
98
- - [ ] Is the `cursor-agent` CLI installed?
99
- - [ ] Are Git worktrees available?
100
- - [ ] Are the task files valid?
101
- - [ ] Do branch names avoid collisions?
102
- - [ ] Are required environment variables set? (for cloud runs)
195
+ The monitor shows:
196
+ - Lane status (pending, running, completed, failed)
197
+ - Current task within each lane
198
+ - Dependency graph and progress
199
+ - Real-time log streaming
103
200
 
104
201
  ## Troubleshooting
105
202
 
106
- ### Branch conflicts
107
- ```bash
108
- # Clean up existing branches
109
- cursorflow clean branches --pattern "feature/my-*"
203
+ ### Validation Errors
204
+
205
+ ```
206
+ Task N missing required "name" field
110
207
  ```
208
+ → Ensure every task has both `name` and `prompt` fields
111
209
 
112
- ### Worktree conflicts
113
- ```bash
114
- # Clean up existing worktrees
115
- cursorflow clean worktrees --all
116
210
  ```
211
+ Invalid task name: "my task"
212
+ ```
213
+ → Task names can only contain alphanumeric characters, `-`, and `_`
117
214
 
118
- ### Run failures
119
- ```bash
120
- # Inspect logs
121
- cursorflow monitor
122
- # or
123
- cat _cursorflow/logs/runs/latest/*/state.json
215
+ ### Dependency Issues
216
+
217
+ ```
218
+ Circular dependency detected
219
+ ```
220
+ Check your `dependsOn` fields for cycles (A→B, B→A)
221
+
222
+ ```
223
+ Unknown dependency: 01-lane-99
124
224
  ```
225
+ → Verify the lane name in `dependsOn` matches an actual JSON filename
226
+
227
+ ### Merge Conflicts
228
+
229
+ When a dependent lane's auto-merge fails:
230
+
231
+ 1. Find the worktree path in `cursorflow monitor`
232
+ 2. Navigate to the worktree directory
233
+ 3. Resolve conflicts manually and commit
234
+ 4. Resume with `cursorflow resume <lane-name>`
235
+
236
+ ### Lane Stuck
237
+
238
+ If a lane stops responding:
239
+
240
+ 1. Check the agent window in Cursor IDE
241
+ 2. Use `cursorflow signal <lane-name> --message "continue"` to nudge
242
+ 3. Or terminate and restart with `cursorflow run --resume`
243
+
244
+ ## Best Practices
125
245
 
126
- ## Next steps
127
- 1. Monitor progress with `cursorflow monitor --watch`.
128
- 2. Review the PR when the run completes.
129
- 3. If a run fails, resume with `cursorflow resume <lane>`.
246
+ 1. **Always Validate First**: Run `cursorflow doctor --tasks-dir <dir>` before `run`
247
+ 2. **Start Small**: Test with a single lane before scaling up
248
+ 3. **Use `--dry-run`**: Preview execution plan before committing
249
+ 4. **Monitor Actively**: Keep `cursorflow monitor` running in a separate terminal
250
+ 5. **Plan Dependencies**: Draw out the DAG before running complex workflows
251
+ 6. **Include Verification**: Add verify tasks to catch edge cases
@@ -1,19 +1,45 @@
1
- # /cursorflow-signal
1
+ # CursorFlow Signal
2
2
 
3
- ## Goal
4
- Directly intervene in a running lane to provide guidance, corrections, or emergency stops.
3
+ ## Overview
4
+ Directly intervene in a running lane by sending a message to the agent. This is useful for providing immediate feedback or corrections during long-running tasks.
5
5
 
6
6
  ## Usage
7
- 1. Type `/cursorflow-signal <lane-name> <your-message>` in the chat.
8
- 2. The message will be injected into the lane's conversation as a high-priority system instruction.
9
7
 
10
- ## Context
11
- Use this command when:
12
- - You see an agent making a repeated mistake in the monitor.
13
- - You want to provide specific implementation guidance mid-task.
14
- - You need to tell the agent to stop or change direction without killing the process.
8
+ ```bash
9
+ cursorflow signal <lane-name> "<message>" [options]
10
+ ```
11
+
12
+ ## Options
13
+
14
+ | Option | Description |
15
+ |------|------|
16
+ | `<lane-name>` | The name of the lane to signal |
17
+ | `"<message>"` | The text message to send to the agent |
18
+ | `--run-dir <path>` | Use a specific run directory (default: latest) |
19
+
20
+ ## How it works
21
+ 1. **Logging**: The message is recorded in the lane's conversation history as a system/commander message.
22
+ 2. **Injection**: If the lane's task configuration has `enableIntervention: true`, the message is injected into the agent's input stream.
15
23
 
16
24
  ## Example
17
- "Send a signal to lane-1: 'Stop using library X, use library Y instead.'"
18
- "Intervene in backend-lane: 'The database schema changed, please pull the latest main branch.'"
19
25
 
26
+ ```bash
27
+ # Provide a hint to a running agent
28
+ cursorflow signal 01-lane-1 "Make sure to export the new function from index.ts"
29
+ ```
30
+
31
+ ## Dashboard Alternative
32
+ You can also use the interactive monitor to send signals:
33
+ 1. Run `cursorflow monitor latest`.
34
+ 2. Select a lane and enter details (`→`).
35
+ 3. Press `I` to type and send an intervention message.
36
+
37
+ ## Note on Intervention
38
+ For the agent to receive the signal immediately, the task must be configured with:
39
+ ```json
40
+ {
41
+ "enableIntervention": true,
42
+ "tasks": [...]
43
+ }
44
+ ```
45
+ If disabled, the signal will be logged but the agent will not be interrupted.
@@ -1,5 +1,7 @@
1
1
  /**
2
- * CursorFlow clean command (stub)
2
+ * CursorFlow clean command
3
+ *
4
+ * Clean up worktrees, branches, and logs created by CursorFlow
3
5
  */
4
6
  declare function clean(args: string[]): Promise<void>;
5
7
  export = clean;
package/dist/cli/clean.js CHANGED
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  /**
3
- * CursorFlow clean command (stub)
3
+ * CursorFlow clean command
4
+ *
5
+ * Clean up worktrees, branches, and logs created by CursorFlow
4
6
  */
5
7
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
8
  if (k2 === undefined) k2 = k;
@@ -35,23 +37,158 @@ var __importStar = (this && this.__importStar) || (function () {
35
37
  return result;
36
38
  };
37
39
  })();
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
38
42
  const logger = __importStar(require("../utils/logger"));
43
+ const git = __importStar(require("../utils/git"));
44
+ const config_1 = require("../utils/config");
45
+ function printHelp() {
46
+ console.log(`
47
+ Usage: cursorflow clean <type> [options]
48
+
49
+ Clean up resources created by CursorFlow.
50
+
51
+ Types:
52
+ branches Remove local feature branches
53
+ worktrees Remove temporary Git worktrees
54
+ logs Clear log directories
55
+ all Remove all of the above (default)
56
+
57
+ Options:
58
+ --dry-run Show what would be removed without deleting
59
+ --force Force removal (ignore uncommitted changes)
60
+ --help, -h Show help
61
+ `);
62
+ }
39
63
  function parseArgs(args) {
40
64
  return {
41
- type: args[0], // branches | worktrees | logs | all
65
+ type: args.find(a => ['branches', 'worktrees', 'logs', 'all'].includes(a)),
42
66
  pattern: null,
43
67
  dryRun: args.includes('--dry-run'),
44
68
  force: args.includes('--force'),
69
+ all: args.includes('--all'),
70
+ help: args.includes('--help') || args.includes('-h'),
45
71
  };
46
72
  }
47
73
  async function clean(args) {
48
- logger.section('🧹 Cleaning CursorFlow Resources');
49
74
  const options = parseArgs(args);
50
- logger.info('This command will be fully implemented in the next phase');
51
- logger.info(`Clean type: ${options.type}`);
52
- logger.info(`Dry run: ${options.dryRun}`);
53
- logger.warn('\n⚠️ Implementation pending');
54
- logger.info('This will clean branches, worktrees, and logs');
75
+ if (options.help) {
76
+ printHelp();
77
+ return;
78
+ }
79
+ const config = (0, config_1.loadConfig)();
80
+ const repoRoot = git.getRepoRoot();
81
+ logger.section('🧹 Cleaning CursorFlow Resources');
82
+ const type = options.type || 'all';
83
+ if (type === 'all') {
84
+ await cleanWorktrees(config, repoRoot, options);
85
+ await cleanBranches(config, repoRoot, options);
86
+ await cleanLogs(config, options);
87
+ }
88
+ else if (type === 'worktrees') {
89
+ await cleanWorktrees(config, repoRoot, options);
90
+ }
91
+ else if (type === 'branches') {
92
+ await cleanBranches(config, repoRoot, options);
93
+ }
94
+ else if (type === 'logs') {
95
+ await cleanLogs(config, options);
96
+ }
97
+ logger.success('\n✨ Cleaning complete!');
98
+ }
99
+ async function cleanWorktrees(config, repoRoot, options) {
100
+ logger.info('\nChecking worktrees...');
101
+ const worktrees = git.listWorktrees(repoRoot);
102
+ const worktreeRoot = path.join(repoRoot, config.worktreeRoot || '_cursorflow/worktrees');
103
+ const toRemove = worktrees.filter(wt => {
104
+ // Skip main worktree
105
+ if (wt.path === repoRoot)
106
+ return false;
107
+ const isInsideRoot = wt.path.startsWith(worktreeRoot);
108
+ const hasPrefix = path.basename(wt.path).startsWith(config.worktreePrefix || 'cursorflow-');
109
+ return isInsideRoot || hasPrefix;
110
+ });
111
+ if (toRemove.length === 0) {
112
+ logger.info(' No worktrees found to clean.');
113
+ return;
114
+ }
115
+ for (const wt of toRemove) {
116
+ if (options.dryRun) {
117
+ logger.info(` [DRY RUN] Would remove worktree: ${wt.path} (${wt.branch || 'no branch'})`);
118
+ }
119
+ else {
120
+ try {
121
+ logger.info(` Removing worktree: ${wt.path}...`);
122
+ git.removeWorktree(wt.path, { cwd: repoRoot, force: options.force });
123
+ // Git worktree remove might leave the directory if it has untracked files
124
+ if (fs.existsSync(wt.path)) {
125
+ if (options.force) {
126
+ fs.rmSync(wt.path, { recursive: true, force: true });
127
+ logger.info(` (Forced removal of directory)`);
128
+ }
129
+ else {
130
+ logger.warn(` Directory still exists: ${wt.path} (contains untracked files). Use --force to delete anyway.`);
131
+ }
132
+ }
133
+ }
134
+ catch (e) {
135
+ logger.error(` Failed to remove worktree ${wt.path}: ${e.message}`);
136
+ }
137
+ }
138
+ }
139
+ }
140
+ async function cleanBranches(config, repoRoot, options) {
141
+ logger.info('\nChecking branches...');
142
+ // List all local branches
143
+ const result = git.runGitResult(['branch', '--list'], { cwd: repoRoot });
144
+ if (!result.success)
145
+ return;
146
+ const branches = result.stdout
147
+ .split('\n')
148
+ .map(b => b.replace('*', '').trim())
149
+ .filter(b => b && b !== 'main' && b !== 'master');
150
+ const prefix = config.branchPrefix || 'feature/';
151
+ const toDelete = branches.filter(b => b.startsWith(prefix));
152
+ if (toDelete.length === 0) {
153
+ logger.info(' No branches found to clean.');
154
+ return;
155
+ }
156
+ for (const branch of toDelete) {
157
+ if (options.dryRun) {
158
+ logger.info(` [DRY RUN] Would delete branch: ${branch}`);
159
+ }
160
+ else {
161
+ try {
162
+ logger.info(` Deleting branch: ${branch}...`);
163
+ git.deleteBranch(branch, { cwd: repoRoot, force: options.force || options.all });
164
+ }
165
+ catch (e) {
166
+ logger.warn(` Could not delete branch ${branch}: ${e.message}. Use --force if it's not merged.`);
167
+ }
168
+ }
169
+ }
170
+ }
171
+ async function cleanLogs(config, options) {
172
+ const logsDir = (0, config_1.getLogsDir)(config);
173
+ logger.info(`\nChecking logs in ${logsDir}...`);
174
+ if (!fs.existsSync(logsDir)) {
175
+ logger.info(' Logs directory does not exist.');
176
+ return;
177
+ }
178
+ if (options.dryRun) {
179
+ logger.info(` [DRY RUN] Would remove logs directory: ${logsDir}`);
180
+ }
181
+ else {
182
+ try {
183
+ logger.info(` Removing logs...`);
184
+ fs.rmSync(logsDir, { recursive: true, force: true });
185
+ fs.mkdirSync(logsDir, { recursive: true });
186
+ logger.info(` Logs cleared.`);
187
+ }
188
+ catch (e) {
189
+ logger.error(` Failed to clean logs: ${e.message}`);
190
+ }
191
+ }
55
192
  }
56
193
  module.exports = clean;
57
194
  //# sourceMappingURL=clean.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"clean.js","sourceRoot":"","sources":["../../src/cli/clean.ts"],"names":[],"mappings":";AAAA;;GAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,wDAA0C;AAS1C,SAAS,SAAS,CAAC,IAAc;IAC/B,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,oCAAoC;QACnD,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;QAClC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;KAChC,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,KAAK,CAAC,IAAc;IACjC,MAAM,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC;IAEnD,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAEhC,MAAM,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;IACxE,MAAM,CAAC,IAAI,CAAC,eAAe,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3C,MAAM,CAAC,IAAI,CAAC,YAAY,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAE1C,MAAM,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;IAC5C,MAAM,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;AAC/D,CAAC;AAED,iBAAS,KAAK,CAAC"}
1
+ {"version":3,"file":"clean.js","sourceRoot":"","sources":["../../src/cli/clean.ts"],"names":[],"mappings":"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"}
@@ -47,6 +47,7 @@ var __importStar = (this && this.__importStar) || (function () {
47
47
  })();
48
48
  const logger = __importStar(require("../utils/logger"));
49
49
  const doctor_1 = require("../utils/doctor");
50
+ const cursor_agent_1 = require("../utils/cursor-agent");
50
51
  function printHelp() {
51
52
  console.log(`
52
53
  Usage: cursorflow doctor [options]
@@ -58,12 +59,13 @@ Options:
58
59
  --tasks-dir <path> Also validate lane files (run preflight)
59
60
  --executor <type> cursor-agent | cloud
60
61
  --no-cursor Skip Cursor Agent install/auth checks
62
+ --test-agent Run interactive agent test (to approve MCP/permissions)
61
63
  --help, -h Show help
62
64
 
63
65
  Examples:
64
66
  cursorflow doctor
67
+ cursorflow doctor --test-agent
65
68
  cursorflow doctor --tasks-dir _cursorflow/tasks/demo-test/
66
- cursorflow doctor --json
67
69
  `);
68
70
  }
69
71
  function parseArgs(args) {
@@ -74,6 +76,7 @@ function parseArgs(args) {
74
76
  tasksDir: tasksDirIdx >= 0 ? (args[tasksDirIdx + 1] || null) : null,
75
77
  executor: executorIdx >= 0 ? (args[executorIdx + 1] || null) : null,
76
78
  includeCursorAgentChecks: !args.includes('--no-cursor'),
79
+ testAgent: args.includes('--test-agent'),
77
80
  };
78
81
  if (args.includes('--help') || args.includes('-h')) {
79
82
  printHelp();
@@ -90,6 +93,8 @@ function printHumanReport(report) {
90
93
  logger.info(`tasks: ${report.context.tasksDir}`);
91
94
  if (report.issues.length === 0) {
92
95
  logger.success('All checks passed');
96
+ console.log('\n💡 Tip: If this is your first run, we recommend running:');
97
+ console.log(' cursorflow doctor --test-agent\n');
93
98
  return;
94
99
  }
95
100
  for (const issue of report.issues) {
@@ -121,6 +126,10 @@ function printHumanReport(report) {
121
126
  }
122
127
  async function doctor(args) {
123
128
  const options = parseArgs(args);
129
+ if (options.testAgent) {
130
+ const success = (0, cursor_agent_1.runInteractiveAgentTest)();
131
+ process.exit(success ? 0 : 1);
132
+ }
124
133
  const report = (0, doctor_1.runDoctor)({
125
134
  cwd: process.cwd(),
126
135
  tasksDir: options.tasksDir || undefined,
@@ -133,6 +142,10 @@ async function doctor(args) {
133
142
  else {
134
143
  printHumanReport(report);
135
144
  }
145
+ // Save successful doctor run status
146
+ if (report.ok && report.context.repoRoot) {
147
+ (0, doctor_1.saveDoctorStatus)(report.context.repoRoot, report);
148
+ }
136
149
  process.exit(report.ok ? 0 : 1);
137
150
  }
138
151
  module.exports = doctor;