@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.
- package/CHANGELOG.md +55 -0
- package/README.md +113 -319
- package/commands/cursorflow-clean.md +24 -135
- package/commands/cursorflow-doctor.md +74 -18
- package/commands/cursorflow-init.md +33 -50
- package/commands/cursorflow-models.md +51 -0
- package/commands/cursorflow-monitor.md +56 -118
- package/commands/cursorflow-prepare.md +410 -108
- package/commands/cursorflow-resume.md +51 -148
- package/commands/cursorflow-review.md +38 -202
- package/commands/cursorflow-run.md +208 -86
- package/commands/cursorflow-signal.md +38 -12
- package/dist/cli/clean.d.ts +3 -1
- package/dist/cli/clean.js +145 -8
- package/dist/cli/clean.js.map +1 -1
- package/dist/cli/doctor.js +14 -1
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.js +32 -21
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init.js +5 -4
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/models.d.ts +7 -0
- package/dist/cli/models.js +104 -0
- package/dist/cli/models.js.map +1 -0
- package/dist/cli/monitor.js +56 -1
- package/dist/cli/monitor.js.map +1 -1
- package/dist/cli/prepare.d.ts +7 -0
- package/dist/cli/prepare.js +748 -0
- package/dist/cli/prepare.js.map +1 -0
- package/dist/cli/resume.js +56 -0
- package/dist/cli/resume.js.map +1 -1
- package/dist/cli/run.js +30 -1
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/signal.js +18 -0
- package/dist/cli/signal.js.map +1 -1
- package/dist/core/runner.d.ts +9 -1
- package/dist/core/runner.js +139 -23
- package/dist/core/runner.js.map +1 -1
- package/dist/utils/cursor-agent.d.ts +4 -0
- package/dist/utils/cursor-agent.js +58 -10
- package/dist/utils/cursor-agent.js.map +1 -1
- package/dist/utils/doctor.d.ts +10 -0
- package/dist/utils/doctor.js +581 -1
- package/dist/utils/doctor.js.map +1 -1
- package/dist/utils/types.d.ts +11 -0
- package/examples/README.md +114 -59
- package/examples/demo-project/README.md +61 -79
- package/examples/demo-project/_cursorflow/tasks/demo-test/01-create-utils.json +17 -6
- package/examples/demo-project/_cursorflow/tasks/demo-test/02-add-tests.json +17 -6
- package/examples/demo-project/_cursorflow/tasks/demo-test/README.md +66 -25
- package/package.json +1 -1
- package/scripts/patches/test-cursor-agent.js +203 -0
- package/src/cli/clean.ts +156 -9
- package/src/cli/doctor.ts +18 -2
- package/src/cli/index.ts +33 -21
- package/src/cli/init.ts +6 -4
- package/src/cli/models.ts +83 -0
- package/src/cli/monitor.ts +60 -1
- package/src/cli/prepare.ts +844 -0
- package/src/cli/resume.ts +66 -0
- package/src/cli/run.ts +36 -2
- package/src/cli/signal.ts +22 -0
- package/src/core/runner.ts +164 -23
- package/src/utils/cursor-agent.ts +62 -10
- package/src/utils/doctor.ts +633 -5
- 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
|
-
|
|
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
|
-
|
|
9
|
-
```bash
|
|
10
|
-
ls _cursorflow/tasks/
|
|
11
|
-
```
|
|
7
|
+
## Workflow
|
|
12
8
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
19
|
-
```bash
|
|
20
|
-
cursorflow lane _cursorflow/tasks/MyFeature/01-task.json
|
|
21
|
-
```
|
|
22
|
+
### Quick Start
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
42
|
+
## How It Works
|
|
29
43
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
|
40
|
-
| `--
|
|
41
|
-
| `--
|
|
42
|
-
| `--
|
|
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
|
-
##
|
|
63
|
+
## Execution Flow
|
|
64
|
+
|
|
65
|
+
### Single Lane
|
|
45
66
|
|
|
46
|
-
### Standard run
|
|
47
67
|
```bash
|
|
48
|
-
cursorflow
|
|
68
|
+
cursorflow prepare SimpleFix --prompt "Fix the bug"
|
|
69
|
+
cursorflow run _cursorflow/tasks/2412211530_SimpleFix
|
|
49
70
|
```
|
|
50
71
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
72
|
+
```
|
|
73
|
+
┌─────────────────────────────────────────────────────────┐
|
|
74
|
+
│ 01-lane-1 │
|
|
75
|
+
│ ┌─────────┐ │
|
|
76
|
+
│ │implement│ → AI executes → Review → Complete │
|
|
77
|
+
│ └─────────┘ │
|
|
78
|
+
└─────────────────────────────────────────────────────────┘
|
|
55
79
|
```
|
|
56
80
|
|
|
57
|
-
###
|
|
81
|
+
### Multiple Tasks in Lane
|
|
82
|
+
|
|
58
83
|
```bash
|
|
59
|
-
cursorflow
|
|
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
|
-
|
|
89
|
+
```
|
|
90
|
+
┌─────────────────────────────────────────────────────────┐
|
|
91
|
+
│ 01-lane-1 │
|
|
92
|
+
│ ┌────┐ ┌─────────┐ │
|
|
93
|
+
│ │plan│ ──▶ │implement│ → Review → Complete │
|
|
94
|
+
│ └────┘ └─────────┘ │
|
|
95
|
+
└─────────────────────────────────────────────────────────┘
|
|
96
|
+
```
|
|
63
97
|
|
|
64
|
-
|
|
65
|
-
- Load configuration
|
|
66
|
-
- Verify the `cursor-agent` CLI
|
|
67
|
-
- Confirm Git repository status
|
|
98
|
+
### Sequential Lanes (with `--sequential`)
|
|
68
99
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
100
|
+
```bash
|
|
101
|
+
cursorflow prepare FullStack --lanes 3 --sequential \
|
|
102
|
+
--prompt "Implement your layer"
|
|
103
|
+
```
|
|
73
104
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
|
|
80
|
-
- Push changes
|
|
81
|
-
- Create a PR (depending on settings)
|
|
82
|
-
- Store logs
|
|
114
|
+
### Parallel Lanes
|
|
83
115
|
|
|
84
|
-
|
|
116
|
+
```bash
|
|
117
|
+
cursorflow prepare FrontBack --lanes 2 \
|
|
118
|
+
--prompt "Implement your layer"
|
|
119
|
+
```
|
|
85
120
|
|
|
86
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
98
|
-
-
|
|
99
|
-
-
|
|
100
|
-
-
|
|
101
|
-
-
|
|
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
|
-
###
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
###
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
#
|
|
1
|
+
# CursorFlow Signal
|
|
2
2
|
|
|
3
|
-
##
|
|
4
|
-
Directly intervene in a running lane to
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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.
|
package/dist/cli/clean.d.ts
CHANGED
package/dist/cli/clean.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* CursorFlow clean command
|
|
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
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
package/dist/cli/clean.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clean.js","sourceRoot":"","sources":["../../src/cli/clean.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"clean.js","sourceRoot":"","sources":["../../src/cli/clean.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/doctor.js
CHANGED
|
@@ -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;
|